1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
13 Kristian Lauszus, TKJ Electronics
14 Web : http://www.tkjelectronics.com
15 e-mail : kristianl@tkjelectronics.com
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
23 PS3USB::PS3USB(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) :
24 pUsb(p), // pointer to USB class instance - mandatory
25 bAddress(0), // device address - mandatory
26 bPollEnable(false) // don't start polling before dongle is connected
28 for(uint8_t i = 0; i < PS3_MAX_ENDPOINTS; i++) {
30 epInfo[i].maxPktSize = (i) ? 0 : 8;
31 epInfo[i].epAttribs = 0;
32 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
35 if(pUsb) // register in USB subsystem
36 pUsb->RegisterDeviceClass(this); //set devConfig[] entry
38 my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
39 my_bdaddr[4] = btadr4;
40 my_bdaddr[3] = btadr3;
41 my_bdaddr[2] = btadr2;
42 my_bdaddr[1] = btadr1;
43 my_bdaddr[0] = btadr0;
46 uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
47 uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
48 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
51 EpInfo *oldep_ptr = NULL;
55 // get memory address of USB device address pool
56 AddressPool &addrPool = pUsb->GetAddressPool();
58 Notify(PSTR("\r\nPS3USB Init"), 0x80);
60 // check if address has already been assigned to an instance
63 Notify(PSTR("\r\nAddress in use"), 0x80);
65 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
68 // Get pointer to pseudo device with address 0 assigned
69 p = addrPool.GetUsbDevicePtr(0);
73 Notify(PSTR("\r\nAddress not found"), 0x80);
75 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
80 Notify(PSTR("\r\nepinfo is null"), 0x80);
82 return USB_ERROR_EPINFO_IS_NULL;
85 // Save old pointer to EP_RECORD of address 0
86 oldep_ptr = p->epinfo;
88 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
91 p->lowspeed = lowspeed;
93 // Get device descriptor
94 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
96 p->epinfo = oldep_ptr;
102 PID = udd->idProduct;
104 if(VID != PS3_VID || (PID != PS3_PID && PID != PS3NAVIGATION_PID && PID != PS3MOVE_PID))
105 goto FailUnknownDevice;
107 // Allocate new address according to device class
108 bAddress = addrPool.AllocAddress(parent, false, port);
111 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
113 // Extract Max Packet Size from device descriptor
114 epInfo[0].maxPktSize = udd->bMaxPacketSize0;
116 // Assign new address to the device
117 rcode = pUsb->setAddr(0, 0, bAddress);
120 addrPool.FreeAddress(bAddress);
122 #ifdef DEBUG_USB_HOST
123 Notify(PSTR("\r\nsetAddr: "), 0x80);
124 D_PrintHex<uint8_t > (rcode, 0x80);
129 Notify(PSTR("\r\nAddr: "), 0x80);
130 D_PrintHex<uint8_t > (bAddress, 0x80);
132 //delay(300); // Spec says you should wait at least 200ms
136 //get pointer to assigned address record
137 p = addrPool.GetUsbDevicePtr(bAddress);
139 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
141 p->lowspeed = lowspeed;
143 // Assign epInfo to epinfo pointer - only EP0 is known
144 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
146 goto FailSetDevTblEntry;
149 /* The application will work in reduced host mode, so we can save program and data
150 memory space. After verifying the PID and VID we will use known values for the
151 configuration values for device, interface, endpoints and HID for the PS3 Controllers */
153 /* Initialize data structures for endpoints of device */
154 epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
155 epInfo[ PS3_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
156 epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
157 epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
158 epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = 0;
159 epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = 0;
160 epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint
161 epInfo[ PS3_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
162 epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
163 epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
164 epInfo[ PS3_INPUT_PIPE ].bmSndToggle = 0;
165 epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = 0;
167 rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
169 goto FailSetDevTblEntry;
171 delay(200); //Give time for address change
173 rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
175 goto FailSetConfDescr;
177 if(PID == PS3_PID || PID == PS3NAVIGATION_PID) {
179 #ifdef DEBUG_USB_HOST
180 Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
183 } else { // must be a navigation controller
184 #ifdef DEBUG_USB_HOST
185 Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
187 PS3NavigationConnected = true;
189 enable_sixaxis(); // The PS3 controller needs a special command before it starts sending data
191 // Needed for PS3 Dualshock and Navigation commands to work
192 for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
193 writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]);
195 for(uint8_t i = 6; i < 10; i++)
196 readBuf[i] = 0x7F; // Set the analog joystick values to center position
197 } else { // must be a Motion controller
198 #ifdef DEBUG_USB_HOST
199 Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
201 PS3MoveConnected = true;
202 writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work
204 if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) {
206 setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
208 setBdaddr(my_bdaddr); // Set internal Bluetooth address
210 #ifdef DEBUG_USB_HOST
211 Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
212 for(int8_t i = 5; i > 0; i--) {
213 D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
214 Notify(PSTR(":"), 0x80);
216 D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
222 Notify(PSTR("\r\n"), 0x80);
224 return 0; // Successful configuration
226 /* Diagnostic messages */
228 #ifdef DEBUG_USB_HOST
229 NotifyFailGetDevDescr();
234 #ifdef DEBUG_USB_HOST
235 NotifyFailSetDevTblEntry();
240 #ifdef DEBUG_USB_HOST
241 NotifyFailSetConfDescr();
246 #ifdef DEBUG_USB_HOST
247 NotifyFailUnknownDevice(VID, PID);
249 rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
252 #ifdef DEBUG_USB_HOST
253 Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
260 /* Performs a cleanup after failed Init() attempt */
261 uint8_t PS3USB::Release() {
262 PS3Connected = false;
263 PS3MoveConnected = false;
264 PS3NavigationConnected = false;
265 pUsb->GetAddressPool().FreeAddress(bAddress);
271 uint8_t PS3USB::Poll() {
275 if(PS3Connected || PS3NavigationConnected) {
276 uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
277 pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
278 if(millis() - timer > 100) { // Loop 100ms before processing data
281 printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
284 } else if(PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB
285 if(millis() - timer > 4000) { // Send at least every 4th second
286 Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on
293 void PS3USB::readReport() {
294 ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16));
296 //Notify(PSTR("\r\nButtonState", 0x80);
297 //PrintHex<uint32_t>(ButtonState, 0x80);
299 if(ButtonState != OldButtonState) {
300 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
301 OldButtonState = ButtonState;
305 void PS3USB::printReport() { // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
307 for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
308 D_PrintHex<uint8_t > (readBuf[i], 0x80);
309 Notify(PSTR(" "), 0x80);
311 Notify(PSTR("\r\n"), 0x80);
315 bool PS3USB::getButtonPress(ButtonEnum b) {
316 return (ButtonState & pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]));
319 bool PS3USB::getButtonClick(ButtonEnum b) {
320 uint32_t button = pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]);
321 bool click = (ButtonClickState & button);
322 ButtonClickState &= ~button; // Clear "click" event
326 uint8_t PS3USB::getAnalogButton(ButtonEnum a) {
327 return (uint8_t)(readBuf[(pgm_read_byte(&PS3_ANALOG_BUTTONS[(uint8_t)a])) - 9]);
330 uint8_t PS3USB::getAnalogHat(AnalogHatEnum a) {
331 return (uint8_t)(readBuf[((uint8_t)a + 6)]);
334 uint16_t PS3USB::getSensor(SensorEnum a) {
335 return ((readBuf[((uint16_t)a) - 9] << 8) | readBuf[((uint16_t)a + 1) - 9]);
338 double PS3USB::getAngle(AngleEnum a) {
344 // Data for the Kionix KXPC4 used in the DualShock 3
345 const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
346 accXval = -((double)getSensor(aX) - zeroG);
347 accYval = -((double)getSensor(aY) - zeroG);
348 accZval = -((double)getSensor(aZ) - zeroG);
350 // Convert to 360 degrees resolution
351 // atan2 outputs the value of -π to π (radians)
352 // We are then converting it to 0 to 2π and then to degrees
354 return (atan2(accYval, accZval) + PI) * RAD_TO_DEG;
356 return (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
361 bool PS3USB::getStatus(StatusEnum c) {
362 return (readBuf[((uint16_t)c >> 8) - 9] == ((uint8_t)c & 0xff));
365 void PS3USB::printStatusString() {
366 char statusOutput[100]; // Max string length plus null character
367 if(PS3Connected || PS3NavigationConnected) {
368 strcpy_P(statusOutput, PSTR("ConnectionStatus: "));
370 if(getStatus(Plugged)) strcat_P(statusOutput, PSTR("Plugged"));
371 else if(getStatus(Unplugged)) strcat_P(statusOutput, PSTR("Unplugged"));
372 else strcat_P(statusOutput, PSTR("Error"));
374 strcat_P(statusOutput, PSTR(" - PowerRating: "));
376 if(getStatus(Charging)) strcat_P(statusOutput, PSTR("Charging"));
377 else if(getStatus(NotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
378 else if(getStatus(Shutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
379 else if(getStatus(Dying)) strcat_P(statusOutput, PSTR("Dying"));
380 else if(getStatus(Low)) strcat_P(statusOutput, PSTR("Low"));
381 else if(getStatus(High)) strcat_P(statusOutput, PSTR("High"));
382 else if(getStatus(Full)) strcat_P(statusOutput, PSTR("Full"));
383 else strcat_P(statusOutput, PSTR("Error"));
385 strcat_P(statusOutput, PSTR(" - WirelessStatus: "));
387 if(getStatus(CableRumble)) strcat_P(statusOutput, PSTR("Cable - Rumble is on"));
388 else if(getStatus(Cable)) strcat_P(statusOutput, PSTR("Cable - Rumble is off"));
389 else if(getStatus(BluetoothRumble)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is on"));
390 else if(getStatus(Bluetooth)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is off"));
391 else strcat_P(statusOutput, PSTR("Error"));
393 strcpy_P(statusOutput, PSTR("Error"));
395 USB_HOST_SERIAL.write(statusOutput);
398 /* Playstation Sixaxis Dualshock and Navigation Controller commands */
399 void PS3USB::PS3_Command(uint8_t *data, uint16_t nbytes) {
400 // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x01), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
401 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL);
404 void PS3USB::setAllOff() {
405 for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
406 writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer
408 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
411 void PS3USB::setRumbleOff() {
413 writeBuf[2] = 0x00; // Low mode off
415 writeBuf[4] = 0x00; // High mode off
417 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
420 void PS3USB::setRumbleOn(RumbleEnum mode) {
421 if((mode & 0x30) > 0x00) {
422 uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
423 if(mode == RumbleHigh) {
427 setRumbleOn(0xfe, power[0], 0xfe, power[1]);
431 void PS3USB::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
432 writeBuf[1] = rightDuration;
433 writeBuf[2] = rightPower;
434 writeBuf[3] = leftDuration;
435 writeBuf[4] = leftPower;
436 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
439 void PS3USB::setLedRaw(uint8_t value) {
440 writeBuf[9] = value << 1;
441 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
444 void PS3USB::setLedOff(LEDEnum a) {
445 writeBuf[9] &= ~((uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1));
446 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
449 void PS3USB::setLedOn(LEDEnum a) {
453 writeBuf[9] |= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
454 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
458 void PS3USB::setLedToggle(LEDEnum a) {
459 writeBuf[9] ^= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
460 PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
463 void PS3USB::setBdaddr(uint8_t *bdaddr) {
464 /* Set the internal Bluetooth address */
469 for(uint8_t i = 0; i < 6; i++)
470 buf[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first
472 // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
473 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
476 void PS3USB::getBdaddr(uint8_t *bdaddr) {
479 // bmRequest = Device to host (0x80) | Class (0x20) | Interface (0x01) = 0xA1, bRequest = Get Report (0x01), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
480 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_IN, HID_REQUEST_GET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
482 for(uint8_t i = 0; i < 6; i++)
483 bdaddr[5 - i] = buf[i + 2]; // Copy into buffer reversed, so it is LSB first
486 void PS3USB::enable_sixaxis() { // Command used to enable the Dualshock 3 and Navigation controller to send data via USB
488 cmd_buf[0] = 0x42; // Special PS3 Controller enable commands
493 // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF4), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
494 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL);
497 /* Playstation Move Controller commands */
498 void PS3USB::Move_Command(uint8_t *data, uint16_t nbytes) {
499 pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data);
502 void PS3USB::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { // Use this to set the Color using RGB values
503 // Set the Bulb's values into the write buffer
508 Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
511 void PS3USB::moveSetBulb(ColorsEnum color) { // Use this to set the Color using the predefined colors in "enums.h"
512 moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
515 void PS3USB::moveSetRumble(uint8_t rumble) {
516 #ifdef DEBUG_USB_HOST
517 if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
518 Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
520 writeBuf[6] = rumble; // Set the rumble value into the write buffer
522 Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
525 void PS3USB::setMoveBdaddr(uint8_t *bdaddr) {
526 /* Set the internal Bluetooth address */
534 for(uint8_t i = 0; i < 6; i++)
535 buf[i + 1] = bdaddr[i];
537 // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
538 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
541 void PS3USB::getMoveBdaddr(uint8_t *bdaddr) {
544 // bmRequest = Device to host (0x80) | Class (0x20) | Interface (0x01) = 0xA1, bRequest = Get Report (0x01), Report ID (0x04), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
545 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_IN, HID_REQUEST_GET_REPORT, 0x04, 0x03, 0x00, 16, 16, buf, NULL);
547 for(uint8_t i = 0; i < 6; i++)
548 bdaddr[i] = buf[10 + i];
551 void PS3USB::getMoveCalibration(uint8_t *data) {
554 for(uint8_t i = 0; i < 3; i++) {
555 // bmRequest = Device to host (0x80) | Class (0x20) | Interface (0x01) = 0xA1, bRequest = Get Report (0x01), Report ID (0x10), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
556 pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_IN, HID_REQUEST_GET_REPORT, 0x10, 0x03, 0x00, 49, 49, buf, NULL);
558 for(byte j = 0; j < 49; j++)
559 data[49 * i + j] = buf[j];
563 void PS3USB::onInit() {
565 pFuncOnInit(); // Call the user function
569 else // Dualshock 3 or Navigation controller