USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
PS3BT.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 "PS3BT.h"
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
22 
23 PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) :
24 BluetoothService(p) // Pointer to USB class instance - mandatory
25 {
26  pBtd->my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
27  pBtd->my_bdaddr[4] = btadr4;
28  pBtd->my_bdaddr[3] = btadr3;
29  pBtd->my_bdaddr[2] = btadr2;
30  pBtd->my_bdaddr[1] = btadr1;
31  pBtd->my_bdaddr[0] = btadr0;
32 
33  HIDBuffer[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02)
34  HIDBuffer[1] = 0x01; // Report ID
35 
36  // Needed for PS3 Move Controller commands to work via bluetooth
37  HIDMoveBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
38  HIDMoveBuffer[1] = 0x02; // Report ID
39 
40  /* Set device cid for the control and intterrupt channelse - LSB */
41  control_dcid[0] = 0x40; // 0x0040
42  control_dcid[1] = 0x00;
43  interrupt_dcid[0] = 0x41; // 0x0041
44  interrupt_dcid[1] = 0x00;
45 
46  Reset();
47 }
48 
50  return (ButtonState & pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]));
51 }
52 
54  uint32_t button = pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]);
55  bool click = (ButtonClickState & button);
56  ButtonClickState &= ~button; // Clear "click" event
57  return click;
58 }
59 
61  return (uint8_t)(l2capinbuf[pgm_read_byte(&PS3_ANALOG_BUTTONS[(uint8_t)a])]);
62 }
63 
65  return (uint8_t)(l2capinbuf[(uint8_t)a + 15]);
66 }
67 
69  if(PS3Connected) {
70  if(a == aX || a == aY || a == aZ || a == gZ)
71  return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]);
72  else
73  return 0;
74  } else if(PS3MoveConnected) {
75  if(a == mXmove || a == mYmove) // These are all 12-bits long
76  return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1]));
77  else if(a == mZmove || a == tempMove) // The tempearature is also 12 bits long
78  return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4));
79  else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove
80  return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8));
81  } else
82  return 0;
83 }
84 
86  float accXval, accYval, accZval;
87 
88  if(PS3Connected) {
89  // Data for the Kionix KXPC4 used in the DualShock 3
90  const float zeroG = 511.5f; // 1.65/3.3*1023 (1.65V)
91  accXval = -((float)getSensor(aX) - zeroG);
92  accYval = -((float)getSensor(aY) - zeroG);
93  accZval = -((float)getSensor(aZ) - zeroG);
94  } else if(PS3MoveConnected) {
95  // It's a Kionix KXSC4 inside the Motion controller
96  const uint16_t zeroG = 0x8000;
97  accXval = -(int16_t)(getSensor(aXmove) - zeroG);
98  accYval = (int16_t)(getSensor(aYmove) - zeroG);
99  accZval = (int16_t)(getSensor(aZmove) - zeroG);
100  } else
101  return 0;
102 
103  // Convert to 360 degrees resolution
104  // atan2 outputs the value of -π to π (radians)
105  // We are then converting it to 0 to 2π and then to degrees
106  if(a == Pitch)
107  return (atan2f(accYval, accZval) + PI) * RAD_TO_DEG;
108  else
109  return (atan2f(accXval, accZval) + PI) * RAD_TO_DEG;
110 }
111 
112 float PS3BT::get9DOFValues(SensorEnum a) { // Thanks to Manfred Piendl
113  if(!PS3MoveConnected)
114  return 0;
115  int16_t value = getSensor(a);
116  if(a == mXmove || a == mYmove || a == mZmove) {
117  if(value > 2047)
118  value -= 0x1000;
119  return (float)value / 3.2f; // unit: muT = 10^(-6) Tesla
120  } else if(a == aXmove || a == aYmove || a == aZmove) {
121  if(value < 0)
122  value += 0x8000;
123  else
124  value -= 0x8000;
125  return (float)value / 442.0f; // unit: m/(s^2)
126  } else if(a == gXmove || a == gYmove || a == gZmove) {
127  if(value < 0)
128  value += 0x8000;
129  else
130  value -= 0x8000;
131  if(a == gXmove)
132  return (float)value / 11.6f; // unit: deg/s
133  else if(a == gYmove)
134  return (float)value / 11.2f; // unit: deg/s
135  else // gZmove
136  return (float)value / 9.6f; // unit: deg/s
137  } else
138  return 0;
139 }
140 
142  if(PS3MoveConnected) {
143  int16_t input = getSensor(tempMove);
144 
145  String output = String(input / 100);
146  output += ".";
147  if(input % 100 < 10)
148  output += "0";
149  output += String(input % 100);
150 
151  return output;
152  } else
153  return "Error";
154 }
155 
157  return (l2capinbuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff));
158 }
159 
161  char statusOutput[102]; // Max string length plus null character
163  strcpy_P(statusOutput, PSTR("\r\nConnectionStatus: "));
164 
165  if(getStatus(Plugged)) strcat_P(statusOutput, PSTR("Plugged"));
166  else if(getStatus(Unplugged)) strcat_P(statusOutput, PSTR("Unplugged"));
167  else strcat_P(statusOutput, PSTR("Error"));
168 
169  strcat_P(statusOutput, PSTR(" - PowerRating: "));
170 
171  if(getStatus(Charging)) strcat_P(statusOutput, PSTR("Charging"));
172  else if(getStatus(NotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
173  else if(getStatus(Shutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
174  else if(getStatus(Dying)) strcat_P(statusOutput, PSTR("Dying"));
175  else if(getStatus(Low)) strcat_P(statusOutput, PSTR("Low"));
176  else if(getStatus(High)) strcat_P(statusOutput, PSTR("High"));
177  else if(getStatus(Full)) strcat_P(statusOutput, PSTR("Full"));
178  else strcat_P(statusOutput, PSTR("Error"));
179 
180  strcat_P(statusOutput, PSTR(" - WirelessStatus: "));
181 
182  if(getStatus(CableRumble)) strcat_P(statusOutput, PSTR("Cable - Rumble is on"));
183  else if(getStatus(Cable)) strcat_P(statusOutput, PSTR("Cable - Rumble is off"));
184  else if(getStatus(BluetoothRumble)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is on"));
185  else if(getStatus(Bluetooth)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is off"));
186  else strcat_P(statusOutput, PSTR("Error"));
187  } else if(PS3MoveConnected) {
188  strcpy_P(statusOutput, PSTR("\r\nPowerRating: "));
189 
190  if(getStatus(MoveCharging)) strcat_P(statusOutput, PSTR("Charging"));
191  else if(getStatus(MoveNotCharging)) strcat_P(statusOutput, PSTR("Not Charging"));
192  else if(getStatus(MoveShutdown)) strcat_P(statusOutput, PSTR("Shutdown"));
193  else if(getStatus(MoveDying)) strcat_P(statusOutput, PSTR("Dying"));
194  else if(getStatus(MoveLow)) strcat_P(statusOutput, PSTR("Low"));
195  else if(getStatus(MoveHigh)) strcat_P(statusOutput, PSTR("High"));
196  else if(getStatus(MoveFull)) strcat_P(statusOutput, PSTR("Full"));
197  else strcat_P(statusOutput, PSTR("Error"));
198  } else
199  strcpy_P(statusOutput, PSTR("\r\nError"));
200 
201  USB_HOST_SERIAL.write(statusOutput);
202 }
203 
204 void PS3BT::Reset() {
205  PS3Connected = false;
206  PS3MoveConnected = false;
207  PS3NavigationConnected = false;
208  activeConnection = false;
209  l2cap_event_flag = 0; // Reset flags
210  l2cap_state = L2CAP_WAIT;
211 
212  // Needed for PS3 Dualshock Controller commands to work via Bluetooth
213  for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
214  HIDBuffer[i + 2] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID
215 }
216 
217 void PS3BT::disconnect() { // Use this void to disconnect any of the controllers
218  // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
219  pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
220  Reset();
221  l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
222 }
223 
224 void PS3BT::ACLData(uint8_t* ACLData) {
226  if(ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) {
227  if((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) {
228  pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
229  activeConnection = true;
230  hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
231  l2cap_state = L2CAP_WAIT;
232  remote_name_first = pBtd->remote_name[0]; // Store the first letter in remote name for the connection
233 #ifdef DEBUG_USB_HOST
234  if(pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
235  Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80);
236  Notify(pBtd->hci_version, 0x80);
237  Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"), 0x80);
238  }
239 #endif
240  }
241  }
242  }
243 
244  if(checkHciHandle(ACLData, hci_handle)) { // acl_handle_ok
245  memcpy(l2capinbuf, ACLData, BULK_MAXPKTSIZE);
246  if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
247  if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
248 #ifdef DEBUG_USB_HOST
249  Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
250  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
251  Notify(PSTR(" "), 0x80);
252  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
253  Notify(PSTR(" Data: "), 0x80);
254  D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
255  Notify(PSTR(" "), 0x80);
256  D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
257  Notify(PSTR(" "), 0x80);
258  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
259  Notify(PSTR(" "), 0x80);
260  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
261 #endif
262  } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
263 #ifdef EXTRADEBUG
264  Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
265  D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
266  Notify(PSTR(" "), 0x80);
267  D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
268  Notify(PSTR(" SCID: "), 0x80);
269  D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
270  Notify(PSTR(" "), 0x80);
271  D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
272  Notify(PSTR(" Identifier: "), 0x80);
273  D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
274 #endif
275  if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
276  identifier = l2capinbuf[9];
277  control_scid[0] = l2capinbuf[14];
278  control_scid[1] = l2capinbuf[15];
280  } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
281  identifier = l2capinbuf[9];
282  interrupt_scid[0] = l2capinbuf[14];
283  interrupt_scid[1] = l2capinbuf[15];
285  }
286  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
287  if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
288  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
289  //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
291  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
292  //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
294  }
295  }
296  } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
297  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
298  //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
299  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
300  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
301  //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
302  pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
303  }
304  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
305  if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
306 #ifdef DEBUG_USB_HOST
307  Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
308 #endif
309  identifier = l2capinbuf[9];
310  pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
311  Reset();
312  } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
313 #ifdef DEBUG_USB_HOST
314  Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
315 #endif
316  identifier = l2capinbuf[9];
317  pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
318  Reset();
319  }
320  } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
321  if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
322  //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
323  identifier = l2capinbuf[9];
325  } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
326  //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
327  identifier = l2capinbuf[9];
329  }
330  }
331 #ifdef EXTRADEBUG
332  else {
333  Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
334  D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
335  }
336 #endif
337  } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
338  //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
340  /* Read Report */
341  if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
342  lastMessageTime = (uint32_t)millis(); // Store the last message time
343 
345  ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
346  else if(PS3MoveConnected)
347  ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16));
348 
349  //Notify(PSTR("\r\nButtonState", 0x80);
350  //PrintHex<uint32_t>(ButtonState, 0x80);
351 
352  if(ButtonState != OldButtonState) {
353  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
354  OldButtonState = ButtonState;
355  }
356 
357 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
358  for(uint8_t i = 10; i < 58; i++) {
359  D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
360  Notify(PSTR(" "), 0x80);
361  }
362  Notify(PSTR("\r\n"), 0x80);
363 #endif
364  }
365  }
366  }
367  L2CAP_task();
368  }
369 }
370 
371 void PS3BT::L2CAP_task() {
372  switch(l2cap_state) {
373  case L2CAP_WAIT:
375 #ifdef DEBUG_USB_HOST
376  Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
377 #endif
378  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
379  delay(1);
380  pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
381  identifier++;
382  delay(1);
384  l2cap_state = L2CAP_CONTROL_SUCCESS;
385  }
386  break;
387 
390 #ifdef DEBUG_USB_HOST
391  Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
392 #endif
393  l2cap_state = L2CAP_INTERRUPT_SETUP;
394  }
395  break;
396 
399 #ifdef DEBUG_USB_HOST
400  Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
401 #endif
402  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
403  delay(1);
404  pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
405  identifier++;
406  delay(1);
407  pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
408 
409  l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
410  }
411  break;
412 
414  if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
415 #ifdef DEBUG_USB_HOST
416  Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80);
417 #endif
418  if(remote_name_first == 'M') { // First letter in Motion Controller ('M')
419  memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed
420  l2cap_state = TURN_ON_LED;
421  } else
422  l2cap_state = PS3_ENABLE_SIXAXIS;
423  timer = (uint32_t)millis();
424  }
425  break;
426 
427  /* These states are handled in Run() */
428 
431 #ifdef DEBUG_USB_HOST
432  Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
433 #endif
434  identifier++;
435  pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
436  l2cap_state = L2CAP_CONTROL_DISCONNECT;
437  }
438  break;
439 
442 #ifdef DEBUG_USB_HOST
443  Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
444 #endif
446  hci_handle = -1; // Reset handle
447  l2cap_event_flag = 0; // Reset flags
448  l2cap_state = L2CAP_WAIT;
449  }
450  break;
451  }
452 }
453 
454 void PS3BT::Run() {
455  switch(l2cap_state) {
456  case PS3_ENABLE_SIXAXIS:
457  if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command
458  memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed
459  for(uint8_t i = 15; i < 19; i++)
460  l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position
461  enable_sixaxis();
462  l2cap_state = TURN_ON_LED;
463  timer = (uint32_t)millis();
464  }
465  break;
466 
467  case TURN_ON_LED:
468  if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command
469  if(remote_name_first == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P')
470 #ifdef DEBUG_USB_HOST
471  Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80);
472 #endif
473  PS3Connected = true;
474  } else if(remote_name_first == 'N') { // First letter in Navigation Controller ('N')
475 #ifdef DEBUG_USB_HOST
476  Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80);
477 #endif
478  PS3NavigationConnected = true;
479  } else if(remote_name_first == 'M') { // First letter in Motion Controller ('M')
480  timer = (uint32_t)millis();
481 #ifdef DEBUG_USB_HOST
482  Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
483 #endif
484  PS3MoveConnected = true;
485  }
486  ButtonState = 0; // Clear all values
487  OldButtonState = 0;
488  ButtonClickState = 0;
489 
490  onInit(); // Turn on the LED on the controller
491  l2cap_state = L2CAP_DONE;
492  }
493  break;
494 
495  case L2CAP_DONE:
496  if(PS3MoveConnected) { // The Bulb and rumble values, has to be send at approximately every 5th second for it to stay on
497  if((int32_t)((uint32_t)millis() - timer) > 4000) { // Send at least every 4th second
498  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on
499  timer = (uint32_t)millis();
500  }
501  }
502  break;
503  }
504 }
505 
506 /************************************************************/
507 /* HID Commands */
508 /************************************************************/
509 
510 // Playstation Sixaxis Dualshock and Navigation Controller commands
511 
512 void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) {
513  if((int32_t)((uint32_t)millis() - timerHID) <= 150) // Check if is has been more than 150ms since last command
514  delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands
515  pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
516  timerHID = (uint32_t)millis();
517 }
518 
520  HIDBuffer[3] = 0x00; // Rumble bytes
521  HIDBuffer[4] = 0x00;
522  HIDBuffer[5] = 0x00;
523  HIDBuffer[6] = 0x00;
524 
525  HIDBuffer[11] = 0x00; // LED byte
526 
527  HID_Command(HIDBuffer, HID_BUFFERSIZE);
528 }
529 
531  uint8_t rumbleBuf[HID_BUFFERSIZE];
532  memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE);
533  rumbleBuf[3] = 0x00;
534  rumbleBuf[4] = 0x00;
535  rumbleBuf[5] = 0x00;
536  rumbleBuf[6] = 0x00;
537  HID_Command(rumbleBuf, HID_BUFFERSIZE);
538 }
539 
541  uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
542  if(mode == RumbleHigh) {
543  power[0] = 0x00;
544  power[1] = 0xff;
545  }
546  setRumbleOn(0xfe, power[0], 0xfe, power[1]);
547 }
548 
549 void PS3BT::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) {
550  uint8_t rumbleBuf[HID_BUFFERSIZE];
551  memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE);
552  rumbleBuf[3] = rightDuration;
553  rumbleBuf[4] = rightPower;
554  rumbleBuf[5] = leftDuration;
555  rumbleBuf[6] = leftPower;
556  HID_Command(rumbleBuf, HID_BUFFERSIZE);
557 }
558 
559 void PS3BT::setLedRaw(uint8_t value) {
560  HIDBuffer[11] = value << 1;
561  HID_Command(HIDBuffer, HID_BUFFERSIZE);
562 }
563 
565  HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1));
566  HID_Command(HIDBuffer, HID_BUFFERSIZE);
567 }
568 
570  if(a == OFF)
571  setLedRaw(0);
572  else {
573  HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
574  HID_Command(HIDBuffer, HID_BUFFERSIZE);
575  }
576 }
577 
579  HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1);
580  HID_Command(HIDBuffer, HID_BUFFERSIZE);
581 }
582 
583 void PS3BT::enable_sixaxis() { // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth
584  uint8_t cmd_buf[6];
585  cmd_buf[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03)
586  cmd_buf[1] = 0xF4; // Report ID
587  cmd_buf[2] = 0x42; // Special PS3 Controller enable commands
588  cmd_buf[3] = 0x03;
589  cmd_buf[4] = 0x00;
590  cmd_buf[5] = 0x00;
591 
592  HID_Command(cmd_buf, 6);
593 }
594 
595 // Playstation Move Controller commands
596 
597 void PS3BT::HIDMove_Command(uint8_t* data, uint8_t nbytes) {
598  if((int32_t)((uint32_t)millis() - timerHID) <= 150)// Check if is has been less than 150ms since last command
599  delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands
600  pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel
601  timerHID = (uint32_t)millis();
602 }
603 
604 void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { // Use this to set the Color using RGB values
605  // Set the Bulb's values into the write buffer
606  HIDMoveBuffer[3] = r;
607  HIDMoveBuffer[4] = g;
608  HIDMoveBuffer[5] = b;
609 
610  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
611 }
612 
613 void PS3BT::moveSetBulb(ColorsEnum color) { // Use this to set the Color using the predefined colors in enum
614  moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
615 }
616 
617 void PS3BT::moveSetRumble(uint8_t rumble) {
618 #ifdef DEBUG_USB_HOST
619  if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
620  Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
621 #endif
622  // Set the rumble value into the write buffer
623  HIDMoveBuffer[7] = rumble;
624 
625  HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
626 }
627 
629  if(pFuncOnInit)
630  pFuncOnInit(); // Call the user function
631  else {
632  if(PS3MoveConnected)
633  moveSetBulb(Red);
634  else // Dualshock 3 or Navigation controller
635  setLedOn(static_cast<LEDEnum>(LED1));
636  }
637 }
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
Definition: BTD.h:140
void(* pFuncOnInit)(void)
Definition: BTD.h:609
bool incomingWii
Definition: BTD.h:474
Definition: PS3Enums.h:124
#define pgm_read_dword(addr)
bool PS3NavigationConnected
Definition: PS3BT.h:184
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
Definition: BTD.h:144
#define L2CAP_INTERRUPT_CONFIG_REQUEST
Definition: BTD.h:116
#define L2CAP_INTERRUPT_SETUP
Definition: BTD.h:114
bool getStatus(StatusEnum c)
Definition: PS3BT.cpp:156
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid, uint8_t result)
Definition: BTD.cpp:1260
void Run()
Definition: PS3BT.cpp:454
#define SUCCESSFUL
Definition: BTD.h:178
#define strcpy_P(dest, src)
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
Definition: BTD.h:143
Definition: BTD.h:201
void setLedOn(LEDEnum a)
Definition: PS3BT.cpp:569
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1313
uint8_t hci_version
Definition: BTD.h:464
bool pairWithWii
Definition: BTD.h:476
uint8_t identifier
Definition: BTD.h:621
String getTemperature()
Definition: PS3BT.cpp:141
AnalogHatEnum
void moveSetRumble(uint8_t rumble)
Definition: PS3BT.cpp:617
#define TURN_ON_LED
Definition: BTD.h:130
void printStatusString()
Definition: PS3BT.cpp:160
void setAllOff()
Definition: PS3BT.cpp:519
#define L2CAP_DONE
Definition: BTD.h:105
#define L2CAP_CONTROL_SUCCESS
Definition: BTD.h:110
#define L2CAP_WAIT
Definition: BTD.h:104
StatusEnum
Definition: PS3Enums.h:113
#define HID_BUFFERSIZE
Definition: PS3BT.h:24
void Reset()
Definition: PS3BT.cpp:204
#define pgm_read_byte(addr)
char remote_name[30]
Definition: BTD.h:458
const uint32_t PS3_BUTTONS[]
Definition: PS3Enums.h:62
bool getButtonPress(ButtonEnum b)
Definition: PS3BT.cpp:49
LEDEnum
int16_t getSensor(SensorEnum a)
Definition: PS3BT.cpp:68
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t *dcid, uint8_t *scid)
Definition: BTD.cpp:1326
#define Notify(...)
Definition: message.h:51
RumbleEnum
#define USB_HOST_SERIAL
Definition: settings.h:49
#define HID_CTRL_PSM
Definition: BTD.h:183
Definition: PS3Enums.h:123
bool connectToWii
Definition: BTD.h:470
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS3BT.cpp:64
uint16_t hci_handle
Definition: BTD.h:454
bool PS3Connected
Definition: PS3BT.h:176
void hci_disconnect(uint16_t handle)
Definition: BTD.cpp:1171
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
Definition: BTD.h:146
ButtonEnum
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b)
Definition: PS3BT.cpp:604
bool PS3MoveConnected
Definition: PS3BT.h:182
uint8_t my_bdaddr[6]
Definition: BTD.h:452
void setRumbleOn(RumbleEnum mode)
Definition: PS3BT.cpp:540
float get9DOFValues(SensorEnum a)
Definition: PS3BT.cpp:112
const uint8_t PS3_LEDS[]
Definition: PS3Enums.h:43
#define l2cap_check_flag(flag)
Definition: BTD.h:161
#define L2CAP_CMD_CONFIG_REQUEST
Definition: BTD.h:169
#define PSTR(str)
#define L2CAP_CMD_DISCONNECT_REQUEST
Definition: BTD.h:171
#define L2CAP_CONTROL_DISCONNECT
Definition: BTD.h:111
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
Definition: BTD.h:137
ColorsEnum
BTD * pBtd
Definition: BTD.h:612
#define BULK_MAXPKTSIZE
Definition: BTD.h:37
#define HID_INTR_PSM
Definition: BTD.h:184
const uint8_t PS3_ANALOG_BUTTONS[]
Definition: PS3Enums.h:92
bool l2capConnectionClaimed
Definition: BTD.h:440
AngleEnum
#define PS3_ENABLE_SIXAXIS
Definition: BTD.h:131
#define L2CAP_CMD_DISCONNECT_RESPONSE
Definition: BTD.h:172
void ACLData(uint8_t *ACLData)
Definition: PS3BT.cpp:224
#define L2CAP_CMD_CONFIG_RESPONSE
Definition: BTD.h:170
uint16_t hci_handle
Definition: BTD.h:615
void setLedOff()
Definition: PS3BT.h:138
#define strcat_P(dest, src)
void setLedToggle(LEDEnum a)
Definition: PS3BT.cpp:578
uint32_t l2cap_event_flag
Definition: BTD.h:618
#define PS3_REPORT_BUFFER_SIZE
Definition: PS3Enums.h:24
void disconnect()
Definition: PS3BT.cpp:217
void L2CAP_Command(uint16_t handle, uint8_t *data, uint8_t nbytes, uint8_t channelLow=0x01, uint8_t channelHigh=0x00)
Definition: BTD.cpp:1219
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t *scid)
Definition: BTD.cpp:1294
#define PENDING
Definition: BTD.h:177
#define l2cap_set_flag(flag)
Definition: BTD.h:162
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t *dcid)
Definition: BTD.cpp:1277
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
Definition: BTD.h:138
SensorEnum
#define L2CAP_CMD_CONNECTION_REQUEST
Definition: BTD.h:167
uint8_t getAnalogButton(ButtonEnum a)
Definition: PS3BT.cpp:60
float getAngle(AngleEnum a)
Definition: PS3BT.cpp:85
void setLedRaw(uint8_t value)
Definition: PS3BT.cpp:559
PS3BT(BTD *pBtd, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0)
Definition: PS3BT.cpp:23
bool checkHciHandle(uint8_t *buf, uint16_t handle)
Definition: BTD.h:604
void onInit()
Definition: PS3BT.cpp:628
Definition: PS3Enums.h:125
#define L2CAP_INTERRUPT_DISCONNECT
Definition: BTD.h:117
void setRumbleOff()
Definition: PS3BT.cpp:530
bool getButtonClick(ButtonEnum b)
Definition: PS3BT.cpp:53
const uint8_t PS3_REPORT_BUFFER[PS3_REPORT_BUFFER_SIZE]
Definition: PS3Enums.h:27
#define L2CAP_CMD_COMMAND_REJECT
Definition: BTD.h:166