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