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 #define DEBUG // Uncomment to print data for debugging
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
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
72  Notify(PSTR("\r\nAddress not found"), 0x80);
73 #endif
75  }
76 
77  if (!p->epinfo) {
78 #ifdef DEBUG
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
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
177  Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
178 #endif
179  PS3Connected = true;
180  } else { // must be a navigation controller
181 #ifdef DEBUG
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
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
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:
225  goto Fail;
226 
227 FailSetDevTblEntry:
229  goto Fail;
230 
231 FailSetConfDescr:
233  goto Fail;
234 FailUnknownDevice:
235  NotifyFailUnknownDevice(VID,PID);
237  Fail:
238 
239 #ifdef DEBUG
240  Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
241 #endif
242  NotifyFail(rcode);
243  Release();
244  return rcode;
245 }
246 
247 /* Performs a cleanup after failed Init() attempt */
248 uint8_t PS3USB::Release() {
249  PS3Connected = false;
250  PS3MoveConnected = false;
251  PS3NavigationConnected = false;
253  bAddress = 0;
254  bPollEnable = false;
255  return 0;
256 }
257 
258 uint8_t PS3USB::Poll() {
259  if (!bPollEnable)
260  return 0;
261 
263  uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
264  pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
265  if (millis() - timer > 100) { // Loop 100ms before processing data
266  readReport();
267 #ifdef PRINTREPORT
268  printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
269 #endif
270  }
271  } 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
272  if (millis() - timer > 4000) // Send at least every 4th second
273  {
274  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
275  timer = millis();
276  }
277  }
278  return 0;
279 }
280 
281 void PS3USB::readReport() {
282  if (readBuf == NULL)
283  return;
284 
285  ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16));
286 
287  //Notify(PSTR("\r\nButtonState", 0x80);
288  //PrintHex<uint32_t>(ButtonState, 0x80);
289 
290  if (ButtonState != OldButtonState) {
291  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
292  OldButtonState = ButtonState;
293  }
294 }
295 
296 void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
297 #ifdef PRINTREPORT
298  if (readBuf == NULL)
299  return;
300  for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
301  PrintHex<uint8_t > (readBuf[i], 0x80);
302  Notify(PSTR(" "), 0x80);
303  }
304  Notify(PSTR("\r\n"), 0x80);
305 #endif
306 }
307 
309  return (ButtonState & pgm_read_dword(&BUTTONS[(uint8_t)b]));
310 }
311 
313  uint32_t button = pgm_read_dword(&BUTTONS[(uint8_t)b]);
314  bool click = (ButtonClickState & button);
315  ButtonClickState &= ~button; // clear "click" event
316  return click;
317 }
318 
320  if (readBuf == NULL)
321  return 0;
322  return (uint8_t)(readBuf[(pgm_read_byte(&ANALOGBUTTONS[(uint8_t)a])) - 9]);
323 }
324 
326  if (readBuf == NULL)
327  return 0;
328  return (uint8_t)(readBuf[((uint8_t)a + 6)]);
329 }
330 
332  if (readBuf == NULL)
333  return 0;
334  return ((readBuf[((uint16_t)a) - 9] << 8) | readBuf[((uint16_t)a + 1) - 9]);
335 }
336 
338  if (PS3Connected) {
339  double accXval;
340  double accYval;
341  double accZval;
342 
343  // Data for the Kionix KXPC4 used in the DualShock 3
344  const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
345  accXval = -((double)getSensor(aX) - zeroG);
346  accYval = -((double)getSensor(aY) - zeroG);
347  accZval = -((double)getSensor(aZ) - zeroG);
348 
349  // Convert to 360 degrees resolution
350  // atan2 outputs the value of -π to π (radians)
351  // We are then converting it to 0 to 2π and then to degrees
352  if (a == Pitch) {
353  double angle = (atan2(accYval, accZval) + PI) * RAD_TO_DEG;
354  return angle;
355  } else {
356  double angle = (atan2(accXval, accZval) + PI) * RAD_TO_DEG;
357  return angle;
358  }
359  } else
360  return 0;
361 }
362 
364  if (readBuf == NULL)
365  return false;
366  if (readBuf[((uint16_t)c >> 8) - 9] == ((uint8_t)c & 0xff))
367  return true;
368  return false;
369 }
370 
373  char statusOutput[100];
374 
375  strcpy(statusOutput, "ConnectionStatus: ");
376 
377  if (getStatus(Plugged)) strcat(statusOutput, "Plugged");
378  else if (getStatus(Unplugged)) strcat(statusOutput, "Unplugged");
379  else strcat(statusOutput, "Error");
380 
381 
382  strcat(statusOutput, " - PowerRating: ");
383 
384  if (getStatus(Charging)) strcat(statusOutput, "Charging");
385  else if (getStatus(NotCharging)) strcat(statusOutput, "Not Charging");
386  else if (getStatus(Shutdown)) strcat(statusOutput, "Shutdown");
387  else if (getStatus(Dying)) strcat(statusOutput, "Dying");
388  else if (getStatus(Low)) strcat(statusOutput, "Low");
389  else if (getStatus(High)) strcat(statusOutput, "High");
390  else if (getStatus(Full)) strcat(statusOutput, "Full");
391  else strcat(statusOutput, "Error");
392 
393  strcat(statusOutput, " - WirelessStatus: ");
394 
395  if (getStatus(CableRumble)) strcat(statusOutput, "Cable - Rumble is on");
396  else if (getStatus(Cable)) strcat(statusOutput, "Cable - Rumble is off");
397  else if (getStatus(BluetoothRumble)) strcat(statusOutput, "Bluetooth - Rumble is on");
398  else if (getStatus(Bluetooth)) strcat(statusOutput, "Bluetooth - Rumble is off");
399  else strcat(statusOutput, "Error");
400 
401  return statusOutput;
402  } else
403  return "Error";
404 }
405 
406 /* Playstation Sixaxis Dualshock and Navigation Controller commands */
407 void PS3USB::PS3_Command(uint8_t* data, uint16_t nbytes) {
408  //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)
409  pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL);
410 }
411 
413  for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
414  writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer
415 
416  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
417 }
418 
420  writeBuf[1] = 0x00;
421  writeBuf[2] = 0x00; //low mode off
422  writeBuf[3] = 0x00;
423  writeBuf[4] = 0x00; //high mode off
424 
425  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
426 }
427 
429  if ((mode & 0x30) > 0x00) {
430  uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow
431  if (mode == RumbleHigh) {
432  power[0] = 0x00;
433  power[1] = 0xff;
434  }
435  setRumbleOn(0xfe, power[0], 0xfe, power[1]);
436  }
437 }
438 
439 void PS3USB::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
440  writeBuf[1] = rightDuration;
441  writeBuf[2] = rightPower;
442  writeBuf[3] = leftDuration;
443  writeBuf[4] = leftPower;
444  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
445 }
446 
447 void PS3USB::setLedRaw(uint8_t value) {
448  writeBuf[9] = value;
449  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
450 }
452  writeBuf[9] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1));
453  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
454 }
456  writeBuf[9] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
457  PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
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 
464 void PS3USB::setBdaddr(uint8_t* BDADDR) {
465  /* Set the internal bluetooth address */
466  uint8_t buf[8];
467  buf[0] = 0x01;
468  buf[1] = 0x00;
469  for (uint8_t i = 0; i < 6; i++)
470  buf[i + 2] = BDADDR[5 - i]; //Copy into buffer, has to be written reversed
471 
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);
474 }
475 
476 void PS3USB::enable_sixaxis() { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB
477  uint8_t cmd_buf[4];
478  cmd_buf[0] = 0x42; // Special PS3 Controller enable commands
479  cmd_buf[1] = 0x0c;
480  cmd_buf[2] = 0x00;
481  cmd_buf[3] = 0x00;
482 
483  //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)
484  pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL);
485 }
486 
487 /* Playstation Move Controller commands */
488 void PS3USB::Move_Command(uint8_t* data, uint16_t nbytes) {
489  pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data);
490 }
491 
492 void PS3USB::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { //Use this to set the Color using RGB values
493  // set the Bulb's values into the write buffer
494  writeBuf[2] = r;
495  writeBuf[3] = g;
496  writeBuf[4] = b;
497 
498  Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
499 }
500 
501 void PS3USB::moveSetBulb(Colors color) { //Use this to set the Color using the predefined colors in "enums.h"
502  moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
503 }
504 
505 void PS3USB::moveSetRumble(uint8_t rumble) {
506 #ifdef DEBUG
507  if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
508  Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
509 #endif
510  //set the rumble value into the write buffer
511  writeBuf[6] = rumble;
512 
513  Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
514 }
515 
516 void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
517  /* Set the internal bluetooth address */
518  uint8_t buf[11];
519  buf[0] = 0x05;
520  buf[7] = 0x10;
521  buf[8] = 0x01;
522  buf[9] = 0x02;
523  buf[10] = 0x12;
524 
525  for (uint8_t i = 0; i < 6; i++)
526  buf[i + 1] = BDADDR[i];
527 
528  //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)
529  pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
530 }