USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
PS3USB.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
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
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "PS3USB.h"
19 // To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
22 
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
27 {
28  for (uint8_t i = 0; i < PS3_MAX_ENDPOINTS; i++) {
29  epInfo[i].epAddr = 0;
30  epInfo[i].maxPktSize = (i) ? 0 : 8;
31  epInfo[i].epAttribs = 0;
33  }
34 
35  if (pUsb) // register in USB subsystem
36  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
37 
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;
44 }
45 
46 uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
47  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
48  uint8_t rcode;
49  UsbDevice *p = NULL;
50  EpInfo *oldep_ptr = NULL;
51  uint16_t PID;
52  uint16_t VID;
53 
54  // get memory address of USB device address pool
55  AddressPool &addrPool = pUsb->GetAddressPool();
56 #ifdef EXTRADEBUG
57  Notify(PSTR("\r\nPS3USB Init"), 0x80);
58 #endif
59  // check if address has already been assigned to an instance
60  if (bAddress) {
61 #ifdef DEBUG_USB_HOST
62  Notify(PSTR("\r\nAddress in use"), 0x80);
63 #endif
65  }
66 
67  // Get pointer to pseudo device with address 0 assigned
68  p = addrPool.GetUsbDevicePtr(0);
69 
70  if (!p) {
71 #ifdef DEBUG_USB_HOST
72  Notify(PSTR("\r\nAddress not found"), 0x80);
73 #endif
75  }
76 
77  if (!p->epinfo) {
78 #ifdef DEBUG_USB_HOST
79  Notify(PSTR("\r\nepinfo is null"), 0x80);
80 #endif
82  }
83 
84  // Save old pointer to EP_RECORD of address 0
85  oldep_ptr = p->epinfo;
86 
87  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
88  p->epinfo = epInfo;
89 
90  p->lowspeed = lowspeed;
91 
92  // Get device descriptor
93  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
94  // Restore p->epinfo
95  p->epinfo = oldep_ptr;
96 
97  if (rcode)
98  goto FailGetDevDescr;
99 
100  VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
101  PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
102 
103  if (VID != PS3_VID || (PID != PS3_PID && PID != PS3NAVIGATION_PID && PID != PS3MOVE_PID))
104  goto FailUnknownDevice;
105 
106  // Allocate new address according to device class
107  bAddress = addrPool.AllocAddress(parent, false, port);
108 
109  if (!bAddress)
111 
112  // Extract Max Packet Size from device descriptor
113  epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
114 
115  // Assign new address to the device
116  rcode = pUsb->setAddr(0, 0, bAddress);
117  if (rcode) {
118  p->lowspeed = false;
119  addrPool.FreeAddress(bAddress);
120  bAddress = 0;
121 #ifdef DEBUG_USB_HOST
122  Notify(PSTR("\r\nsetAddr: "), 0x80);
123 #endif
124  PrintHex<uint8_t > (rcode, 0x80);
125  return rcode;
126  }
127 #ifdef EXTRADEBUG
128  Notify(PSTR("\r\nAddr: "), 0x80);
129  PrintHex<uint8_t > (bAddress, 0x80);
130 #endif
131  p->lowspeed = false;
132 
133  //get pointer to assigned address record
134  p = addrPool.GetUsbDevicePtr(bAddress);
135  if (!p)
137 
138  p->lowspeed = lowspeed;
139 
140  // Assign epInfo to epinfo pointer - only EP0 is known
141  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
142  if (rcode)
143  goto FailSetDevTblEntry;
144 
145 
146  /* The application will work in reduced host mode, so we can save program and data
147  memory space. After verifying the PID and VID we will use known values for the
148  configuration values for device, interface, endpoints and HID for the PS3 Controllers */
149 
150  /* Initialize data structures for endpoints of device */
151  epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
153  epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
157  epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint
159  epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
163 
164  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
165  if (rcode)
166  goto FailSetDevTblEntry;
167 
168  delay(200); //Give time for address change
169 
170  rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
171  if (rcode)
172  goto FailSetConfDescr;
173 
174  if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
175  if (PID == PS3_PID) {
176 #ifdef DEBUG_USB_HOST
177  Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
178 #endif
179  PS3Connected = true;
180  } else { // must be a navigation controller
181 #ifdef DEBUG_USB_HOST
182  Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
183 #endif
184  PS3NavigationConnected = true;
185  }
186  /* Set internal bluetooth address and request for data */
187  setBdaddr(my_bdaddr);
188  enable_sixaxis();
189  setLedOn(LED1);
190 
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]);
194 
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);
200 #endif
201  PS3MoveConnected = true;
202  setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
203  moveSetBulb(Red);
204 
205  writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work
206  }
207 
208 #ifdef DEBUG_USB_HOST
209  Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
210  for (int8_t i = 5; i > 0; i--) {
211  PrintHex<uint8_t > (my_bdaddr[i], 0x80);
212  Notify(PSTR(":"), 0x80);
213  }
214  PrintHex<uint8_t > (my_bdaddr[0], 0x80);
215 #endif
216 
217  bPollEnable = true;
218  Notify(PSTR("\r\n"), 0x80);
219  timer = millis();
220  return 0; // successful configuration
221 
222  /* diagnostic messages */
223 FailGetDevDescr:
224 #ifdef DEBUG_USB_HOST
226  goto Fail;
227 #endif
228 FailSetDevTblEntry:
229 #ifdef DEBUG_USB_HOST
231  goto Fail;
232 #endif
233 
234 FailSetConfDescr:
235 #ifdef DEBUG_USB_HOST
237 #endif
238  goto Fail;
239 FailUnknownDevice:
240 #ifdef DEBUG_USB_HOST
241  NotifyFailUnknownDevice(VID, PID);
242 #endif
244 Fail:
245 
246 #ifdef DEBUG_USB_HOST
247  Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
248  NotifyFail(rcode);
249 #endif
250  Release();
251  return rcode;
252 }
253 
254 /* Performs a cleanup after failed Init() attempt */
255 uint8_t PS3USB::Release() {
256  PS3Connected = false;
257  PS3MoveConnected = false;
258  PS3NavigationConnected = false;
260  bAddress = 0;
261  bPollEnable = false;
262  return 0;
263 }
264 
265 uint8_t PS3USB::Poll() {
266  if (!bPollEnable)
267  return 0;
268 
270  uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
271  pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
272  if (millis() - timer > 100) { // Loop 100ms before processing data
273  readReport();
274 #ifdef PRINTREPORT
275  printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
276 #endif
277  }
278  } 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
279  if (millis() - timer > 4000) // Send at least every 4th second
280  {
281  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
282  timer = millis();
283  }
284  }
285  return 0;
286 }
287 
288 void PS3USB::readReport() {
289  if (readBuf == NULL)
290  return;
291 
292  ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16));
293 
294  //Notify(PSTR("\r\nButtonState", 0x80);
295  //PrintHex<uint32_t>(ButtonState, 0x80);
296 
297  if (ButtonState != OldButtonState) {
298  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
299  OldButtonState = ButtonState;
300  }
301 }
302 
303 void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
304 #ifdef PRINTREPORT
305  if (readBuf == NULL)
306  return;
307  for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
308  PrintHex<uint8_t > (readBuf[i], 0x80);
309  Notify(PSTR(" "), 0x80);
310  }
311  Notify(PSTR("\r\n"), 0x80);
312 #endif
313 }
314 
316  return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b]));
317 }
318 
320  uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]);
321  bool click = (ButtonClickState & button);
322  ButtonClickState &= ~button; // clear "click" event
323  return click;
324 }
325 
327  if (readBuf == NULL)
328  return 0;
329  return (uint8_t)(readBuf[(pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])) - 9]);
330 }
331 
333  if (readBuf == NULL)
334  return 0;
335  return (uint8_t)(readBuf[((uint8_t)a + 6)]);
336 }
337 
339  if (readBuf == NULL)
340  return 0;
341  return ((readBuf[((uint16_t)a) - 9] << 8) | readBuf[((uint16_t)a + 1) - 9]);
342 }
343 
345  if (PS3Connected) {
346  double accXval;
347  double accYval;
348  double accZval;
349 
350  // Data for the Kionix KXPC4 used in the DualShock 3
351  const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
352  accXval = -((double)getSensor(aX) - zeroG);
353  accYval = -((double)getSensor(aY) - zeroG);
354  accZval = -((double)getSensor(aZ) - zeroG);
355 
356  // Convert to 360 degrees resolution
357  // atan2 outputs the value of -π to π (radians)
358  // We are then converting it to 0 to 2π and then to degrees
359  if (a == Pitch) {
360  double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG;
361  return angle;
362  } else {
363  double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
364  return angle;
365  }
366  } else
367  return 0;
368 }
369 
371  if (readBuf == NULL)
372  return false;
373  if (readBuf[((uint16_t)c >> 8) - 9] == ((uint8_t)c & 0xff))
374  return true;
375  return false;
376 }
377 
380  char statusOutput[100];
381 
382  strcpy(statusOutput, "ConnectionStatus: ");
383 
384  if (getStatus(Plugged)) strcat(statusOutput, "Plugged");
385  else if (getStatus(Unplugged)) strcat(statusOutput, "Unplugged");
386  else strcat(statusOutput, "Error");
387 
388 
389  strcat(statusOutput, " - PowerRating: ");
390 
391  if (getStatus(Charging)) strcat(statusOutput, "Charging");
392  else if (getStatus(NotCharging)) strcat(statusOutput, "Not Charging");
393  else if (getStatus(Shutdown)) strcat(statusOutput, "Shutdown");
394  else if (getStatus(Dying)) strcat(statusOutput, "Dying");
395  else if (getStatus(Low)) strcat(statusOutput, "Low");
396  else if (getStatus(High)) strcat(statusOutput, "High");
397  else if (getStatus(Full)) strcat(statusOutput, "Full");
398  else strcat(statusOutput, "Error");
399 
400  strcat(statusOutput, " - WirelessStatus: ");
401 
402  if (getStatus(CableRumble)) strcat(statusOutput, "Cable - Rumble is on");
403  else if (getStatus(Cable)) strcat(statusOutput, "Cable - Rumble is off");
404  else if (getStatus(BluetoothRumble)) strcat(statusOutput, "Bluetooth - Rumble is on");
405  else if (getStatus(Bluetooth)) strcat(statusOutput, "Bluetooth - Rumble is off");
406  else strcat(statusOutput, "Error");
407 
408  return statusOutput;
409  } else
410  return "Error";
411 }
412 
413 /* Playstation Sixaxis Dualshock and Navigation Controller commands */
414 void PS3USB::PS3_Command(uint8_t* data, uint16_t nbytes) {
415  //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)
416  pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL);
417 }
418 
420  for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
421  writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer
422 
423  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
424 }
425 
427  writeBuf[1] = 0x00;
428  writeBuf[2] = 0x00; //low mode off
429  writeBuf[3] = 0x00;
430  writeBuf[4] = 0x00; //high mode off
431 
432  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
433 }
434 
436  if ((mode & 0x30) > 0x00) {
437  uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
438  if (mode == RumbleHigh) {
439  power[0] = 0x00;
440  power[1] = 0xff;
441  }
442  setRumbleOn(0xfe, power[0], 0xfe, power[1]);
443  }
444 }
445 
446 void PS3USB::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
447  writeBuf[1] = rightDuration;
448  writeBuf[2] = rightPower;
449  writeBuf[3] = leftDuration;
450  writeBuf[4] = leftPower;
451  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
452 }
453 
454 void PS3USB::setLedRaw(uint8_t value) {
455  writeBuf[9] = value << 1;
456  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
457 }
458 
460  writeBuf[9] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1));
461  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
462 }
463 
465  writeBuf[9] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
466  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
467 }
468 
470  writeBuf[9] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
471  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
472 }
473 
474 void PS3USB::setBdaddr(uint8_t* BDADDR) {
475  /* Set the internal bluetooth address */
476  uint8_t buf[8];
477  buf[0] = 0x01;
478  buf[1] = 0x00;
479  for (uint8_t i = 0; i < 6; i++)
480  buf[i + 2] = BDADDR[5 - i]; //Copy into buffer, has to be written reversed
481 
482  //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)
483  pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
484 }
485 
486 void PS3USB::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB
487  uint8_t cmd_buf[4];
488  cmd_buf[0] = 0x42; // Special PS3 Controller enable commands
489  cmd_buf[1] = 0x0c;
490  cmd_buf[2] = 0x00;
491  cmd_buf[3] = 0x00;
492 
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);
495 }
496 
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);
500 }
501 
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
504  writeBuf[2] = r;
505  writeBuf[3] = g;
506  writeBuf[4] = b;
507 
508  Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
509 }
510 
511 void PS3USB::moveSetBulb(Colors 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));
513 }
514 
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);
519 #endif
520  //set the rumble value into the write buffer
521  writeBuf[6] = rumble;
522 
523  Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
524 }
525 
526 void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
527  /* Set the internal bluetooth address */
528  uint8_t buf[11];
529  buf[0] = 0x05;
530  buf[7] = 0x10;
531  buf[8] = 0x01;
532  buf[9] = 0x02;
533  buf[10] = 0x12;
534 
535  for (uint8_t i = 0; i < 6; i++)
536  buf[i + 1] = BDADDR[i];
537 
538  //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)
539  pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
540 }