2012-03-04 02:38:50 +01:00
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2012-03-02 08:34:29 +01:00
This software may be distributed and modified under the terms of the GNU
General Public License version 2 ( GPL2 ) as published by the Free Software
Foundation and appearing in the file GPL2 . TXT included in the packaging of
this file . Please note that GPL2 Section 2 [ b ] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ( " Copyleft " ) .
Contact information
- - - - - - - - - - - - - - - - - - -
2012-03-04 02:38:50 +01:00
Kristian Lauszus , TKJ Electronics
2012-03-02 08:34:29 +01:00
Web : http : //www.tkjelectronics.com
2012-03-04 02:38:50 +01:00
e - mail : kristianl @ tkjelectronics . com
2012-03-02 08:34:29 +01:00
*/
# include "PS3BT.h"
# define DEBUG // Uncomment to print data for debugging
2012-04-11 16:48:55 +02:00
//#define EXTRADEBUG // Uncomment to get even more debugging data
2012-03-02 08:34:29 +01:00
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
2012-08-04 12:20:47 +02:00
const uint8_t OUTPUT_REPORT_BUFFER [ ] PROGMEM = {
2012-03-02 08:34:29 +01:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0xff , 0x27 , 0x10 , 0x00 , 0x32 ,
0xff , 0x27 , 0x10 , 0x00 , 0x32 ,
0xff , 0x27 , 0x10 , 0x00 , 0x32 ,
0xff , 0x27 , 0x10 , 0x00 , 0x32 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
2012-08-04 12:20:47 +02:00
PS3BT : : PS3BT ( BTD * p , uint8_t btadr5 , uint8_t btadr4 , uint8_t btadr3 , uint8_t btadr2 , uint8_t btadr1 , uint8_t btadr0 ) :
pBtd ( p ) // pointer to USB class instance - mandatory
{
if ( pBtd )
pBtd - > registerServiceClass ( this ) ; // Register it as a Bluetooth service
pBtd - > my_bdaddr [ 5 ] = btadr5 ; // Change to your dongle's Bluetooth address instead
pBtd - > my_bdaddr [ 4 ] = btadr4 ;
pBtd - > my_bdaddr [ 3 ] = btadr3 ;
pBtd - > my_bdaddr [ 2 ] = btadr2 ;
pBtd - > my_bdaddr [ 1 ] = btadr1 ;
pBtd - > my_bdaddr [ 0 ] = btadr0 ;
HIDBuffer [ 0 ] = 0x52 ; // HID BT Set_report (0x50) | Report Type (Output 0x02)
HIDBuffer [ 1 ] = 0x01 ; // Report ID
2012-03-02 08:34:29 +01:00
2012-08-04 12:20:47 +02:00
//Needed for PS3 Move Controller commands to work via bluetooth
HIDMoveBuffer [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
HIDMoveBuffer [ 1 ] = 0x02 ; // Report ID
2012-04-12 23:15:18 +02:00
2012-08-04 12:20:47 +02:00
/* Set device cid for the control and intterrupt channelse - LSB */
control_dcid [ 0 ] = 0x40 ; //0x0040
control_dcid [ 1 ] = 0x00 ;
interrupt_dcid [ 0 ] = 0x41 ; //0x0041
interrupt_dcid [ 1 ] = 0x00 ;
2012-03-02 08:34:29 +01:00
2012-08-08 05:40:53 +02:00
Reset ( ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 19:46:32 +02:00
bool PS3BT : : getButton ( Button b ) {
2012-08-04 20:10:59 +02:00
if ( l2capinbuf = = NULL )
2012-03-02 08:34:29 +01:00
return false ;
2012-05-28 21:53:20 +02:00
if ( PS3MoveConnected ) {
2012-08-04 20:10:59 +02:00
if ( ( l2capinbuf [ ( ( uint16_t ) b > > 8 ) - 1 ] & ( ( uint8_t ) b & 0xff ) ) ) // All the buttons locations are shifted one back on the Move controller
2012-05-28 21:53:20 +02:00
return true ;
else
return false ;
} else {
2012-08-04 20:10:59 +02:00
if ( ( l2capinbuf [ ( uint16_t ) b > > 8 ] & ( ( uint8_t ) b & 0xff ) ) )
2012-05-28 21:53:20 +02:00
return true ;
else
return false ;
}
2012-03-02 08:34:29 +01:00
}
2012-08-04 19:46:32 +02:00
uint8_t PS3BT : : getAnalogButton ( AnalogButton a ) {
2012-08-04 20:10:59 +02:00
if ( l2capinbuf = = NULL )
2012-03-02 08:34:29 +01:00
return 0 ;
2012-08-04 20:10:59 +02:00
return ( uint8_t ) ( l2capinbuf [ ( uint16_t ) a ] ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 19:46:32 +02:00
uint8_t PS3BT : : getAnalogHat ( AnalogHat a ) {
2012-08-04 20:10:59 +02:00
if ( l2capinbuf = = NULL )
2012-03-02 08:34:29 +01:00
return 0 ;
2012-08-04 20:10:59 +02:00
return ( uint8_t ) ( l2capinbuf [ ( uint16_t ) a ] ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 19:46:32 +02:00
int16_t PS3BT : : getSensor ( Sensor a ) {
2012-08-04 20:10:59 +02:00
if ( l2capinbuf = = NULL )
2012-04-11 01:52:43 +02:00
return 0 ;
2012-03-02 08:34:29 +01:00
if ( a = = aX | | a = = aY | | a = = aZ | | a = = gZ )
2012-08-04 20:10:59 +02:00
return ( ( l2capinbuf [ ( uint16_t ) a ] < < 8 ) | l2capinbuf [ ( uint16_t ) a + 1 ] ) ;
2012-05-28 21:02:43 +02:00
else if ( a = = mXmove | | a = = mYmove | | a = = mZmove ) // These are all 12-bits long
2012-04-11 01:52:43 +02:00
{
// Might not be correct, haven't tested it yet
2012-05-28 21:02:43 +02:00
/*if (a == mXmove)
2012-08-04 20:10:59 +02:00
return ( ( l2capinbuf [ ( uint16_t ) a + 1 ] < < 0x04 ) | ( l2capinbuf [ ( uint16_t ) a ] < < 0x0C ) ) ;
2012-03-02 08:34:29 +01:00
else if ( a = = mYmove )
2012-08-04 20:10:59 +02:00
return ( ( l2capinbuf [ ( uint16_t ) a + 1 ] & 0xF0 ) | ( l2capinbuf [ ( uint16_t ) a ] < < 0x08 ) ) ;
2012-03-02 08:34:29 +01:00
else if ( a = = mZmove )
2012-08-04 20:10:59 +02:00
return ( ( l2capinbuf [ ( uint16_t ) a + 1 ] < < 0x0F ) | ( l2capinbuf [ ( uint16_t ) a ] < < 0x0C ) ) ;
2012-05-28 21:02:43 +02:00
*/
if ( a = = mXmove | | a = = mYmove )
2012-08-04 20:10:59 +02:00
return ( ( ( l2capinbuf [ ( uint16_t ) a ] & 0x0F ) < < 8 ) | ( l2capinbuf [ ( uint16_t ) a + 1 ] ) ) ;
2012-05-28 21:02:43 +02:00
else // mZmove
2012-08-04 20:10:59 +02:00
return ( ( l2capinbuf [ ( uint16_t ) a ] < < 4 ) | ( l2capinbuf [ ( uint16_t ) a + 1 ] > > 4 ) ) ;
2012-03-02 08:34:29 +01:00
}
2012-05-28 21:02:43 +02:00
else if ( a = = tempMove ) // The tempearature is 12 bits long too
2012-08-04 20:10:59 +02:00
return ( ( l2capinbuf [ ( uint16_t ) a ] < < 4 ) | ( ( l2capinbuf [ ( uint16_t ) a + 1 ] & 0xF0 ) > > 4 ) ) ;
2012-04-24 22:49:34 +02:00
else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove
2012-08-04 20:10:59 +02:00
return ( l2capinbuf [ ( uint16_t ) a ] | ( l2capinbuf [ ( uint16_t ) a + 1 ] < < 8 ) ) ;
2012-04-24 22:49:34 +02:00
}
double PS3BT : : getAngle ( Angle a ) {
double accXval ;
double accYval ;
double accZval ;
2012-05-26 01:46:18 +02:00
if ( PS3Connected ) {
2012-04-24 22:49:34 +02:00
// Data for the Kionix KXPC4 used in the DualShock 3
2012-05-09 19:46:26 +02:00
const double zeroG = 511.5 ; // 1.65/3.3*1023 (1,65V)
accXval = - ( ( double ) getSensor ( aX ) - zeroG ) ;
accYval = - ( ( double ) getSensor ( aY ) - zeroG ) ;
accZval = - ( ( double ) getSensor ( aZ ) - zeroG ) ;
2012-05-26 01:46:18 +02:00
} else if ( PS3MoveConnected ) {
2012-05-09 19:46:26 +02:00
// It's a Kionix KXSC4 inside the Motion controller
const uint16_t zeroG = 0x8000 ;
2012-06-01 17:27:21 +02:00
accXval = - ( int16_t ) ( getSensor ( aXmove ) - zeroG ) ;
accYval = ( int16_t ) ( getSensor ( aYmove ) - zeroG ) ;
accZval = ( int16_t ) ( getSensor ( aZmove ) - zeroG ) ;
2012-03-02 08:34:29 +01:00
}
2012-04-24 22:49:34 +02:00
2012-04-24 01:35:43 +02:00
// Convert to 360 degrees resolution
// atan2 outputs the value of -π to π (radians)
2012-04-24 22:49:34 +02:00
// We are then converting it to 0 to 2π and then to degrees
2012-04-24 01:35:43 +02:00
if ( a = = Pitch ) {
2012-05-09 19:46:26 +02:00
double angle = ( atan2 ( accYval , accZval ) + PI ) * RAD_TO_DEG ;
2012-04-24 01:35:43 +02:00
return angle ;
} else {
2012-05-09 19:46:26 +02:00
double angle = ( atan2 ( accXval , accZval ) + PI ) * RAD_TO_DEG ;
2012-04-24 01:35:43 +02:00
return angle ;
2012-04-24 22:49:34 +02:00
}
2012-03-02 08:34:29 +01:00
}
2012-06-01 18:47:15 +02:00
String PS3BT : : getTemperature ( ) {
if ( PS3MoveConnected ) {
int16_t input = getSensor ( tempMove ) ;
String output = String ( input / 100 ) ;
output + = " . " ;
if ( input % 100 < 10 )
output + = " 0 " ;
output + = String ( input % 100 ) ;
return output ;
}
}
2012-08-04 19:46:32 +02:00
bool PS3BT : : getStatus ( Status c ) {
2012-08-04 20:10:59 +02:00
if ( l2capinbuf = = NULL )
2012-03-02 08:34:29 +01:00
return false ;
2012-08-04 20:10:59 +02:00
if ( l2capinbuf [ ( uint16_t ) c > > 8 ] = = ( ( uint8_t ) c & 0xff ) )
2012-03-02 08:34:29 +01:00
return true ;
return false ;
}
2012-08-04 19:46:32 +02:00
String PS3BT : : getStatusString ( ) {
if ( PS3Connected | | PS3NavigationConnected ) {
2012-03-02 08:34:29 +01:00
char statusOutput [ 100 ] ;
strcpy ( statusOutput , " ConnectionStatus: " ) ;
if ( getStatus ( Plugged ) ) strcat ( statusOutput , " Plugged " ) ;
else if ( getStatus ( Unplugged ) ) strcat ( statusOutput , " Unplugged " ) ;
else strcat ( statusOutput , " Error " ) ;
strcat ( statusOutput , " - PowerRating: " ) ;
if ( getStatus ( Charging ) ) strcat ( statusOutput , " Charging " ) ;
else if ( getStatus ( NotCharging ) ) strcat ( statusOutput , " Not Charging " ) ;
else if ( getStatus ( Shutdown ) ) strcat ( statusOutput , " Shutdown " ) ;
else if ( getStatus ( Dying ) ) strcat ( statusOutput , " Dying " ) ;
else if ( getStatus ( Low ) ) strcat ( statusOutput , " Low " ) ;
else if ( getStatus ( High ) ) strcat ( statusOutput , " High " ) ;
else if ( getStatus ( Full ) ) strcat ( statusOutput , " Full " ) ;
else strcat ( statusOutput , " Error " ) ;
strcat ( statusOutput , " - WirelessStatus: " ) ;
if ( getStatus ( CableRumble ) ) strcat ( statusOutput , " Cable - Rumble is on " ) ;
else if ( getStatus ( Cable ) ) strcat ( statusOutput , " Cable - Rumble is off " ) ;
else if ( getStatus ( BluetoothRumble ) ) strcat ( statusOutput , " Bluetooth - Rumble is on " ) ;
else if ( getStatus ( Bluetooth ) ) strcat ( statusOutput , " Bluetooth - Rumble is off " ) ;
else strcat ( statusOutput , " Error " ) ;
return statusOutput ;
}
2012-08-04 19:46:32 +02:00
else if ( PS3MoveConnected ) {
2012-03-02 08:34:29 +01:00
char statusOutput [ 50 ] ;
strcpy ( statusOutput , " PowerRating: " ) ;
if ( getStatus ( MoveCharging ) ) strcat ( statusOutput , " Charging " ) ;
else if ( getStatus ( MoveNotCharging ) ) strcat ( statusOutput , " Not Charging " ) ;
else if ( getStatus ( MoveShutdown ) ) strcat ( statusOutput , " Shutdown " ) ;
else if ( getStatus ( MoveDying ) ) strcat ( statusOutput , " Dying " ) ;
else if ( getStatus ( MoveLow ) ) strcat ( statusOutput , " Low " ) ;
else if ( getStatus ( MoveHigh ) ) strcat ( statusOutput , " High " ) ;
else if ( getStatus ( MoveFull ) ) strcat ( statusOutput , " Full " ) ;
else strcat ( statusOutput , " Error " ) ;
return statusOutput ;
}
}
2012-08-08 05:40:53 +02:00
void PS3BT : : Reset ( ) {
2012-08-04 12:20:47 +02:00
PS3Connected = false ;
PS3MoveConnected = false ;
PS3NavigationConnected = false ;
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_EV_WAIT ;
2012-03-02 08:34:29 +01:00
2012-08-04 12:20:47 +02:00
// Needed for PS3 Dualshock Controller commands to work via bluetooth
for ( uint8_t i = 0 ; i < OUTPUT_REPORT_BUFFER_SIZE ; i + + )
HIDBuffer [ i + 2 ] = pgm_read_byte ( & OUTPUT_REPORT_BUFFER [ i ] ) ; // First two bytes reserved for report type and ID
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : disconnect ( ) { //Use this void to disconnect any of the controllers
PS3Connected = false ;
PS3MoveConnected = false ;
PS3NavigationConnected = false ;
//First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection
pBtd - > l2cap_disconnection_request ( hci_handle , 0x0A , interrupt_scid , interrupt_dcid ) ;
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_EV_INTERRUPT_DISCONNECT ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 20:10:59 +02:00
void PS3BT : : ACLData ( uint8_t * ACLData ) {
2012-08-08 05:40:53 +02:00
if ( ! pBtd - > l2capConnectionClaimed & & ! PS3Connected & & ! PS3MoveConnected & & ! PS3NavigationConnected ) {
if ( ACLData [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
if ( ( ( ACLData [ 12 ] | ( ACLData [ 13 ] < < 8 ) ) = = HID_CTRL_PSM ) | | ( ( ACLData [ 12 ] | ( ACLData [ 13 ] < < 8 ) ) = = HID_INTR_PSM ) ) {
2012-08-04 12:20:47 +02:00
pBtd - > claimConnection ( ) ; // Claim that the incoming connection belongs to this service
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
2012-08-09 20:30:32 +02:00
l2cap_state = L2CAP_EV_WAIT ;
2012-08-04 12:20:47 +02:00
for ( uint8_t i = 0 ; i < 30 ; i + + )
remote_name [ i ] = pBtd - > remote_name [ i ] ; // Store the remote name for the connection
# ifdef DEBUG
if ( pBtd - > hci_version < 3 ) { // Check the HCI Version of the Bluetooth dongle
2012-05-05 20:58:16 +02:00
Notify ( PSTR ( " \r \n Your dongle may not support reading the analog buttons, sensors and status \r \n Your HCI Version is: " ) ) ;
2012-08-04 12:20:47 +02:00
Serial . print ( pBtd - > hci_version ) ;
Notify ( PSTR ( " \r \n But should be at least 3 \r \n This means that it doesn't support Bluetooth Version 2.0+EDR " ) ) ;
2012-05-05 20:58:16 +02:00
}
2012-04-24 01:35:43 +02:00
# endif
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
}
2012-03-02 08:34:29 +01:00
}
2012-08-08 05:40:53 +02:00
if ( ( ( ACLData [ 0 ] | ( ACLData [ 1 ] < < 8 ) ) = = ( hci_handle | 0x2000 ) ) ) { //acl_handle_ok
for ( uint8_t i = 0 ; i < BULK_MAXPKTSIZE ; i + + )
l2capinbuf [ i ] = ACLData [ i ] ;
2012-08-04 12:20:47 +02:00
if ( ( l2capinbuf [ 6 ] | ( l2capinbuf [ 7 ] < < 8 ) ) = = 0x0001 ) { //l2cap_control - Channel ID for ACL-U
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_COMMAND_REJECT ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-04-11 01:52:43 +02:00
Notify ( PSTR ( " \r \n L2CAP Command Rejected - Reason: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 13 ] ) ;
Serial . print ( " " ) ;
PrintHex < uint8_t > ( l2capinbuf [ 12 ] ) ;
Serial . print ( " Data: " ) ;
PrintHex < uint8_t > ( l2capinbuf [ 17 ] ) ;
Serial . print ( " " ) ;
PrintHex < uint8_t > ( l2capinbuf [ 16 ] ) ;
Serial . print ( " " ) ;
PrintHex < uint8_t > ( l2capinbuf [ 15 ] ) ;
Serial . print ( " " ) ;
PrintHex < uint8_t > ( l2capinbuf [ 14 ] ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n L2CAP Connection Request - PSM: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 13 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 12 ] ) ;
Notify ( PSTR ( " SCID: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 15 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 14 ] ) ;
Notify ( PSTR ( " Identifier: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 9 ] ) ;
# endif
if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_CTRL_PSM ) {
2012-04-11 01:52:43 +02:00
identifier = l2capinbuf [ 9 ] ;
control_scid [ 0 ] = l2capinbuf [ 14 ] ;
control_scid [ 1 ] = l2capinbuf [ 15 ] ;
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_CONNECTION_CONTROL_REQUEST ;
2012-04-11 01:52:43 +02:00
}
2012-08-04 12:20:47 +02:00
else if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_INTR_PSM ) {
2012-04-11 01:52:43 +02:00
identifier = l2capinbuf [ 9 ] ;
interrupt_scid [ 0 ] = l2capinbuf [ 14 ] ;
interrupt_scid [ 1 ] = l2capinbuf [ 15 ] ;
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST ;
2012-03-02 08:34:29 +01:00
}
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_RESPONSE ) {
if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
if ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) { //Success
2012-04-11 01:52:43 +02:00
//Serial.print("\r\nHID Control Configuration Complete");
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_CONFIG_CONTROL_SUCCESS ;
2012-04-11 01:52:43 +02:00
}
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
if ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) { //Success
2012-04-11 01:52:43 +02:00
//Serial.print("\r\nHID Interrupt Configuration Complete");
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS ;
2012-04-11 01:52:43 +02:00
}
2012-03-02 08:34:29 +01:00
}
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_REQUEST ) {
if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
2012-04-11 01:52:43 +02:00
//Serial.print("\r\nHID Control Configuration Request");
identifier = l2capinbuf [ 9 ] ;
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_CONFIG_CONTROL_REQUEST ;
2012-04-11 01:52:43 +02:00
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
2012-04-11 01:52:43 +02:00
//Serial.print("\r\nHID Interrupt Configuration Request");
identifier = l2capinbuf [ 9 ] ;
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_CONFIG_INTERRUPT_REQUEST ;
2012-04-11 01:52:43 +02:00
}
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_REQUEST ) {
if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-05-28 21:02:43 +02:00
Notify ( PSTR ( " \r \n Disconnect Request: Control Channel " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-04-11 01:52:43 +02:00
identifier = l2capinbuf [ 9 ] ;
2012-08-04 12:20:47 +02:00
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , control_dcid , control_scid ) ;
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_EV_WAIT ;
2012-04-11 01:52:43 +02:00
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-05-28 21:02:43 +02:00
Notify ( PSTR ( " \r \n Disconnect Request: Interrupt Channel " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-04-11 01:52:43 +02:00
identifier = l2capinbuf [ 9 ] ;
2012-08-04 12:20:47 +02:00
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid ) ;
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_EV_WAIT ;
2012-04-11 01:52:43 +02:00
}
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_RESPONSE ) {
if ( l2capinbuf [ 12 ] = = control_scid [ 0 ] & & l2capinbuf [ 13 ] = = control_scid [ 1 ] ) {
2012-05-28 21:02:43 +02:00
//Serial.print("\r\nDisconnect Response: Control Channel");
2012-04-11 01:52:43 +02:00
identifier = l2capinbuf [ 9 ] ;
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE ;
2012-04-11 01:52:43 +02:00
}
2012-08-04 12:20:47 +02:00
else if ( l2capinbuf [ 12 ] = = interrupt_scid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_scid [ 1 ] ) {
2012-05-28 21:02:43 +02:00
//Serial.print("\r\nDisconnect Response: Interrupt Channel");
2012-04-11 01:52:43 +02:00
identifier = l2capinbuf [ 9 ] ;
2012-08-04 12:20:47 +02:00
l2cap_event_flag | = L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE ;
2012-04-11 01:52:43 +02:00
}
2012-03-02 08:34:29 +01:00
}
2012-04-24 01:35:43 +02:00
# ifdef EXTRADEBUG
2012-08-04 12:20:47 +02:00
else {
Notify ( PSTR ( " \r \n L2CAP Unknown Signaling Command: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 8 ] ) ;
}
# endif
} else if ( l2capinbuf [ 6 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 7 ] = = interrupt_dcid [ 1 ] ) { // l2cap_interrupt
//Serial.print("\r\nL2CAP Interrupt");
if ( PS3Connected | | PS3MoveConnected | | PS3NavigationConnected ) {
/* Read Report */
2012-08-04 19:46:32 +02:00
if ( l2capinbuf [ 8 ] = = 0xA1 ) { // HID_THDR_DATA_INPUT
2012-08-04 12:20:47 +02:00
if ( PS3Connected | | PS3NavigationConnected )
ButtonState = ( uint32_t ) ( l2capinbuf [ 11 ] | ( ( uint16_t ) l2capinbuf [ 12 ] < < 8 ) | ( ( uint32_t ) l2capinbuf [ 13 ] < < 16 ) ) ;
else if ( PS3MoveConnected )
ButtonState = ( uint32_t ) ( l2capinbuf [ 10 ] | ( ( uint16_t ) l2capinbuf [ 11 ] < < 8 ) | ( ( uint32_t ) l2capinbuf [ 12 ] < < 16 ) ) ;
//Notify(PSTR("\r\nButtonState");
//PrintHex<uint32_t>(ButtonState);
2012-08-04 19:46:32 +02:00
if ( ButtonState ! = OldButtonState ) {
2012-08-04 12:20:47 +02:00
buttonChanged = true ;
if ( ButtonState ! = 0x00 ) {
buttonPressed = true ;
buttonReleased = false ;
} else {
buttonPressed = false ;
buttonReleased = true ;
}
2012-08-04 19:46:32 +02:00
}
else {
2012-08-04 12:20:47 +02:00
buttonChanged = false ;
buttonPressed = false ;
buttonReleased = false ;
2012-08-04 19:46:32 +02:00
}
OldButtonState = ButtonState ;
2012-08-04 12:20:47 +02:00
}
# ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
if ( l2capinbuf [ 8 ] = = 0xA1 ) { //HID_THDR_DATA_INPUT
for ( uint8_t i = 10 ; i < 58 ; i + + ) {
PrintHex < uint8_t > ( l2capinbuf [ i ] ) ;
Serial . print ( " " ) ;
}
Serial . println ( ) ;
}
2012-04-24 01:35:43 +02:00
# endif
2012-08-04 12:20:47 +02:00
}
}
2012-08-08 05:40:53 +02:00
L2CAP_task ( ) ;
2012-03-02 08:34:29 +01:00
}
}
2012-08-08 05:40:53 +02:00
void PS3BT : : L2CAP_task ( ) {
2012-08-04 12:20:47 +02:00
switch ( l2cap_state ) {
2012-03-02 08:34:29 +01:00
case L2CAP_EV_WAIT :
2012-08-04 12:20:47 +02:00
if ( l2cap_connection_request_control_flag ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-03-02 08:34:29 +01:00
Notify ( PSTR ( " \r \n HID Control Incoming Connection Request " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-08-04 12:20:47 +02:00
pBtd - > l2cap_connection_response ( hci_handle , identifier , control_dcid , control_scid , PENDING ) ;
2012-03-02 08:34:29 +01:00
delay ( 1 ) ;
2012-08-04 12:20:47 +02:00
pBtd - > l2cap_connection_response ( hci_handle , identifier , control_dcid , control_scid , SUCCESSFUL ) ;
2012-03-02 08:34:29 +01:00
identifier + + ;
delay ( 1 ) ;
2012-08-04 12:20:47 +02:00
pBtd - > l2cap_config_request ( hci_handle , identifier , control_scid ) ;
2012-03-02 08:34:29 +01:00
l2cap_state = L2CAP_EV_CONTROL_REQUEST ;
}
break ;
case L2CAP_EV_CONTROL_REQUEST :
2012-08-04 12:20:47 +02:00
if ( l2cap_config_request_control_flag ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-03-02 08:34:29 +01:00
Notify ( PSTR ( " \r \n HID Control Configuration Request " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-08-08 05:40:53 +02:00
pBtd - > l2cap_config_response ( hci_handle , identifier , control_scid ) ;
2012-03-02 08:34:29 +01:00
l2cap_state = L2CAP_EV_CONTROL_SUCCESS ;
}
break ;
case L2CAP_EV_CONTROL_SUCCESS :
2012-08-04 12:20:47 +02:00
if ( l2cap_config_success_control_flag ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-03-02 08:34:29 +01:00
Notify ( PSTR ( " \r \n HID Control Successfully Configured " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-03-02 08:34:29 +01:00
l2cap_state = L2CAP_EV_INTERRUPT_SETUP ;
}
break ;
case L2CAP_EV_INTERRUPT_SETUP :
2012-08-04 12:20:47 +02:00
if ( l2cap_connection_request_interrupt_flag ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-03-02 08:34:29 +01:00
Notify ( PSTR ( " \r \n HID Interrupt Incoming Connection Request " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-08-08 05:40:53 +02:00
pBtd - > l2cap_connection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid , PENDING ) ;
2012-03-02 08:34:29 +01:00
delay ( 1 ) ;
2012-08-08 05:40:53 +02:00
pBtd - > l2cap_connection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid , SUCCESSFUL ) ;
2012-03-02 08:34:29 +01:00
identifier + + ;
delay ( 1 ) ;
2012-08-08 05:40:53 +02:00
pBtd - > l2cap_config_request ( hci_handle , identifier , interrupt_scid ) ;
2012-03-02 08:34:29 +01:00
l2cap_state = L2CAP_EV_INTERRUPT_REQUEST ;
}
break ;
case L2CAP_EV_INTERRUPT_REQUEST :
2012-08-04 12:20:47 +02:00
if ( l2cap_config_request_interrupt_flag ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-03-02 08:34:29 +01:00
Notify ( PSTR ( " \r \n HID Interrupt Configuration Request " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-08-04 12:20:47 +02:00
pBtd - > l2cap_config_response ( hci_handle , identifier , interrupt_scid ) ;
2012-03-02 08:34:29 +01:00
l2cap_state = L2CAP_EV_INTERRUPT_SUCCESS ;
}
break ;
case L2CAP_EV_INTERRUPT_SUCCESS :
2012-08-04 12:20:47 +02:00
if ( l2cap_config_success_interrupt_flag ) {
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-03-02 08:34:29 +01:00
Notify ( PSTR ( " \r \n HID Interrupt Successfully Configured " ) ) ;
2012-08-08 05:40:53 +02:00
# endif
if ( remote_name [ 0 ] = = ' M ' ) { // First letter in Motion Controller ('M')
2012-04-15 01:42:16 +02:00
for ( uint8_t i = 0 ; i < BULK_MAXPKTSIZE ; i + + ) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
2012-08-04 20:10:59 +02:00
l2capinbuf [ i ] = 0 ;
2012-04-15 01:42:16 +02:00
ButtonState = 0 ;
2012-08-04 12:20:47 +02:00
OldButtonState = 0 ;
2012-04-24 01:35:43 +02:00
2012-04-15 01:42:16 +02:00
l2cap_state = L2CAP_EV_HID_PS3_LED ;
} else
2012-04-24 01:35:43 +02:00
l2cap_state = L2CAP_EV_HID_ENABLE_SIXAXIS ;
2012-04-15 01:42:16 +02:00
timer = millis ( ) ;
2012-03-02 08:34:29 +01:00
}
break ;
2012-08-08 05:40:53 +02:00
/* These states are handled in Run() */
case L2CAP_EV_INTERRUPT_DISCONNECT :
if ( l2cap_disconnect_response_interrupt_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Disconnected Interrupt Channel " ) ) ;
# endif
identifier + + ;
pBtd - > l2cap_disconnection_request ( hci_handle , identifier , control_scid , control_dcid ) ;
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_EV_CONTROL_DISCONNECT ;
}
break ;
case L2CAP_EV_CONTROL_DISCONNECT :
if ( l2cap_disconnect_response_control_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Disconnected Control Channel " ) ) ;
# endif
pBtd - > hci_disconnect ( hci_handle ) ;
l2cap_state = L2CAP_EV_WAIT ;
}
break ;
}
}
void PS3BT : : Run ( ) {
switch ( l2cap_state ) {
2012-04-15 01:42:16 +02:00
case L2CAP_EV_HID_ENABLE_SIXAXIS :
if ( millis ( ) - timer > 1000 ) { // loop 1 second before sending the command
for ( uint8_t i = 0 ; i < BULK_MAXPKTSIZE ; i + + ) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
2012-08-04 20:10:59 +02:00
l2capinbuf [ i ] = 0 ;
2012-04-15 01:42:16 +02:00
ButtonState = 0 ;
2012-08-08 05:40:53 +02:00
OldButtonState = 0 ;
2012-03-02 08:34:29 +01:00
2012-08-04 12:20:47 +02:00
enable_sixaxis ( ) ;
2012-03-02 08:34:29 +01:00
for ( uint8_t i = 15 ; i < 19 ; i + + )
2012-08-04 20:10:59 +02:00
l2capinbuf [ i ] = 0x7F ; // Set the analog joystick values to center position
2012-04-15 01:42:16 +02:00
l2cap_state = L2CAP_EV_HID_PS3_LED ;
timer = millis ( ) ;
2012-03-02 08:34:29 +01:00
}
2012-04-15 01:42:16 +02:00
break ;
2012-08-08 05:40:53 +02:00
case L2CAP_EV_HID_PS3_LED :
2012-04-15 01:42:16 +02:00
if ( millis ( ) - timer > 1000 ) { // loop 1 second before sending the command
if ( remote_name [ 0 ] = = ' P ' ) { // First letter in PLAYSTATION(R)3 Controller ('P')
setLedOn ( LED1 ) ;
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-04-15 01:42:16 +02:00
Notify ( PSTR ( " \r \n Dualshock 3 Controller Enabled \r \n " ) ) ;
2012-08-08 05:40:53 +02:00
# endif
2012-05-26 01:46:18 +02:00
PS3Connected = true ;
2012-04-15 01:42:16 +02:00
} else if ( remote_name [ 0 ] = = ' N ' ) { // First letter in Navigation Controller ('N')
setLedOn ( LED1 ) ; // This just turns LED constantly on, on the Navigation controller
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-04-15 01:42:16 +02:00
Notify ( PSTR ( " \r \n Navigation Controller Enabled \r \n " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-05-26 01:46:18 +02:00
PS3NavigationConnected = true ;
2012-08-08 05:40:53 +02:00
} else if ( remote_name [ 0 ] = = ' M ' ) { // First letter in Motion Controller ('M')
2012-04-15 01:42:16 +02:00
moveSetBulb ( Red ) ;
timerBulbRumble = millis ( ) ;
2012-04-24 01:35:43 +02:00
# ifdef DEBUG
2012-04-15 01:42:16 +02:00
Notify ( PSTR ( " \r \n Motion Controller Enabled \r \n " ) ) ;
2012-04-24 01:35:43 +02:00
# endif
2012-05-26 01:46:18 +02:00
PS3MoveConnected = true ;
2012-04-15 01:42:16 +02:00
}
2012-08-08 05:40:53 +02:00
l2cap_state = L2CAP_EV_DONE ;
}
2012-03-02 08:34:29 +01:00
break ;
2012-08-04 12:20:47 +02:00
case L2CAP_EV_DONE :
2012-08-04 19:46:32 +02:00
if ( PS3MoveConnected ) { //The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on
if ( millis ( ) - timerBulbRumble > 4000 ) { //Send at least every 4th second
2012-04-11 01:52:43 +02:00
HIDMove_Command ( HIDMoveBuffer , HID_BUFFERSIZE ) ; //The Bulb and rumble values, has to be written again and again, for it to stay turned on
2012-03-02 08:34:29 +01:00
timerBulbRumble = millis ( ) ;
}
}
break ;
}
}
/************************************************************/
/* HID Commands */
/************************************************************/
//Playstation Sixaxis Dualshock and Navigation Controller commands
2012-08-04 12:20:47 +02:00
void PS3BT : : HID_Command ( uint8_t * data , uint8_t nbytes ) {
2012-05-26 01:46:18 +02:00
if ( millis ( ) - timerHID < = 250 ) // Check if is has been more than 250ms since last command
delay ( ( uint32_t ) ( 250 - ( millis ( ) - timerHID ) ) ) ; //There have to be a delay between commands
2012-08-08 19:22:07 +02:00
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
2012-03-02 08:34:29 +01:00
timerHID = millis ( ) ;
}
2012-08-04 12:20:47 +02:00
void PS3BT : : setAllOff ( ) {
2012-03-02 08:34:29 +01:00
for ( uint8_t i = 0 ; i < OUTPUT_REPORT_BUFFER_SIZE ; i + + )
HIDBuffer [ i + 2 ] = pgm_read_byte ( & OUTPUT_REPORT_BUFFER [ i ] ) ; //First two bytes reserved for report type and ID
2012-04-11 01:52:43 +02:00
HID_Command ( HIDBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : setRumbleOff ( ) {
2012-03-02 08:34:29 +01:00
HIDBuffer [ 3 ] = 0x00 ;
HIDBuffer [ 4 ] = 0x00 ; //low mode off
HIDBuffer [ 5 ] = 0x00 ;
HIDBuffer [ 6 ] = 0x00 ; //high mode off
2012-04-11 01:52:43 +02:00
HID_Command ( HIDBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : setRumbleOn ( Rumble mode ) {
2012-03-02 08:34:29 +01:00
/* Still not totally sure how it works, maybe something like this instead?
* 3 - duration_right
* 4 - power_right
* 5 - duration_left
* 6 - power_left
*/
if ( ( mode & 0x30 ) > 0 )
{
HIDBuffer [ 3 ] = 0xfe ;
HIDBuffer [ 5 ] = 0xfe ;
if ( mode = = RumbleHigh )
{
HIDBuffer [ 4 ] = 0 ; //low mode off
HIDBuffer [ 6 ] = 0xff ; //high mode on
}
else
{
HIDBuffer [ 4 ] = 0xff ; //low mode on
HIDBuffer [ 6 ] = 0 ; //high mode off
}
2012-04-11 01:52:43 +02:00
HID_Command ( HIDBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}
}
2012-08-04 12:20:47 +02:00
void PS3BT : : setLedOff ( LED a ) {
2012-05-09 18:38:38 +02:00
HIDBuffer [ 11 ] & = ~ ( ( uint8_t ) ( ( ( uint16_t ) a & 0x0f ) < < 1 ) ) ;
HID_Command ( HIDBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : setLedOn ( LED a ) {
2012-05-09 18:38:38 +02:00
HIDBuffer [ 11 ] | = ( uint8_t ) ( ( ( uint16_t ) a & 0x0f ) < < 1 ) ;
HID_Command ( HIDBuffer , HID_BUFFERSIZE ) ;
}
2012-08-04 12:20:47 +02:00
void PS3BT : : setLedToggle ( LED a ) {
2012-05-09 18:38:38 +02:00
HIDBuffer [ 11 ] ^ = ( uint8_t ) ( ( ( uint16_t ) a & 0x0f ) < < 1 ) ;
2012-04-11 01:52:43 +02:00
HID_Command ( HIDBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : enable_sixaxis ( ) { //Command used to enable the Dualshock 3 and Navigation controller to send data via USB
2012-04-11 01:52:43 +02:00
uint8_t cmd_buf [ 6 ] ;
2012-03-02 08:34:29 +01:00
cmd_buf [ 0 ] = 0x53 ; // HID BT Set_report (0x50) | Report Type (Feature 0x03)
cmd_buf [ 1 ] = 0xF4 ; // Report ID
cmd_buf [ 2 ] = 0x42 ; // Special PS3 Controller enable commands
cmd_buf [ 3 ] = 0x03 ;
cmd_buf [ 4 ] = 0x00 ;
cmd_buf [ 5 ] = 0x00 ;
HID_Command ( cmd_buf , 6 ) ;
}
//Playstation Move Controller commands
2012-08-04 12:20:47 +02:00
void PS3BT : : HIDMove_Command ( uint8_t * data , uint8_t nbytes ) {
if ( millis ( ) - timerHID < = 250 ) // Check if is has been less than 200ms since last command
2012-05-26 01:46:18 +02:00
delay ( ( uint32_t ) ( 250 - ( millis ( ) - timerHID ) ) ) ; //There have to be a delay between commands
2012-08-04 12:20:47 +02:00
pBtd - > L2CAP_Command ( hci_handle , data , nbytes , interrupt_scid [ 0 ] , interrupt_scid [ 1 ] ) ; // The Move controller sends it's data via the intterrupt channel
2012-03-02 08:34:29 +01:00
timerHID = millis ( ) ;
}
2012-08-04 12:20:47 +02:00
void PS3BT : : moveSetBulb ( uint8_t r , uint8_t g , uint8_t b ) { //Use this to set the Color using RGB values
2012-03-02 08:34:29 +01:00
//set the Bulb's values into the write buffer
HIDMoveBuffer [ 3 ] = r ;
HIDMoveBuffer [ 4 ] = g ;
HIDMoveBuffer [ 5 ] = b ;
2012-04-11 01:52:43 +02:00
HIDMove_Command ( HIDMoveBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : moveSetBulb ( Colors color ) { //Use this to set the Color using the predefined colors in enum
2012-05-26 01:46:18 +02:00
moveSetBulb ( ( uint8_t ) ( color > > 16 ) , ( uint8_t ) ( color > > 8 ) , ( uint8_t ) ( color ) ) ;
2012-03-02 08:34:29 +01:00
}
2012-08-04 12:20:47 +02:00
void PS3BT : : moveSetRumble ( uint8_t rumble ) {
2012-05-26 01:46:18 +02:00
# ifdef DEBUG
if ( rumble < 64 & & rumble ! = 0 ) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify ( PSTR ( " \r \n The rumble value has to at least 64, or approximately 25% " ) ) ;
# endif
2012-03-02 08:34:29 +01:00
//set the rumble value into the write buffer
HIDMoveBuffer [ 7 ] = rumble ;
2012-04-11 01:52:43 +02:00
HIDMove_Command ( HIDMoveBuffer , HID_BUFFERSIZE ) ;
2012-03-02 08:34:29 +01:00
}