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 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
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
;
33 HIDBuffer
[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02)
34 HIDBuffer
[1] = 0x01; // Report ID
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
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;
49 bool PS3BT::getButtonPress(ButtonEnum b
) {
50 return (ButtonState
& pgm_read_dword(&PS3_BUTTONS
[(uint8_t)b
]));
53 bool PS3BT::getButtonClick(ButtonEnum b
) {
54 uint32_t button
= pgm_read_dword(&PS3_BUTTONS
[(uint8_t)b
]);
55 bool click
= (ButtonClickState
& button
);
56 ButtonClickState
&= ~button
; // Clear "click" event
60 uint8_t PS3BT::getAnalogButton(ButtonEnum a
) {
61 return (uint8_t)(l2capinbuf
[pgm_read_byte(&PS3_ANALOG_BUTTONS
[(uint8_t)a
])]);
64 uint8_t PS3BT::getAnalogHat(AnalogHatEnum a
) {
65 return (uint8_t)(l2capinbuf
[(uint8_t)a
+ 15]);
68 int16_t PS3BT::getSensor(SensorEnum a
) {
70 if(a
== aX
|| a
== aY
|| a
== aZ
|| a
== gZ
)
71 return ((l2capinbuf
[(uint16_t)a
] << 8) | l2capinbuf
[(uint16_t)a
+ 1]);
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));
85 double PS3BT::getAngle(AngleEnum a
) {
86 double accXval
, accYval
, accZval
;
89 // Data for the Kionix KXPC4 used in the DualShock 3
90 const double zeroG
= 511.5; // 1.65/3.3*1023 (1.65V)
91 accXval
= -((double)getSensor(aX
) - zeroG
);
92 accYval
= -((double)getSensor(aY
) - zeroG
);
93 accZval
= -((double)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
);
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
107 return (atan2(accYval
, accZval
) + PI
) * RAD_TO_DEG
;
109 return (atan2(accXval
, accZval
) + PI
) * RAD_TO_DEG
;
112 double PS3BT::get9DOFValues(SensorEnum a
) { // Thanks to Manfred Piendl
113 if(!PS3MoveConnected
)
115 int16_t value
= getSensor(a
);
116 if(a
== mXmove
|| a
== mYmove
|| a
== mZmove
) {
119 return (double)value
/ 3.2; // unit: muT = 10^(-6) Tesla
120 } else if(a
== aXmove
|| a
== aYmove
|| a
== aZmove
) {
125 return (double)value
/ 442.0; // unit: m/(s^2)
126 } else if(a
== gXmove
|| a
== gYmove
|| a
== gZmove
) {
132 return (double)value
/ 11.6; // unit: deg/s
134 return (double)value
/ 11.2; // unit: deg/s
136 return (double)value
/ 9.6; // unit: deg/s
141 String
PS3BT::getTemperature() {
142 if(PS3MoveConnected
) {
143 int16_t input
= getSensor(tempMove
);
145 String output
= String(input
/ 100);
149 output
+= String(input
% 100);
156 bool PS3BT::getStatus(StatusEnum c
) {
157 return (l2capinbuf
[(uint16_t)c
>> 8] == ((uint8_t)c
& 0xff));
160 void PS3BT::printStatusString() {
161 char statusOutput
[100]; // Max string length plus null character
162 if(PS3Connected
|| PS3NavigationConnected
) {
163 strcpy_P(statusOutput
, PSTR("ConnectionStatus: "));
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"));
169 strcat_P(statusOutput
, PSTR(" - PowerRating: "));
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"));
180 strcat_P(statusOutput
, PSTR(" - WirelessStatus: "));
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("PowerRating: "));
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"));
199 strcpy_P(statusOutput
, PSTR("Error"));
201 USB_HOST_SERIAL
.write(statusOutput
);
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
;
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
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
);
221 l2cap_state
= L2CAP_INTERRUPT_DISCONNECT
;
224 void PS3BT::ACLData(uint8_t* ACLData
) {
225 if(!pBtd
->l2capConnectionClaimed
&& !PS3Connected
&& !PS3MoveConnected
&& !PS3NavigationConnected
&& !activeConnection
&& !pBtd
->connectToWii
&& !pBtd
->incomingWii
&& !pBtd
->pairWithWii
) {
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);
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);
262 } else if(l2capinbuf
[8] == L2CAP_CMD_CONNECTION_REQUEST
) {
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);
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];
279 l2cap_set_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
);
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];
284 l2cap_set_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
);
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);
290 l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
);
291 } else if(l2capinbuf
[12] == interrupt_dcid
[0] && l2capinbuf
[13] == interrupt_dcid
[1]) {
292 //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
293 l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS
);
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
);
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);
309 identifier
= l2capinbuf
[9];
310 pBtd
->l2cap_disconnection_response(hci_handle
, identifier
, control_dcid
, control_scid
);
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);
316 identifier
= l2capinbuf
[9];
317 pBtd
->l2cap_disconnection_response(hci_handle
, identifier
, interrupt_dcid
, interrupt_scid
);
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];
324 l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
);
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];
328 l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
);
333 Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
334 D_PrintHex
<uint8_t > (l2capinbuf
[8], 0x80);
337 } else if(l2capinbuf
[6] == interrupt_dcid
[0] && l2capinbuf
[7] == interrupt_dcid
[1]) { // l2cap_interrupt
338 //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
339 if(PS3Connected
|| PS3MoveConnected
|| PS3NavigationConnected
) {
341 if(l2capinbuf
[8] == 0xA1) { // HID_THDR_DATA_INPUT
342 lastMessageTime
= millis(); // Store the last message time
344 if(PS3Connected
|| PS3NavigationConnected
)
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));
349 //Notify(PSTR("\r\nButtonState", 0x80);
350 //PrintHex<uint32_t>(ButtonState, 0x80);
352 if(ButtonState
!= OldButtonState
) {
353 ButtonClickState
= ButtonState
& ~OldButtonState
; // Update click state variable
354 OldButtonState
= ButtonState
;
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);
362 Notify(PSTR("\r\n"), 0x80);
371 void PS3BT::L2CAP_task() {
372 switch(l2cap_state
) {
374 if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST
)) {
375 #ifdef DEBUG_USB_HOST
376 Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
378 pBtd
->l2cap_connection_response(hci_handle
, identifier
, control_dcid
, control_scid
, PENDING
);
380 pBtd
->l2cap_connection_response(hci_handle
, identifier
, control_dcid
, control_scid
, SUCCESSFUL
);
383 pBtd
->l2cap_config_request(hci_handle
, identifier
, control_scid
);
384 l2cap_state
= L2CAP_CONTROL_SUCCESS
;
388 case L2CAP_CONTROL_SUCCESS
:
389 if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS
)) {
390 #ifdef DEBUG_USB_HOST
391 Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
393 l2cap_state
= L2CAP_INTERRUPT_SETUP
;
397 case L2CAP_INTERRUPT_SETUP
:
398 if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST
)) {
399 #ifdef DEBUG_USB_HOST
400 Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
402 pBtd
->l2cap_connection_response(hci_handle
, identifier
, interrupt_dcid
, interrupt_scid
, PENDING
);
404 pBtd
->l2cap_connection_response(hci_handle
, identifier
, interrupt_dcid
, interrupt_scid
, SUCCESSFUL
);
407 pBtd
->l2cap_config_request(hci_handle
, identifier
, interrupt_scid
);
409 l2cap_state
= L2CAP_INTERRUPT_CONFIG_REQUEST
;
413 case L2CAP_INTERRUPT_CONFIG_REQUEST
:
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);
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
;
422 l2cap_state
= PS3_ENABLE_SIXAXIS
;
427 /* These states are handled in Run() */
429 case L2CAP_INTERRUPT_DISCONNECT
:
430 if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE
)) {
431 #ifdef DEBUG_USB_HOST
432 Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
435 pBtd
->l2cap_disconnection_request(hci_handle
, identifier
, control_scid
, control_dcid
);
436 l2cap_state
= L2CAP_CONTROL_DISCONNECT
;
440 case L2CAP_CONTROL_DISCONNECT
:
441 if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE
)) {
442 #ifdef DEBUG_USB_HOST
443 Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
445 pBtd
->hci_disconnect(hci_handle
);
446 hci_handle
= -1; // Reset handle
447 l2cap_event_flag
= 0; // Reset flags
448 l2cap_state
= L2CAP_WAIT
;
455 switch(l2cap_state
) {
456 case PS3_ENABLE_SIXAXIS
:
457 if(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
462 l2cap_state
= TURN_ON_LED
;
468 if(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);
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);
478 PS3NavigationConnected
= true;
479 } else if(remote_name_first
== 'M') { // First letter in Motion Controller ('M')
481 #ifdef DEBUG_USB_HOST
482 Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
484 PS3MoveConnected
= true;
486 ButtonState
= 0; // Clear all values
488 ButtonClickState
= 0;
490 onInit(); // Turn on the LED on the controller
491 l2cap_state
= 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(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
506 /************************************************************/
508 /************************************************************/
510 // Playstation Sixaxis Dualshock and Navigation Controller commands
512 void PS3BT::HID_Command(uint8_t* data
, uint8_t nbytes
) {
513 if(millis() - timerHID
<= 150) // Check if is has been more than 150ms since last command
514 delay((uint32_t)(150 - (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
519 void PS3BT::setAllOff() {
520 HIDBuffer
[3] = 0x00; // Rumble bytes
525 HIDBuffer
[11] = 0x00; // LED byte
527 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
530 void PS3BT::setRumbleOff() {
536 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
539 void PS3BT::setRumbleOn(RumbleEnum mode
) {
540 uint8_t power
[2] = {0xff, 0x00}; // Defaults to RumbleLow
541 if(mode
== RumbleHigh
) {
545 setRumbleOn(0xfe, power
[0], 0xfe, power
[1]);
548 void PS3BT::setRumbleOn(uint8_t rightDuration
, uint8_t rightPower
, uint8_t leftDuration
, uint8_t leftPower
) {
549 HIDBuffer
[3] = rightDuration
;
550 HIDBuffer
[4] = rightPower
;
551 HIDBuffer
[5] = leftDuration
;
552 HIDBuffer
[6] = leftPower
;
553 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
556 void PS3BT::setLedRaw(uint8_t value
) {
557 HIDBuffer
[11] = value
<< 1;
558 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
561 void PS3BT::setLedOff(LEDEnum a
) {
562 HIDBuffer
[11] &= ~((uint8_t)((pgm_read_byte(&PS3_LEDS
[(uint8_t)a
]) & 0x0f) << 1));
563 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
566 void PS3BT::setLedOn(LEDEnum a
) {
570 HIDBuffer
[11] |= (uint8_t)((pgm_read_byte(&PS3_LEDS
[(uint8_t)a
]) & 0x0f) << 1);
571 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
575 void PS3BT::setLedToggle(LEDEnum a
) {
576 HIDBuffer
[11] ^= (uint8_t)((pgm_read_byte(&PS3_LEDS
[(uint8_t)a
]) & 0x0f) << 1);
577 HID_Command(HIDBuffer
, HID_BUFFERSIZE
);
580 void PS3BT::enable_sixaxis() { // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth
582 cmd_buf
[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03)
583 cmd_buf
[1] = 0xF4; // Report ID
584 cmd_buf
[2] = 0x42; // Special PS3 Controller enable commands
589 HID_Command(cmd_buf
, 6);
592 // Playstation Move Controller commands
594 void PS3BT::HIDMove_Command(uint8_t* data
, uint8_t nbytes
) {
595 if(millis() - timerHID
<= 150)// Check if is has been less than 150ms since last command
596 delay((uint32_t)(150 - (millis() - timerHID
))); // There have to be a delay between commands
597 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 void PS3BT::moveSetBulb(uint8_t r
, uint8_t g
, uint8_t b
) { // Use this to set the Color using RGB values
602 // Set the Bulb's values into the write buffer
603 HIDMoveBuffer
[3] = r
;
604 HIDMoveBuffer
[4] = g
;
605 HIDMoveBuffer
[5] = b
;
607 HIDMove_Command(HIDMoveBuffer
, HID_BUFFERSIZE
);
610 void PS3BT::moveSetBulb(ColorsEnum color
) { // Use this to set the Color using the predefined colors in enum
611 moveSetBulb((uint8_t)(color
>> 16), (uint8_t)(color
>> 8), (uint8_t)(color
));
614 void PS3BT::moveSetRumble(uint8_t rumble
) {
615 #ifdef DEBUG_USB_HOST
616 if(rumble
< 64 && rumble
!= 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
617 Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
619 // Set the rumble value into the write buffer
620 HIDMoveBuffer
[7] = rumble
;
622 HIDMove_Command(HIDMoveBuffer
, HID_BUFFERSIZE
);
625 void PS3BT::onInit() {
627 pFuncOnInit(); // Call the user function
631 else // Dualshock 3 or Navigation controller