This commit is contained in:
Oleg Mazurov 2012-07-26 17:02:12 -06:00
commit 9a58f9b94d
13 changed files with 2278 additions and 386 deletions

View file

@ -1,13 +1,13 @@
The PS3BT.cpp PS3BT.h was developed by Kristian Lauszus The PS3BT.cpp, PS3BT.h, PS3USB.cpp, PS3USB.h, XBOXUSB.cpp, and XBOXUSB.h were developed by Kristian Lauszus
For more information regarding the PS3 protocol etc. visit my blog at: http://blog.tkjelectronics.dk/ or send me an email at kristianl at tkjelectronics dot dk. For more information regarding the PS3 protocol etc. visit my blog at: http://blog.tkjelectronics.dk/ or send me an email at kristianl at tkjelectronics dot dk.
You could also visit the official wiki: https://github.com/TKJElectronics/USB_Host_Shield_2.0/wiki for information. You could also visit the official wiki: https://github.com/TKJElectronics/USB_Host_Shield_2.0/wiki for information.
All three PS3 Controllers are supported (Dualshock 3-, Navigation-, and Motioncontroller). All three PS3 Controllers are supported (Dualshock 3-, Navigation-, and Motioncontroller).
They communicate with the Arduino via Bluetooth using the USB Host Shield from http://www.circuitsathome.com/ They communicate with the Arduino via Bluetooth or USB using the USB Host Shield from http://www.circuitsathome.com/
A special thanks go to the following people: A special thanks go to the following people:
"Richard Ibbotson" who made this guide: http://www.circuitsathome.com/mcu/ps3-and-wiimote-game-controllers-on-the-arduino-host-shield-part-1 "Richard Ibbotson" who made this excellent guide: http://www.circuitsathome.com/mcu/ps3-and-wiimote-game-controllers-on-the-arduino-host-shield-part-1
- It inspired me to get starting and had a lot of good information for the USB communication - It inspired me to get starting and had a lot of good information for the USB communication
"Tomoyuki Tanaka" for releasing his code for the Arduino USB Host shield connected to the wiimote: http://www.circuitsathome.com/mcu/rc-car-controlled-by-wii-remote-on-arduino "Tomoyuki Tanaka" for releasing his code for the Arduino USB Host shield connected to the wiimote: http://www.circuitsathome.com/mcu/rc-car-controlled-by-wii-remote-on-arduino
@ -19,4 +19,8 @@ http://www.copenhagengamecollective.org/unimove/
https://github.com/thp/psmoveapi https://github.com/thp/psmoveapi
http://code.google.com/p/moveonpc/ http://code.google.com/p/moveonpc/
All the information regarding the Xbox 360 controller protocol are form these two sites:
http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/UsbInfo
http://pingus.seul.org/~grumbel/xboxdrv/
And at last I would like to thank Oleg from http://www.circuitsathome.com/ for making such an awesome shield! And at last I would like to thank Oleg from http://www.circuitsathome.com/ for making such an awesome shield!

265
PS3BT.cpp
View file

@ -24,7 +24,7 @@ const uint8_t PS3BT::BTD_EVENT_PIPE = 1;
const uint8_t PS3BT::BTD_DATAIN_PIPE = 2; const uint8_t PS3BT::BTD_DATAIN_PIPE = 2;
const uint8_t PS3BT::BTD_DATAOUT_PIPE = 3; const uint8_t PS3BT::BTD_DATAOUT_PIPE = 3;
prog_char OUTPUT_REPORT_BUFFER[] PROGMEM = { uint8_t OUTPUT_REPORT_BUFFER[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32,
@ -62,25 +62,6 @@ bPollEnable(false) // don't start polling before dongle is connected
my_bdaddr[0] = btadr0; my_bdaddr[0] = btadr0;
} }
PS3BT::PS3BT(USB *p):
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bNumEP(1), // if config descriptor needs to be parsed
qNextPollTime(0),
bPollEnable(false) // don't start polling before dongle is connected
{
for(uint8_t i=0; i<PS3_MAX_ENDPOINTS; i++)
{
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
}
uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
{ {
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)]; uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
@ -283,7 +264,7 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
interrupt_dcid[0] = 0x41;//0x0041 interrupt_dcid[0] = 0x41;//0x0041
interrupt_dcid[1] = 0x00; interrupt_dcid[1] = 0x00;
hci_num_reset_loops = 10; // only loop 10 times before trying to send the hci reset command hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command
hci_state = HCI_INIT_STATE; hci_state = HCI_INIT_STATE;
hci_counter = 0; hci_counter = 0;
@ -388,6 +369,9 @@ void PS3BT::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
/* Performs a cleanup after failed Init() attempt */ /* Performs a cleanup after failed Init() attempt */
uint8_t PS3BT::Release() uint8_t PS3BT::Release()
{ {
PS3Connected = false;
PS3MoveConnected = false;
PS3NavigationConnected = false;
pUsb->GetAddressPool().FreeAddress(bAddress); pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0; bAddress = 0;
bPollEnable = false; bPollEnable = false;
@ -399,24 +383,20 @@ uint8_t PS3BT::Poll()
if (!bPollEnable) if (!bPollEnable)
return 0; return 0;
if (qNextPollTime <= millis()) { // Don't poll if shorter than polling interval if (qNextPollTime <= millis()) { // Don't poll if shorter than polling interval
qNextPollTime = millis() + pollInterval; // Set new poll time
HCI_event_task(); // poll the HCI event pipe HCI_event_task(); // poll the HCI event pipe
ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected
} }
qNextPollTime = millis() + pollInterval; // Poll time
return 0; return 0;
} }
void PS3BT::setBdaddr(uint8_t* BDADDR) void PS3BT::setBdaddr(uint8_t* BDADDR)
{ {
/* Store the bluetooth address */
for(uint8_t i = 0; i <6;i++)
my_bdaddr[i] = BDADDR[i];
/* Set the internal bluetooth address */ /* Set the internal bluetooth address */
uint8_t buf[8]; uint8_t buf[8];
buf[0] = 0x01; buf[0] = 0x01;
buf[1] = 0x00; buf[1] = 0x00;
for (uint8_t i = 0; i < 6; i++) for (uint8_t i = 0; i < 6; i++)
buf[i+2] = my_bdaddr[5 - i];//Copy into buffer, has to be written reversed buf[i+2] = BDADDR[5 - i];//Copy into buffer, has to be written reversed
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
@ -433,10 +413,6 @@ void PS3BT::setBdaddr(uint8_t* BDADDR)
} }
void PS3BT::setMoveBdaddr(uint8_t* BDADDR) void PS3BT::setMoveBdaddr(uint8_t* BDADDR)
{ {
/* Store the bluetooth address */
for(uint8_t i = 0; i <6;i++)
my_bdaddr[i] = BDADDR[i];
/* Set the internal bluetooth address */ /* Set the internal bluetooth address */
uint8_t buf[11]; uint8_t buf[11];
buf[0] = 0x05; buf[0] = 0x05;
@ -446,7 +422,7 @@ void PS3BT::setMoveBdaddr(uint8_t* BDADDR)
buf[10] = 0x12; buf[10] = 0x12;
for (uint8_t i = 0; i < 6; i++) for (uint8_t i = 0; i < 6; i++)
buf[i + 1] = my_bdaddr[i]; buf[i + 1] = BDADDR[i];
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL); pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL);
@ -465,10 +441,17 @@ bool PS3BT::getButton(Button b)
{ {
if (l2capinbuf == NULL) if (l2capinbuf == NULL)
return false; return false;
if ((l2capinbuf[(uint16_t)b >> 8] & ((uint8_t)b & 0xff)) > 0) if(PS3MoveConnected) {
if((l2capinbuf[((uint16_t)b >> 8)-1] & ((uint8_t)b & 0xff))) // All the buttons locations are shifted one back on the Move controller
return true; return true;
else else
return false; return false;
} else {
if((l2capinbuf[(uint16_t)b >> 8] & ((uint8_t)b & 0xff)))
return true;
else
return false;
}
} }
uint8_t PS3BT::getAnalogButton(AnalogButton a) uint8_t PS3BT::getAnalogButton(AnalogButton a)
{ {
@ -482,87 +465,75 @@ uint8_t PS3BT::getAnalogHat(AnalogHat a)
return 0; return 0;
return (uint8_t)(l2capinbuf[(uint16_t)a]); return (uint8_t)(l2capinbuf[(uint16_t)a]);
} }
int32_t PS3BT::getSensor(Sensor a) int16_t PS3BT::getSensor(Sensor a)
{ {
if (l2capinbuf == NULL) if (l2capinbuf == NULL)
return 0; return 0;
if (a == aX || a == aY || a == aZ || a == gZ) if (a == aX || a == aY || a == aZ || a == gZ)
return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]); return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]);
else if (a == mXmove || a == mYmove || a == mZmove) else if (a == mXmove || a == mYmove || a == mZmove) // These are all 12-bits long
{ {
// Might not be correct, haven't tested it yet // Might not be correct, haven't tested it yet
if (a == mXmove) /*if (a == mXmove)
return ((l2capinbuf[(uint16_t)a + 1] << 0x04) | (l2capinbuf[(uint16_t)a] << 0x0C)); return ((l2capinbuf[(uint16_t)a + 1] << 0x04) | (l2capinbuf[(uint16_t)a] << 0x0C));
//return (((unsigned char)l2capinbuf[(unsigned int)a + 1]) | (((unsigned char)l2capinbuf[(unsigned int)a] & 0x0F)) << 8);
else if (a == mYmove) else if (a == mYmove)
return ((l2capinbuf[(uint16_t)a + 1] & 0xF0) | (l2capinbuf[(uint16_t)a] << 0x08)); return ((l2capinbuf[(uint16_t)a + 1] & 0xF0) | (l2capinbuf[(uint16_t)a] << 0x08));
//return (((unsigned char)l2capinbuf[(unsigned int)a + 1]) | (((unsigned char)l2capinbuf[(unsigned int)a] & 0x0F)) << 8);
else if (a == mZmove) else if (a == mZmove)
return ((l2capinbuf[(uint16_t)a + 1] << 0x0F) | (l2capinbuf[(uint16_t)a] << 0x0C)); return ((l2capinbuf[(uint16_t)a + 1] << 0x0F) | (l2capinbuf[(uint16_t)a] << 0x0C));
//return ((((unsigned char)l2capinbuf[(unsigned int)a + 1] & 0xF0) >> 4) | ((unsigned char)l2capinbuf[(unsigned int)a] << 4)); */
else if (a == mXmove || a == mYmove)
return 0; return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1]));
else // mZmove
return ((l2capinbuf[(uint16_t)a] << 4) | (l2capinbuf[(uint16_t)a + 1] >> 4));
} }
else if (a == tempMove) else if (a == tempMove) // The tempearature is 12 bits long too
return (((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4) | (l2capinbuf[(uint16_t)a] << 4)); return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4));
else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove
return ((l2capinbuf[(uint16_t)a + 1] << 8) | l2capinbuf[(uint16_t)a]); return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8));
} }
double PS3BT::getAngle(Angle a) { double PS3BT::getAngle(Angle a) {
double accXval; double accXval;
double accYval; double accYval;
double accZval; double accZval;
if(PS3BTConnected) { if(PS3Connected) {
// Data for the Kionix KXPC4 used in the DualShock 3 // Data for the Kionix KXPC4 used in the DualShock 3
double sensivity = 204.6; // 0.66/3.3*1023 (660mV/g) const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) accXval = -((double)getSensor(aX)-zeroG);
accXval = ((double)getSensor(aX)-zeroG) / sensivity; // Convert to g's accYval = -((double)getSensor(aY)-zeroG);
accXval *= 2; accZval = -((double)getSensor(aZ)-zeroG);
accYval = ((double)getSensor(aY)-zeroG) / sensivity; // Convert to g's } else if(PS3MoveConnected) {
accYval *= 2;
accZval = ((double)getSensor(aZ)-zeroG) / sensivity; // Convert to g's
accZval *= 2;
} else if(PS3MoveBTConnected) {
// It's a Kionix KXSC4 inside the Motion controller // It's a Kionix KXSC4 inside the Motion controller
const uint16_t sensivity = 28285; // Find by experimenting const uint16_t zeroG = 0x8000;
accXval = (double)getSensor(aXmove)/sensivity; accXval = -(int16_t)(getSensor(aXmove)-zeroG);
accYval = (double)getSensor(aYmove)/sensivity; accYval = (int16_t)(getSensor(aYmove)-zeroG);
accZval = (double)getSensor(aZmove)/sensivity; accZval = (int16_t)(getSensor(aZmove)-zeroG);
if(accXval < -1) // Convert to g's
accXval = ((1+accXval)-(1-1.15))*(-1/0.15);
else if(accXval > 1)
accXval = ((1+accXval)-(1+1.15))*(-1/0.15);
if(accYval < -1) // Convert to g's
accYval = ((1+accYval)-(1-1.15))*(-1/0.15);
else if(accYval > 1)
accYval = ((1+accYval)-(1+1.15))*(-1/0.15);
if(accZval < -1) // Convert to g's
accZval = ((1+accZval)-(1-1.15))*(-1/0.15);
else if(accZval > 1)
accZval = ((1+accZval)-(1+1.15))*(-1/0.15);
} }
double R = sqrt(accXval*accXval + accYval*accYval + accZval*accZval); // Calculate the length of the force vector
// Normalize vectors
accXval = accXval/R;
accYval = accYval/R;
accZval = accZval/R;
// Convert to 360 degrees resolution // Convert to 360 degrees resolution
// atan2 outputs the value of -π to π (radians) // atan2 outputs the value of -π to π (radians)
// We are then converting it to 0 to 2π and then to degrees // We are then converting it to 0 to 2π and then to degrees
if (a == Pitch) { if (a == Pitch) {
double angle = (atan2(-accYval,-accZval)+PI)*RAD_TO_DEG; double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG;
return angle; return angle;
} else { } else {
double angle = (atan2(-accXval,-accZval)+PI)*RAD_TO_DEG; double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG;
return angle; return angle;
} }
} }
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;
}
}
bool PS3BT::getStatus(Status c) bool PS3BT::getStatus(Status c)
{ {
if (l2capinbuf == NULL) if (l2capinbuf == NULL)
@ -573,7 +544,7 @@ bool PS3BT::getStatus(Status c)
} }
String PS3BT::getStatusString() String PS3BT::getStatusString()
{ {
if (PS3BTConnected || PS3NavigationBTConnected) if (PS3Connected || PS3NavigationConnected)
{ {
char statusOutput[100]; char statusOutput[100];
@ -605,7 +576,7 @@ String PS3BT::getStatusString()
return statusOutput; return statusOutput;
} }
else if(PS3MoveBTConnected) else if(PS3MoveConnected)
{ {
char statusOutput[50]; char statusOutput[50];
@ -625,12 +596,12 @@ String PS3BT::getStatusString()
} }
void PS3BT::disconnect()//Use this void to disconnect any of the controllers void PS3BT::disconnect()//Use this void to disconnect any of the controllers
{ {
if (PS3BTConnected) if (PS3Connected)
PS3BTConnected = false; PS3Connected = false;
else if (PS3MoveBTConnected) else if (PS3MoveConnected)
PS3MoveBTConnected = false; PS3MoveConnected = false;
else if (PS3NavigationBTConnected) else if (PS3NavigationConnected)
PS3NavigationBTConnected = false; PS3NavigationConnected = false;
//First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection //First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection
l2cap_disconnection_request(0x0A, interrupt_dcid, interrupt_scid); l2cap_disconnection_request(0x0A, interrupt_dcid, interrupt_scid);
@ -648,10 +619,16 @@ void PS3BT::HCI_event_task()
{ {
case EV_COMMAND_COMPLETE: case EV_COMMAND_COMPLETE:
hci_event_flag |= HCI_FLAG_CMD_COMPLETE; // set command complete flag hci_event_flag |= HCI_FLAG_CMD_COMPLETE; // set command complete flag
if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10))// parameters from read local bluetooth address if (!hcibuf[5]) { // check if command succeeded
{ if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // parameters from read local version information
hci_version = hcibuf[6]; // Check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm
hci_event_flag |= HCI_FLAG_READ_VERSION;
}
else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // parameters from read local bluetooth address
for (uint8_t i = 0; i < 6; i++) for (uint8_t i = 0; i < 6; i++)
my_bdaddr[i] = hcibuf[6 + i]; my_bdaddr[i] = hcibuf[6 + i];
hci_event_flag |= HCI_FLAG_READ_BDADDR;
}
} }
break; break;
@ -685,9 +662,6 @@ void PS3BT::HCI_event_task()
} }
break; break;
case EV_NUM_COMPLETE_PKT:
break;
case EV_REMOTE_NAME_COMPLETE: case EV_REMOTE_NAME_COMPLETE:
if (!hcibuf[2]) // check if reading is OK if (!hcibuf[2]) // check if reading is OK
{ {
@ -708,6 +682,10 @@ void PS3BT::HCI_event_task()
break; break;
/* We will just ignore the following events */ /* We will just ignore the following events */
case EV_NUM_COMPLETE_PKT:
break;
case EV_ROLE_CHANGED: case EV_ROLE_CHANGED:
break; break;
@ -782,8 +760,9 @@ void PS3BT::HCI_task()
hci_counter = 0; hci_counter = 0;
} }
break; break;
case HCI_BDADDR_STATE: case HCI_BDADDR_STATE:
if (hci_cmd_complete) if (hci_read_bdaddr_complete)
{ {
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nLocal Bluetooth Address: ")); Notify(PSTR("\r\nLocal Bluetooth Address: "));
@ -793,10 +772,27 @@ void PS3BT::HCI_task()
Serial.print(":"); Serial.print(":");
} }
PrintHex<uint8_t>(my_bdaddr[0]); PrintHex<uint8_t>(my_bdaddr[0]);
#endif
hci_read_local_version_information();
hci_state = HCI_LOCAL_VERSION_STATE;
}
break;
case HCI_LOCAL_VERSION_STATE:
if (hci_read_version_complete)
{
#ifdef DEBUG
if(hci_version < 3) {
Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "));
Serial.print(hci_version);
Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"));
}
#endif #endif
hci_state = HCI_SCANNING_STATE; hci_state = HCI_SCANNING_STATE;
} }
break; break;
break;
case HCI_SCANNING_STATE: case HCI_SCANNING_STATE:
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nWait For Incoming Connection Request")); Notify(PSTR("\r\nWait For Incoming Connection Request"));
@ -957,14 +953,14 @@ void PS3BT::ACL_event_task()
Notify(PSTR(" Identifier: ")); Notify(PSTR(" Identifier: "));
PrintHex<uint8_t>(l2capinbuf[9]); PrintHex<uint8_t>(l2capinbuf[9]);
*/ */
if ((l2capinbuf[13] | l2capinbuf[12]) == L2CAP_PSM_HID_CTRL) if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == L2CAP_PSM_HID_CTRL)
{ {
identifier = l2capinbuf[9]; identifier = l2capinbuf[9];
control_scid[0] = l2capinbuf[14]; control_scid[0] = l2capinbuf[14];
control_scid[1] = l2capinbuf[15]; control_scid[1] = l2capinbuf[15];
l2cap_event_flag |= L2CAP_EV_CONTROL_CONNECTION_REQUEST; l2cap_event_flag |= L2CAP_EV_CONTROL_CONNECTION_REQUEST;
} }
else if ((l2capinbuf[13] | l2capinbuf[12]) == L2CAP_PSM_HID_INTR) else if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == L2CAP_PSM_HID_INTR)
{ {
identifier = l2capinbuf[9]; identifier = l2capinbuf[9];
interrupt_scid[0] = l2capinbuf[14]; interrupt_scid[0] = l2capinbuf[14];
@ -1011,7 +1007,7 @@ void PS3BT::ACL_event_task()
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1])
{ {
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nDisconnected Request: Disconnected Control")); Notify(PSTR("\r\nDisconnect Request: Control Channel"));
#endif #endif
identifier = l2capinbuf[9]; identifier = l2capinbuf[9];
l2cap_disconnection_response(identifier,control_dcid,control_scid); l2cap_disconnection_response(identifier,control_dcid,control_scid);
@ -1019,7 +1015,7 @@ void PS3BT::ACL_event_task()
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1])
{ {
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nDisconnected Request: Disconnected Interrupt")); Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"));
#endif #endif
identifier = l2capinbuf[9]; identifier = l2capinbuf[9];
l2cap_disconnection_response(identifier,interrupt_dcid,interrupt_scid); l2cap_disconnection_response(identifier,interrupt_dcid,interrupt_scid);
@ -1029,13 +1025,13 @@ void PS3BT::ACL_event_task()
{ {
if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1])
{ {
//Serial.print("\r\nDisconnected Response: Disconnected Control"); //Serial.print("\r\nDisconnect Response: Control Channel");
identifier = l2capinbuf[9]; identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_EV_CONTROL_DISCONNECT_RESPONSE; l2cap_event_flag |= L2CAP_EV_CONTROL_DISCONNECT_RESPONSE;
} }
else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1])
{ {
//Serial.print("\r\nDisconnected Response: Disconnected Interrupt"); //Serial.print("\r\nDisconnect Response: Interrupt Channel");
identifier = l2capinbuf[9]; identifier = l2capinbuf[9];
l2cap_event_flag |= L2CAP_EV_INTERRUPT_DISCONNECT_RESPONSE; l2cap_event_flag |= L2CAP_EV_INTERRUPT_DISCONNECT_RESPONSE;
} }
@ -1044,7 +1040,7 @@ void PS3BT::ACL_event_task()
else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1])//l2cap_interrupt else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1])//l2cap_interrupt
{ {
//Serial.print("\r\nL2CAP Interrupt"); //Serial.print("\r\nL2CAP Interrupt");
if(PS3BTConnected || PS3MoveBTConnected || PS3NavigationBTConnected) if(PS3Connected || PS3MoveConnected || PS3NavigationConnected)
{ {
readReport(); readReport();
#ifdef PRINTREPORT #ifdef PRINTREPORT
@ -1169,30 +1165,29 @@ void PS3BT::L2CAP_task()
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n")); Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"));
#endif #endif
PS3BTConnected = true; PS3Connected = true;
} else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N') } else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N')
setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nNavigation Controller Enabled\r\n")); Notify(PSTR("\r\nNavigation Controller Enabled\r\n"));
#endif #endif
PS3NavigationBTConnected = true; PS3NavigationConnected = true;
} else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M') } else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M')
moveSetBulb(Red); moveSetBulb(Red);
timerBulbRumble = millis(); timerBulbRumble = millis();
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nMotion Controller Enabled\r\n")); Notify(PSTR("\r\nMotion Controller Enabled\r\n"));
#endif #endif
PS3MoveBTConnected = true; PS3MoveConnected = true;
} }
l2cap_state = L2CAP_EV_L2CAP_DONE; l2cap_state = L2CAP_EV_L2CAP_DONE;
} }
break; break;
case L2CAP_EV_L2CAP_DONE: case L2CAP_EV_L2CAP_DONE:
if (PS3MoveBTConnected)//The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on if (PS3MoveConnected)//The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on
{ {
dtimeBulbRumble = millis() - timerBulbRumble; if (millis() - timerBulbRumble > 4000)//Send at least every 4th second
if (dtimeBulbRumble > 4000)//Send at least every 4th second
{ {
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on
timerBulbRumble = millis(); timerBulbRumble = millis();
@ -1231,11 +1226,13 @@ void PS3BT::L2CAP_task()
/************************************************************/ /************************************************************/
void PS3BT::readReport() void PS3BT::readReport()
{ {
if (l2capinbuf == NULL)
return;
if(l2capinbuf[8] == 0xA1)//HID_THDR_DATA_INPUT if(l2capinbuf[8] == 0xA1)//HID_THDR_DATA_INPUT
{ {
if(PS3BTConnected || PS3NavigationBTConnected) if(PS3Connected || PS3NavigationConnected)
ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16)); ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
else if(PS3MoveBTConnected) else if(PS3MoveConnected)
ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16)); ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16));
//Notify(PSTR("\r\nButtonState"); //Notify(PSTR("\r\nButtonState");
@ -1266,6 +1263,8 @@ void PS3BT::readReport()
void PS3BT::printReport() //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers void PS3BT::printReport() //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
{ {
if (l2capinbuf == NULL)
return;
if(l2capinbuf[8] == 0xA1)//HID_THDR_DATA_INPUT if(l2capinbuf[8] == 0xA1)//HID_THDR_DATA_INPUT
{ {
for(uint8_t i = 10; i < 58;i++) for(uint8_t i = 10; i < 58;i++)
@ -1320,6 +1319,13 @@ void PS3BT::hci_read_bdaddr()
hcibuf[2] = 0x00; hcibuf[2] = 0x00;
HCI_Command(hcibuf, 3); HCI_Command(hcibuf, 3);
} }
void PS3BT::hci_read_local_version_information()
{
hcibuf[0] = 0x01; // HCI OCF = 1
hcibuf[1] = 0x04 << 2; // HCI OGF = 4
hcibuf[2] = 0x00;
HCI_Command(hcibuf, 3);
}
void PS3BT::hci_accept_connection() void PS3BT::hci_accept_connection()
{ {
hcibuf[0] = 0x09; // HCI OCF = 9 hcibuf[0] = 0x09; // HCI OCF = 9
@ -1513,10 +1519,8 @@ void PS3BT::HID_Command(uint8_t* data, uint16_t nbytes)
for (uint16_t i = 0; i < nbytes; i++)//L2CAP C-frame for (uint16_t i = 0; i < nbytes; i++)//L2CAP C-frame
buf[8 + i] = data[i]; buf[8 + i] = data[i];
dtimeHID = millis() - timerHID; 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
if (dtimeHID <= 250)// Check if is has been more than 250ms since last command
delay((uint32_t)(250 - dtimeHID));//There have to be a delay between commands
pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
@ -1567,19 +1571,17 @@ void PS3BT::setRumbleOn(Rumble mode)
} }
void PS3BT::setLedOff(LED a) void PS3BT::setLedOff(LED a)
{ {
//check if LED is already off HIDBuffer[11] &= ~((uint8_t)(((uint16_t)a & 0x0f) << 1));
if ((uint8_t)((uint8_t)(((uint16_t)a << 1) & HIDBuffer[11])) != 0)
{
//set the LED into the write buffer
HIDBuffer[11] = (uint8_t)((uint8_t)(((uint16_t)a & 0x0f) << 1) ^ HIDBuffer[11]);
HID_Command(HIDBuffer, HID_BUFFERSIZE); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
}
void PS3BT::setLedOn(LED a) void PS3BT::setLedOn(LED a)
{ {
HIDBuffer[11] = (uint8_t)((uint8_t)(((uint16_t)a & 0x0f) << 1) | HIDBuffer[11]); HIDBuffer[11] |= (uint8_t)(((uint16_t)a & 0x0f) << 1);
HID_Command(HIDBuffer, HID_BUFFERSIZE);
}
void PS3BT::setLedToggle(LED a)
{
HIDBuffer[11] ^= (uint8_t)(((uint16_t)a & 0x0f) << 1);
HID_Command(HIDBuffer, HID_BUFFERSIZE); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
void PS3BT::enable_sixaxis()//Command used to enable the Dualshock 3 and Navigation controller to send data via USB void PS3BT::enable_sixaxis()//Command used to enable the Dualshock 3 and Navigation controller to send data via USB
@ -1611,10 +1613,8 @@ void PS3BT::HIDMove_Command(uint8_t* data,uint16_t nbytes)
for (uint16_t i = 0; i < nbytes; i++)//L2CAP C-frame for (uint16_t i = 0; i < nbytes; i++)//L2CAP C-frame
buf[8 + i] = data[i]; buf[8 + i] = data[i];
dtimeHID = millis() - timerHID; if (millis() - timerHID <= 250)// Check if is has been less than 200ms since last command
delay((uint32_t)(250 - (millis() - timerHID)));//There have to be a delay between commands
if (dtimeHID <= 250)// Check if is has been less than 200ms since last command
delay((uint32_t)(250 - dtimeHID));//There have to be a delay between commands
pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
@ -1631,15 +1631,14 @@ void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b)//Use this to set the Co
} }
void PS3BT::moveSetBulb(Colors color)//Use this to set the Color using the predefined colors in "enums.h" void PS3BT::moveSetBulb(Colors color)//Use this to set the Color using the predefined colors in "enums.h"
{ {
//set the Bulb's values into the write buffer moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color));
HIDMoveBuffer[3] = (uint8_t)(color >> 16);
HIDMoveBuffer[4] = (uint8_t)(color >> 8);
HIDMoveBuffer[5] = (uint8_t)(color);
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
} }
void PS3BT::moveSetRumble(uint8_t rumble) void PS3BT::moveSetRumble(uint8_t rumble)
{ {
#ifdef DEBUG
if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"));
#endif
//set the rumble value into the write buffer //set the rumble value into the write buffer
HIDMoveBuffer[7] = rumble; HIDMoveBuffer[7] = rumble;

65
PS3BT.h
View file

@ -62,13 +62,14 @@
#define HCI_INIT_STATE 0 #define HCI_INIT_STATE 0
#define HCI_RESET_STATE 1 #define HCI_RESET_STATE 1
#define HCI_BDADDR_STATE 2 #define HCI_BDADDR_STATE 2
#define HCI_SCANNING_STATE 3 #define HCI_LOCAL_VERSION_STATE 3
#define HCI_CONNECT_IN_STATE 4 #define HCI_SCANNING_STATE 4
#define HCI_REMOTE_NAME_STATE 5 #define HCI_CONNECT_IN_STATE 5
#define HCI_CONNECTED_STATE 6 #define HCI_REMOTE_NAME_STATE 6
#define HCI_DISABLE_SCAN 7 #define HCI_CONNECTED_STATE 7
#define HCI_DONE_STATE 8 #define HCI_DISABLE_SCAN 8
#define HCI_DISCONNECT_STATE 9 #define HCI_DONE_STATE 9
#define HCI_DISCONNECT_STATE 10
/* HCI event flags*/ /* HCI event flags*/
#define HCI_FLAG_CMD_COMPLETE 0x01 #define HCI_FLAG_CMD_COMPLETE 0x01
@ -76,6 +77,8 @@
#define HCI_FLAG_DISCONN_COMPLETE 0x04 #define HCI_FLAG_DISCONN_COMPLETE 0x04
#define HCI_FLAG_REMOTE_NAME_COMPLETE 0x08 #define HCI_FLAG_REMOTE_NAME_COMPLETE 0x08
#define HCI_FLAG_INCOMING_REQUEST 0x10 #define HCI_FLAG_INCOMING_REQUEST 0x10
#define HCI_FLAG_READ_BDADDR 0x20
#define HCI_FLAG_READ_VERSION 0x40
/*Macros for HCI event flag tests */ /*Macros for HCI event flag tests */
#define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE) #define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE)
@ -83,6 +86,8 @@
#define hci_disconnect_complete (hci_event_flag & HCI_FLAG_DISCONN_COMPLETE) #define hci_disconnect_complete (hci_event_flag & HCI_FLAG_DISCONN_COMPLETE)
#define hci_remote_name_complete (hci_event_flag & HCI_FLAG_REMOTE_NAME_COMPLETE) #define hci_remote_name_complete (hci_event_flag & HCI_FLAG_REMOTE_NAME_COMPLETE)
#define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST) #define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST)
#define hci_read_bdaddr_complete (hci_event_flag & HCI_FLAG_READ_BDADDR)
#define hci_read_version_complete (hci_event_flag & HCI_FLAG_READ_VERSION)
/* HCI Events managed */ /* HCI Events managed */
#define EV_COMMAND_COMPLETE 0x0E #define EV_COMMAND_COMPLETE 0x0E
@ -175,16 +180,16 @@ enum LED
enum Colors enum Colors
{ {
// Used to set the colors of the move controller // Used to set the colors of the move controller
Red = 0xFF0000,//((255 << 16) | (0 << 8) | 0); Red = 0xFF0000, // r = 255, g = 0, b = 0
Green = 0xFF00,//((0 << 16) | (255 << 8) | 0); Green = 0xFF00, // r = 0, g = 255, b = 0
Blue = 0xFF,//((0 << 16) | (0 << 8) | 255); Blue = 0xFF, // r = 0, g = 0, b = 255
Yellow = 0xFFEB04,//((255 << 16) | (235 << 8) | 4); Yellow = 0xFFEB04, // r = 255, g = 235, b = 4
Lightblue = 0xFFFF,//((0 << 16) | (255 << 8) | 255); Lightblue = 0xFFFF, // r = 0, g = 255, b = 255
Purble = 0xFF00FF,//((255 << 16) | (0 << 8) | 255); Purble = 0xFF00FF, // r = 255, g = 0, b = 255
White = 0xFFFFFF,//((255 << 16) | (255 << 8) | 255); White = 0xFFFFFF, // r = 255, g = 255, b = 255
Off = 0x00,//((0 << 16) | (0 << 8) | 0); Off = 0x00, // r = 0, g = 0, b = 0
}; };
enum Button enum Button
@ -212,6 +217,12 @@ enum Button
PS = (13 << 8) | 0x01, PS = (13 << 8) | 0x01,
MOVE = (13/*12*/ << 8) | 0x08, // covers 12 bits - we only need to read the top 8
T = (13/*12*/ << 8) | 0x10, // covers 12 bits - we only need to read the top 8
// These are the true locations for the Move controller, but to make the same syntax for all controllers, it is handled by getButton()
/*
// Playstation Move Controller // Playstation Move Controller
SELECT_MOVE = (10 << 8) | 0x01, SELECT_MOVE = (10 << 8) | 0x01,
START_MOVE = (10 << 8) | 0x08, START_MOVE = (10 << 8) | 0x08,
@ -224,6 +235,7 @@ enum Button
PS_MOVE = (12 << 8) | 0x01, PS_MOVE = (12 << 8) | 0x01,
MOVE_MOVE = (12 << 8) | 0x08, // covers 12 bits - we only need to read the top 8 MOVE_MOVE = (12 << 8) | 0x08, // covers 12 bits - we only need to read the top 8
T_MOVE = (12 << 8) | 0x10, // covers 12 bits - we only need to read the top 8 T_MOVE = (12 << 8) | 0x10, // covers 12 bits - we only need to read the top 8
*/
}; };
enum AnalogButton enum AnalogButton
{ {
@ -243,7 +255,7 @@ enum AnalogButton
SQUARE_ANALOG = 34, SQUARE_ANALOG = 34,
//Playstation Move Controller //Playstation Move Controller
T_MOVE_ANALOG = 15,//Both at byte 14 (last reading) and byte 15 (current reading) T_ANALOG = 15, // Both at byte 14 (last reading) and byte 15 (current reading)
}; };
enum AnalogHat enum AnalogHat
{ {
@ -316,8 +328,7 @@ enum Rumble
class PS3BT : public USBDeviceConfig, public UsbConfigXtracter class PS3BT : public USBDeviceConfig, public UsbConfigXtracter
{ {
public: public:
PS3BT(USB *pUsb, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0); PS3BT(USB *pUsb, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0);
PS3BT(USB *pUsb);
// USBDeviceConfig implementation // USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
@ -338,10 +349,11 @@ public:
bool getButton(Button b); bool getButton(Button b);
uint8_t getAnalogButton(AnalogButton a); uint8_t getAnalogButton(AnalogButton a);
uint8_t getAnalogHat(AnalogHat a); uint8_t getAnalogHat(AnalogHat a);
int32_t getSensor(Sensor a); int16_t getSensor(Sensor a);
double getAngle(Angle a); double getAngle(Angle a);
bool getStatus(Status c); bool getStatus(Status c);
String getStatusString(); String getStatusString();
String getTemperature();
void disconnect(); // use this void to disconnect any of the controllers void disconnect(); // use this void to disconnect any of the controllers
/* HID Commands */ /* HID Commands */
@ -351,17 +363,18 @@ public:
void setRumbleOn(Rumble mode); void setRumbleOn(Rumble mode);
void setLedOff(LED a); void setLedOff(LED a);
void setLedOn(LED a); void setLedOn(LED a);
void setLedToggle(LED a);
/* Commands for Motion controller only */ /* Commands for Motion controller only */
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);//Use this to set the Color using RGB values void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);//Use this to set the Color using RGB values
void moveSetBulb(Colors color);//Use this to set the Color using the predefined colors in "enum Colors" void moveSetBulb(Colors color);//Use this to set the Color using the predefined colors in "enum Colors"
void moveSetRumble(uint8_t rumble); void moveSetRumble(uint8_t rumble);
bool PS3BTConnected;// Variable used to indicate if the normal playstation controller is successfully connected bool PS3Connected;// Variable used to indicate if the normal playstation controller is successfully connected
bool PS3MoveBTConnected;// Variable used to indicate if the move controller is successfully connected bool PS3MoveConnected;// Variable used to indicate if the move controller is successfully connected
bool PS3NavigationBTConnected;// Variable used to indicate if the navigation controller is successfully connected bool PS3NavigationConnected;// Variable used to indicate if the navigation controller is successfully connected
bool buttonChanged;//Indicate if a button has been changed bool buttonChanged;//Indicate if a button has been changed
bool buttonPressed;//Indicate if a button has been pressed bool buttonPressed;//Indicate if a button has been pressed
bool buttonReleased;//Indicate if a button has been pressed bool buttonReleased;//Indicate if a button has been released
protected: protected:
/* mandatory members */ /* mandatory members */
@ -389,6 +402,7 @@ private:
int16_t hci_handle; int16_t hci_handle;
uint8_t disc_bdaddr[6]; // the bluetooth address is always 6 bytes uint8_t disc_bdaddr[6]; // the bluetooth address is always 6 bytes
uint8_t remote_name[30]; // first 30 chars of remote name uint8_t remote_name[30]; // first 30 chars of remote name
uint8_t hci_version;
/* variables used by high level HCI task */ /* variables used by high level HCI task */
uint8_t hci_state; //current state of bluetooth hci connection uint8_t hci_state; //current state of bluetooth hci connection
@ -405,11 +419,9 @@ private:
uint32_t ButtonState; uint32_t ButtonState;
uint32_t OldButtonState; uint32_t OldButtonState;
uint32_t timerHID;// timer used see if there has to be a delay before a new HID command uint32_t timerHID;// timer used see if there has to be a delay before a new HID command
uint32_t dtimeHID;// delta time since last HID command
uint32_t timerBulbRumble;// used to continuously set PS3 Move controller Bulb and rumble values uint32_t timerBulbRumble;// used to continuously set PS3 Move controller Bulb and rumble values
uint32_t dtimeBulbRumble;// used to know how longs since last since the Bulb and rumble values was written
uint8_t my_bdaddr[6]; //Change to your dongles Bluetooth address in PS3BT.cpp uint8_t my_bdaddr[6]; // Change to your dongles Bluetooth address in the constructor
uint8_t hcibuf[BULK_MAXPKTSIZE];//General purpose buffer for hci data uint8_t hcibuf[BULK_MAXPKTSIZE];//General purpose buffer for hci data
uint8_t l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in data uint8_t l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in data
uint8_t l2capoutbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap out data uint8_t l2capoutbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap out data
@ -437,6 +449,7 @@ private:
void hci_write_scan_enable(); void hci_write_scan_enable();
void hci_write_scan_disable(); void hci_write_scan_disable();
void hci_read_bdaddr(); void hci_read_bdaddr();
void hci_read_local_version_information();
void hci_accept_connection(); void hci_accept_connection();
void hci_remote_name(); void hci_remote_name();
void hci_disconnect(); void hci_disconnect();

605
PS3USB.cpp Normal file
View file

@ -0,0 +1,605 @@
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
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
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#include "PS3USB.h"
#define DEBUG // Uncomment to print data for debugging
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
prog_char PS3_REPORT_BUFFER[] PROGMEM = {
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
};
prog_char MOVE_REPORT_BUFFER[] PROGMEM = {
0x02, 0x00, // Always 0x02, 0x00,
0x00, 0x00, 0x00, // r, g, b,
0x00, // Always 0x00,
0x00 // Rumble
};
PS3USB::PS3USB(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bPollEnable(false) // don't start polling before dongle is connected
{
for(uint8_t i=0; i<PS3_MAX_ENDPOINTS; i++)
{
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
my_bdaddr[4] = btadr4;
my_bdaddr[3] = btadr3;
my_bdaddr[2] = btadr2;
my_bdaddr[1] = btadr1;
my_bdaddr[0] = btadr0;
}
uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed)
{
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint16_t PID;
uint16_t VID;
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
Notify(PSTR("\r\nPS3USB Init"));
#endif
// check if address has already been assigned to an instance
if (bAddress)
{
#ifdef DEBUG
Notify(PSTR("\r\nAddress in use"));
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p)
{
#ifdef DEBUG
Notify(PSTR("\r\nAddress not found"));
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo)
{
#ifdef DEBUG
Notify(PSTR("\r\nepinfo is null"));
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
if (rcode)
{
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
Notify(PSTR("\r\nsetAddr: "));
#endif
PrintHex<uint8_t>(rcode);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "));
PrintHex<uint8_t>(bAddress);
#endif
p->lowspeed = false;
//get pointer to assigned address record
p = addrPool.GetUsbDevicePtr(bAddress);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
// Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode)
goto FailSetDevTblEntry;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
/* The application will work in reduced host mode, so we can save program and data
memory space. After verifying the PID and VID we will use known values for the
configuration values for device, interface, endpoints and HID for the PS3 Controllers */
/* Initialize data structures for endpoints of device */
epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ PS3_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ PS3_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ PS3_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ PS3_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
epInfo[ PS3_INPUT_PIPE ].epAddr = 0x01; // PS3 report endpoint
epInfo[ PS3_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ PS3_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ PS3_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if( rcode )
goto FailSetDevTblEntry;
delay(200);//Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
if( rcode )
goto FailSetConf;
if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
{
if(PID == PS3_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nDualshock 3 Controller Connected"));
#endif
PS3Connected = true;
} else { // must be a navigation controller
#ifdef DEBUG
Notify(PSTR("\r\nNavigation Controller Connected"));
#endif
PS3NavigationConnected = true;
}
/* Set internal bluetooth address and request for data */
setBdaddr(my_bdaddr);
enable_sixaxis();
setLedOn(LED1);
// Needed for PS3 Dualshock and Navigation commands to work
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]);
for (uint8_t i = 6; i < 10; i++)
readBuf[i] = 0x7F; // Set the analog joystick values to center position
}
else // must be a Motion controller
{
#ifdef DEBUG
Notify(PSTR("\r\nMotion Controller Connected"));
#endif
PS3MoveConnected = true;
setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
moveSetBulb(Red);
// Needed for Move commands to work
for (uint8_t i = 0; i < MOVE_REPORT_BUFFER_SIZE; i++)
writeBuf[i] = pgm_read_byte(&MOVE_REPORT_BUFFER[i]);
}
}
else
goto FailUnknownDevice;
bPollEnable = true;
Notify(PSTR("\r\n"));
timer = millis();
return 0; // successful configuration
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG
Notify(PSTR("\r\ngetDevDescr:"));
#endif
goto Fail;
FailSetDevTblEntry:
#ifdef DEBUG
Notify(PSTR("\r\nsetDevTblEn:"));
#endif
goto Fail;
FailSetConf:
#ifdef DEBUG
Notify(PSTR("\r\nsetConf:"));
#endif
goto Fail;
FailUnknownDevice:
#ifdef DEBUG
Notify(PSTR("\r\nUnknown Device Connected - VID: "));
PrintHex<uint16_t>(VID);
Notify(PSTR(" PID: "));
PrintHex<uint16_t>(PID);
#endif
goto Fail;
Fail:
#ifdef DEBUG
Notify(PSTR("\r\nPS3 Init Failed, error code: "));
Serial.print(rcode);
#endif
Release();
return rcode;
}
/* Performs a cleanup after failed Init() attempt */
uint8_t PS3USB::Release()
{
PS3Connected = false;
PS3MoveConnected = false;
PS3NavigationConnected = false;
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bPollEnable = false;
return 0;
}
uint8_t PS3USB::Poll()
{
if (!bPollEnable)
return 0;
if(PS3Connected || PS3NavigationConnected) {
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
pUsb->inTransfer(bAddress, epInfo[ PS3_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
if(millis() - timer > 100) { // Loop 100ms before processing data
readReport();
#ifdef PRINTREPORT
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
#endif
}
}
else if(PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB
if (millis() - timer > 4000) // Send at least every 4th second
{
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on
timer = millis();
}
}
return 0;
}
void PS3USB::readReport()
{
if (readBuf == NULL)
return;
ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16));
//Notify(PSTR("\r\nButtonState");
//PrintHex<uint32_t>(ButtonState);
if(ButtonState != OldButtonState)
{
buttonChanged = true;
if(ButtonState != 0x00) {
buttonPressed = true;
buttonReleased = false;
} else {
buttonPressed = false;
buttonReleased = true;
}
}
else
{
buttonChanged = false;
buttonPressed = false;
buttonReleased = false;
}
OldButtonState = ButtonState;
}
void PS3USB::printReport() //Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
{
if (readBuf == NULL)
return;
for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE;i++)
{
PrintHex<uint8_t>(readBuf[i]);
Serial.print(" ");
}
Serial.println("");
}
bool PS3USB::getButton(Button b)
{
if (readBuf == NULL)
return false;
if ((readBuf[(uint16_t)b >> 8] & ((uint8_t)b & 0xff)) > 0)
return true;
else
return false;
}
uint8_t PS3USB::getAnalogButton(AnalogButton a)
{
if (readBuf == NULL)
return 0;
return (uint8_t)(readBuf[(uint16_t)a]);
}
uint8_t PS3USB::getAnalogHat(AnalogHat a)
{
if (readBuf == NULL)
return 0;
return (uint8_t)(readBuf[(uint16_t)a]);
}
uint16_t PS3USB::getSensor(Sensor a)
{
if (readBuf == NULL)
return 0;
return ((readBuf[(uint16_t)a] << 8) | readBuf[(uint16_t)a + 1]);
}
double PS3USB::getAngle(Angle a) {
if(PS3Connected) {
double accXval;
double accYval;
double accZval;
// Data for the Kionix KXPC4 used in the DualShock 3
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);
// Convert to 360 degrees resolution
// atan2 outputs the value of -π to π (radians)
// We are then converting it to 0 to 2π and then to degrees
if (a == Pitch) {
double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG;
return angle;
} else {
double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG;
return angle;
}
} else
return 0;
}
bool PS3USB::getStatus(Status c)
{
if (readBuf == NULL)
return false;
if (readBuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff))
return true;
return false;
}
String PS3USB::getStatusString()
{
if (PS3Connected || PS3NavigationConnected)
{
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;
}
}
/* Playstation Sixaxis Dualshock and Navigation Controller commands */
void PS3USB::PS3_Command(uint8_t* data, uint16_t nbytes)
{
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x01), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x01, 0x02, 0x00, nbytes, nbytes, data, NULL);
}
void PS3USB::setAllOff()
{
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
writeBuf[i] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // Reset buffer
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setRumbleOff()
{
writeBuf[1] = 0x00;
writeBuf[2] = 0x00;//low mode off
writeBuf[3] = 0x00;
writeBuf[4] = 0x00;//high mode off
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setRumbleOn(Rumble mode)
{
/* 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)
{
writeBuf[1] = 0xfe;
writeBuf[3] = 0xfe;
if (mode == RumbleHigh)
{
writeBuf[2] = 0;//low mode off
writeBuf[4] = 0xff;//high mode on
}
else
{
writeBuf[2] = 0xff;//low mode on
writeBuf[4] = 0;//high mode off
}
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
}
void PS3USB::setLedOff(LED a)
{
writeBuf[9] &= ~((uint8_t)(((uint16_t)a & 0x0f) << 1));
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedOn(LED a)
{
writeBuf[9] |= (uint8_t)(((uint16_t)a & 0x0f) << 1);
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setLedToggle(LED a)
{
writeBuf[9] ^= (uint8_t)(((uint16_t)a & 0x0f) << 1);
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
}
void PS3USB::setBdaddr(uint8_t* BDADDR)
{
/* Set the internal bluetooth address */
uint8_t buf[8];
buf[0] = 0x01;
buf[1] = 0x00;
for (uint8_t i = 0; i < 6; i++)
buf[i+2] = BDADDR[5 - i];//Copy into buffer, has to be written reversed
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
#ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: "));
for(int8_t i = 5; i > 0; i--)
{
PrintHex<uint8_t>(my_bdaddr[i]);
Serial.print(":");
}
PrintHex<uint8_t>(my_bdaddr[0]);
#endif
return;
}
void PS3USB::enable_sixaxis()//Command used to enable the Dualshock 3 and Navigation controller to send data via USB
{
uint8_t cmd_buf[4];
cmd_buf[0] = 0x42;// Special PS3 Controller enable commands
cmd_buf[1] = 0x0c;
cmd_buf[2] = 0x00;
cmd_buf[3] = 0x00;
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF4), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF4, 0x03, 0x00, 4, 4, cmd_buf, NULL);
}
/* Playstation Move Controller commands */
void PS3USB::Move_Command(uint8_t* data, uint16_t nbytes)
{
pUsb->outTransfer(bAddress, epInfo[ PS3_OUTPUT_PIPE ].epAddr, nbytes, data);
}
void PS3USB::moveSetBulb(uint8_t r, uint8_t g, uint8_t b)//Use this to set the Color using RGB values
{
// set the Bulb's values into the write buffer
writeBuf[2] = r;
writeBuf[3] = g;
writeBuf[4] = b;
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
}
void PS3USB::moveSetBulb(Colors color)//Use this to set the Color using the predefined colors in "enums.h"
{
moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color));
}
void PS3USB::moveSetRumble(uint8_t rumble)
{
#ifdef DEBUG
if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"));
#endif
//set the rumble value into the write buffer
writeBuf[6] = rumble;
Move_Command(writeBuf, MOVE_REPORT_BUFFER_SIZE);
}
void PS3USB::setMoveBdaddr(uint8_t* BDADDR)
{
/* Set the internal bluetooth address */
uint8_t buf[11];
buf[0] = 0x05;
buf[7] = 0x10;
buf[8] = 0x01;
buf[9] = 0x02;
buf[10] = 0x12;
for (uint8_t i = 0; i < 6; i++)
buf[i + 1] = BDADDR[i];
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL);
#ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: "));
for(int8_t i = 5; i > 0; i--)
{
PrintHex<uint8_t>(my_bdaddr[i]);
Serial.print(":");
}
PrintHex<uint8_t>(my_bdaddr[0]);
#endif
return;
}

241
PS3USB.h Normal file
View file

@ -0,0 +1,241 @@
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
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
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#ifndef _ps3usb_h_
#define _ps3usb_h_
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Usb.h"
/* PS3 data taken from descriptors */
#define EP_MAXPKTSIZE 64 // max size for data via USB
/* Endpoint types */
#define EP_INTERRUPT 0x03
/* Names we give to the 3 ps3 pipes - this is only used for setting the bluetooth address into the ps3 controllers */
#define PS3_CONTROL_PIPE 0
#define PS3_OUTPUT_PIPE 1
#define PS3_INPUT_PIPE 2
//PID and VID of the different devices
#define PS3_VID 0x054C // Sony Corporation
#define PS3_PID 0x0268 // PS3 Controller DualShock 3
#define PS3NAVIGATION_PID 0x042F // Navigation controller
#define PS3MOVE_PID 0x03D5 // Motion controller
#define PS3_REPORT_BUFFER_SIZE 48 // Size of the output report buffer for the Dualshock and Navigation controllers
#define MOVE_REPORT_BUFFER_SIZE 7 // Size of the output report buffer for the Move Controller
// used in control endpoint header for HID Commands
#define bmREQ_HID_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQUEST_SET_REPORT 0x09
#define PS3_MAX_ENDPOINTS 3
enum LED
{
LED1 = 0x01,
LED2 = 0x02,
LED3 = 0x04,
LED4 = 0x08,
LED5 = 0x09,
LED6 = 0x0A,
LED7 = 0x0C,
LED8 = 0x0D,
LED9 = 0x0E,
LED10 = 0x0F,
};
enum Colors
{
// Used to set the colors of the move controller
Red = 0xFF0000, // r = 255, g = 0, b = 0
Green = 0xFF00, // r = 0, g = 255, b = 0
Blue = 0xFF, // r = 0, g = 0, b = 255
Yellow = 0xFFEB04, // r = 255, g = 235, b = 4
Lightblue = 0xFFFF, // r = 0, g = 255, b = 255
Purble = 0xFF00FF, // r = 255, g = 0, b = 255
White = 0xFFFFFF, // r = 255, g = 255, b = 255
Off = 0x00, // r = 0, g = 0, b = 0
};
enum Button
{
// byte location | bit location
// Sixaxis Dualshcock 3 & Navigation controller
SELECT = (2 << 8) | 0x01,
L3 = (2 << 8) | 0x02,
R3 = (2 << 8) | 0x04,
START = (2 << 8) | 0x08,
UP = (2 << 8) | 0x10,
RIGHT = (2 << 8) | 0x20,
DOWN = (2 << 8) | 0x40,
LEFT = (2 << 8) | 0x80,
L2 = (3 << 8) | 0x01,
R2 = (3 << 8) | 0x02,
L1 = (3 << 8) | 0x04,
R1 = (3 << 8) | 0x08,
TRIANGLE = (3 << 8) | 0x10,
CIRCLE = (3 << 8) | 0x20,
CROSS = (3 << 8) | 0x40,
SQUARE = (3 << 8) | 0x80,
PS = (4 << 8) | 0x01,
};
enum AnalogButton
{
// Sixaxis Dualshcock 3 & Navigation controller
UP_ANALOG = 14,
RIGHT_ANALOG = 15,
DOWN_ANALOG = 16,
LEFT_ANALOG = 17,
L2_ANALOG = 18,
R2_ANALOG = 19,
L1_ANALOG = 20,
R1_ANALOG = 21,
TRIANGLE_ANALOG = 22,
CIRCLE_ANALOG = 23,
CROSS_ANALOG = 24,
SQUARE_ANALOG = 25,
};
enum AnalogHat
{
LeftHatX = 6,
LeftHatY = 7,
RightHatX = 8,
RightHatY = 9,
};
enum Sensor
{
// Sensors inside the Sixaxis Dualshock 3 controller
aX = 41,
aY = 43,
aZ = 45,
gZ = 47,
};
enum Angle
{
Pitch = 0x01,
Roll = 0x02,
};
enum Status
{
// byte location | bit location
Plugged = (29 << 8) | 0x02,
Unplugged = (29 << 8) | 0x03,
Charging = (30 << 8) | 0xEE,
NotCharging = (30 << 8) | 0xF1,
Shutdown = (30 << 8) | 0x01,
Dying = (30 << 8) | 0x02,
Low = (30 << 8) | 0x03,
High = (30 << 8) | 0x04,
Full = (30 << 8) | 0x05,
CableRumble = (31 << 8) | 0x10, // Opperating by USB and rumble is turned on
Cable = (31 << 8) | 0x12, // Opperating by USB and rumble is turned off
BluetoothRumble = (31 << 8) | 0x14, // Opperating by bluetooth and rumble is turned on
Bluetooth = (31 << 8) | 0x16, // Opperating by bluetooth and rumble is turned off
};
enum Rumble
{
RumbleHigh = 0x10,
RumbleLow = 0x20,
};
class PS3USB : public USBDeviceConfig
{
public:
PS3USB(USB *pUsb, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0);
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return bPollEnable; };
void setBdaddr(uint8_t* BDADDR);
void setMoveBdaddr(uint8_t* BDADDR);
/* PS3 Controller Commands */
bool getButton(Button b);
uint8_t getAnalogButton(AnalogButton a);
uint8_t getAnalogHat(AnalogHat a);
uint16_t getSensor(Sensor a);
double getAngle(Angle a);
bool getStatus(Status c);
String getStatusString();
/* Commands for Dualshock 3 and Navigation controller */
void setAllOff();
void setRumbleOff();
void setRumbleOn(Rumble mode);
void setLedOff(LED a);
void setLedOn(LED a);
void setLedToggle(LED a);
/* Commands for Motion controller only */
void moveSetBulb(uint8_t r, uint8_t g, uint8_t b);//Use this to set the Color using RGB values
void moveSetBulb(Colors color);//Use this to set the Color using the predefined colors in "enum Colors"
void moveSetRumble(uint8_t rumble);
bool PS3Connected;// Variable used to indicate if the normal playstation controller is successfully connected
bool PS3MoveConnected;// Variable used to indicate if the move controller is successfully connected
bool PS3NavigationConnected;// Variable used to indicate if the navigation controller is successfully connected */
bool buttonChanged;//Indicate if a button has been changed
bool buttonPressed;//Indicate if a button has been pressed
bool buttonReleased;//Indicate if a button has been released
protected:
/* mandatory members */
USB *pUsb;
uint8_t bAddress; // device address
EpInfo epInfo[PS3_MAX_ENDPOINTS]; //endpoint info structure
private:
bool bPollEnable;
uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values
uint32_t ButtonState;
uint32_t OldButtonState;
uint8_t my_bdaddr[6]; // Change to your dongles Bluetooth address in the constructor
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
void readReport(); // read incoming data
void printReport(); // print incoming date - Uncomment for debugging
/* Private commands */
void PS3_Command(uint8_t* data, uint16_t nbytes);
void enable_sixaxis();//Command used to enable the Dualshock 3 and Navigation controller to send data via USB
void Move_Command(uint8_t* data, uint16_t nbytes);
};
#endif

355
XBOXUSB.cpp Normal file
View file

@ -0,0 +1,355 @@
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
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
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#include "XBOXUSB.h"
#define DEBUG // Uncomment to print data for debugging
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
XBOXUSB::XBOXUSB(USB *p):
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bPollEnable(false) { // don't start polling before dongle is connected
for(uint8_t i=0; i<XBOX_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
}
uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint16_t PID;
uint16_t VID;
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
Notify(PSTR("\r\nXBOXUSB Init"));
#endif
// check if address has already been assigned to an instance
if (bAddress)
{
#ifdef DEBUG
Notify(PSTR("\r\nAddress in use"));
#endif
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
}
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p)
{
#ifdef DEBUG
Notify(PSTR("\r\nAddress not found"));
#endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if (!p->epinfo)
{
#ifdef DEBUG
Notify(PSTR("\r\nepinfo is null"));
#endif
return USB_ERROR_EPINFO_IS_NULL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p->epinfo = epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p->epinfo = oldep_ptr;
if(rcode)
goto FailGetDevDescr;
// Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
// Extract Max Packet Size from device descriptor
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
// Assign new address to the device
rcode = pUsb->setAddr( 0, 0, bAddress );
if (rcode)
{
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
#ifdef DEBUG
Notify(PSTR("\r\nsetAddr: "));
#endif
PrintHex<uint8_t>(rcode);
return rcode;
}
#ifdef EXTRADEBUG
Notify(PSTR("\r\nAddr: "));
PrintHex<uint8_t>(bAddress);
#endif
p->lowspeed = false;
//get pointer to assigned address record
p = addrPool.GetUsbDevicePtr(bAddress);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
// Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode)
goto FailSetDevTblEntry;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if(VID == XBOX_VID) { // We just check if it's a xbox controller using the Vendor ID
if(PID == XBOX_WIRELESS_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"));
#endif
return 0;
}
else if(PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
#ifdef DEBUG
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"));
#endif
return 0;
}
/* The application will work in reduced host mode, so we can save program and data
memory space. After verifying the VID we will use known values for the
configuration values for device, interface, endpoints and HID for the XBOX360 Controllers */
/* Initialize data structures for endpoints of device */
epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 report endpoint
epInfo[ XBOX_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint
epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if( rcode )
goto FailSetDevTblEntry;
delay(200);//Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
if( rcode )
goto FailSetConf;
#ifdef DEBUG
Notify(PSTR("\r\nXbox 360 Controller Connected"));
#endif
setLedMode(ROTATING);
Xbox360Connected = true;
}
else
goto FailUnknownDevice;
bPollEnable = true;
Notify(PSTR("\r\n"));
return 0; // successful configuration
/* diagnostic messages */
FailGetDevDescr:
#ifdef DEBUG
Notify(PSTR("\r\ngetDevDescr:"));
#endif
goto Fail;
FailSetDevTblEntry:
#ifdef DEBUG
Notify(PSTR("\r\nsetDevTblEn:"));
#endif
goto Fail;
FailSetConf:
#ifdef DEBUG
Notify(PSTR("\r\nsetConf:"));
#endif
goto Fail;
FailUnknownDevice:
#ifdef DEBUG
Notify(PSTR("\r\nUnknown Device Connected - VID: "));
PrintHex<uint16_t>(VID);
Notify(PSTR(" PID: "));
PrintHex<uint16_t>(PID);
#endif
goto Fail;
Fail:
#ifdef DEBUG
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "));
Serial.print(rcode);
#endif
Release();
return rcode;
}
/* Performs a cleanup after failed Init() attempt */
uint8_t XBOXUSB::Release() {
Xbox360Connected = false;
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bPollEnable = false;
return 0;
}
uint8_t XBOXUSB::Poll() {
if (!bPollEnable)
return 0;
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
readReport();
#ifdef PRINTREPORT
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
#endif
return 0;
}
void XBOXUSB::readReport() {
if (readBuf == NULL)
return;
if(readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports
return;
}
ButtonState = (uint32_t)(readBuf[2] | ((uint16_t)readBuf[3] << 8) | ((uint32_t)readBuf[4] << 16) | ((uint32_t)readBuf[5] << 24));
//Notify(PSTR("\r\nButtonState");
//PrintHex<uint32_t>(ButtonState);
if(ButtonState != OldButtonState) {
buttonChanged = true;
if(ButtonState != 0x00) {
buttonPressed = true;
buttonReleased = false;
} else {
buttonPressed = false;
buttonReleased = true;
}
} else {
buttonChanged = false;
buttonPressed = false;
buttonReleased = false;
}
OldButtonState = ButtonState;
}
void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
if (readBuf == NULL)
return;
for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE;i++) {
PrintHex<uint8_t>(readBuf[i]);
Serial.print(" ");
}
Serial.println("");
}
uint8_t XBOXUSB::getButton(Button b) {
if (readBuf == NULL)
return false;
if(b == L2 || b == R2) { // These are analog buttons
return (uint8_t)(readBuf[(uint8_t)b]);
}
else {
if ((readBuf[(uint16_t)b >> 8] & ((uint8_t)b & 0xff)) > 0)
return 1;
else
return 0;
}
}
int16_t XBOXUSB::getAnalogHat(AnalogHat a) {
if (readBuf == NULL)
return 0;
return (int16_t)(readBuf[(uint8_t)a+1] << 8 | readBuf[(uint8_t)a]);
}
/* Playstation Sixaxis Dualshock and Navigation Controller commands */
void XBOXUSB::XboxCommand(uint8_t* data, uint16_t nbytes) {
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
}
void XBOXUSB::setLedOn(LED l) {
if(l == ALL) // All LEDs can't be on a the same time
return;
writeBuf[0] = 0x01;
writeBuf[1] = 0x03;
writeBuf[2] = (uint8_t)l;
writeBuf[2] += 4;
XboxCommand(writeBuf, 3);
}
void XBOXUSB::setLedOff() {
writeBuf[0] = 0x01;
writeBuf[1] = 0x03;
writeBuf[2] = 0x00;
XboxCommand(writeBuf, 3);
}
void XBOXUSB::setLedBlink(LED l) {
writeBuf[0] = 0x01;
writeBuf[1] = 0x03;
writeBuf[2] = (uint8_t)l;
XboxCommand(writeBuf, 3);
}
void XBOXUSB::setLedMode(LEDMode lm) { // This function is used to do some speciel LED stuff the controller supports
writeBuf[0] = 0x01;
writeBuf[1] = 0x03;
writeBuf[2] = (uint8_t)lm;
XboxCommand(writeBuf, 3);
}
void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) {
writeBuf[0] = 0x00;
writeBuf[1] = 0x08;
writeBuf[2] = 0x00;
writeBuf[3] = lValue; // big weight
writeBuf[4] = rValue; // small weight
writeBuf[5] = 0x00;
writeBuf[6] = 0x00;
writeBuf[7] = 0x00;
XboxCommand(writeBuf, 8);
}

152
XBOXUSB.h Normal file
View file

@ -0,0 +1,152 @@
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
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
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#ifndef _xboxusb_h_
#define _xboxusb_h_
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Usb.h"
/* Data Xbox 360 taken from descriptors */
#define EP_MAXPKTSIZE 32 // max size for data via USB
/* Endpoint types */
#define EP_INTERRUPT 0x03
/* Names we give to the 3 Xbox360 pipes */
#define XBOX_CONTROL_PIPE 0
#define XBOX_INPUT_PIPE 1
#define XBOX_OUTPUT_PIPE 2
//PID and VID of the different devices
#define XBOX_VID 0x045E // Microsoft Corporation
#define XBOX_WIRELESS_PID 0x028F // Wireless controller only support charging
#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
#define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer
// used in control endpoint header for HID Commands
#define bmREQ_HID_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQUEST_SET_REPORT 0x09
#define XBOX_MAX_ENDPOINTS 3
enum LED {
ALL = 0x01, // Used to blink all LEDs
LED1 = 0x02,
LED2 = 0x03,
LED3 = 0x04,
LED4 = 0x05,
};
enum LEDMode {
ROTATING = 0x0A,
FASTBLINK = 0x0B,
SLOWBLINK = 0x0C,
ALTERNATING = 0x0D,
};
enum Button {
// byte location | bit location
UP = (2 << 8) | 0x01,
DOWN = (2 << 8) | 0x02,
LEFT = (2 << 8) | 0x04,
RIGHT = (2 << 8) | 0x08,
START = (2 << 8) | 0x10,
BACK = (2 << 8) | 0x20,
L3 = (2 << 8) | 0x40,
R3 = (2 << 8) | 0x80,
L1 = (3 << 8) | 0x01,
R1 = (3 << 8) | 0x02,
XBOX = (3 << 8) | 0x04,
A = (3 << 8) | 0x10,
B = (3 << 8) | 0x20,
X = (3 << 8) | 0x40,
Y = (3 << 8) | 0x80,
// These buttons are analog
L2 = 4,
R2 = 5,
};
enum AnalogHat
{
LeftHatX = 6,
LeftHatY = 8,
RightHatX = 10,
RightHatY = 12,
};
class XBOXUSB : public USBDeviceConfig
{
public:
XBOXUSB(USB *pUsb);
// USBDeviceConfig implementation
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
virtual uint8_t Release();
virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return bPollEnable; };
/* XBOX Controller Readings */
uint8_t getButton(Button b);
int16_t getAnalogHat(AnalogHat a);
/* Commands for Dualshock 3 and Navigation controller */
void setAllOff() { setRumbleOn(0,0); setLedOff(); };
void setRumbleOff() { setRumbleOn(0,0); };
void setRumbleOn(uint8_t lValue, uint8_t rValue);
void setLedOff();
void setLedOn(LED l);
void setLedBlink(LED l);
void setLedMode(LEDMode lm);
bool Xbox360Connected;// Variable used to indicate if the XBOX 360 controller is successfully connected
bool buttonChanged;//Indicate if a button has been changed
bool buttonPressed;//Indicate if a button has been pressed
bool buttonReleased;//Indicate if a button has been released
protected:
/* mandatory members */
USB *pUsb;
uint8_t bAddress; // device address
EpInfo epInfo[XBOX_MAX_ENDPOINTS]; //endpoint info structure
private:
bool bPollEnable;
uint32_t ButtonState;
uint32_t OldButtonState;
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
void readReport(); // read incoming data
void printReport(); // print incoming date - Uncomment for debugging
/* Private commands */
void XboxCommand(uint8_t* data, uint16_t nbytes);
};
#endif

View file

@ -20,9 +20,13 @@ e-mail : support@circuitsathome.com
#ifndef _avrpins_h_ #ifndef _avrpins_h_
#define _avrpins_h_ #define _avrpins_h_
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
/* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */ /* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */
//#define BOARD_MEGA_ADK //#define BOARD_MEGA_ADK
#endif
/* Uncomment the following if you are using a Teensy 2.0 */
//#define BOARD_TEENSY
#include <avr/io.h> #include <avr/io.h>
@ -501,7 +505,47 @@ template<typename Tp_pin, typename Tc_bit>
#endif // "Classic" Arduino pin numbers #endif // "Classic" Arduino pin numbers
#if defined(__AVR_ATmega32U4__) #if !defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
// Arduino Leonardo pin numbers
#define P0 Pd2 // D0 - PD2
#define P1 Pd3 // D1 - PD3
#define P2 Pd1 // D2 - PD1
#define P3 Pd0 // D3 - PD0
#define P4 Pd4 // D4 - PD4
#define P5 Pc6 // D5 - PC6
#define P6 Pd7 // D6 - PD7
#define P7 Pe6 // D7 - PE6
#define P8 Pb4 // D8 - PB4
#define P9 Pb5 // D9 - PB5
#define P10 Pb6 // D10 - PB6
#define P11 Pb7 // D11 - PB7
#define P12 Pd6 // D12 - PD6
#define P13 Pc7 // D13 - PC7
#define P14 Pb3 // D14 - MISO - PB3
#define P15 Pb1 // D15 - SCK - PB1
#define P16 Pb2 // D16 - MOSI - PB2
#define P17 Pb0 // D17 - SS - PB0
#define P18 Pf7 // D18 - A0 - PF7
#define P19 Pf6 // D19 - A1 - PF6
#define P20 Pf5 // D20 - A2 - PF5
#define P21 Pf4 // D21 - A3 - PF4
#define P22 Pf1 // D22 - A4 - PF1
#define P23 Pf0 // D23 - A5 - PF0
#define P24 Pd4 // D24 / D4 - A6 - PD4
#define P25 Pd7 // D25 / D6 - A7 - PD7
#define P26 Pb4 // D26 / D8 - A8 - PB4
#define P27 Pb5 // D27 / D9 - A9 - PB5
#define P28 Pb6 // D28 / D10 - A10 - PB6
#define P29 Pd6 // D29 / D12 - A11 - PD6
#endif // Arduino Leonardo pin numbers
#if defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
// Teensy 2.0 pin numbers // Teensy 2.0 pin numbers
// http://www.pjrc.com/teensy/pinout.html // http://www.pjrc.com/teensy/pinout.html
#define P0 Pb0 #define P0 Pb0

View file

@ -0,0 +1,197 @@
/*
Example sketch for the PS3 Bluetooth library - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <PS3BT.h>
USB Usb;
/* You can create the instance of the class in two ways */
PS3BT PS3(&Usb); // This will just create the instance
//PS3BT PS3(&Usb,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch
boolean printTemperature;
boolean printAngle;
void setup()
{
Serial.begin(115200);
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while(1); //halt
}
Serial.print(F("\r\nPS3 Bluetooth Library Started"));
}
void loop()
{
Usb.Task();
if(PS3.PS3Connected || PS3.PS3NavigationConnected) {
if(PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117 || PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117 || PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117 || PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117) {
if(PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117) {
Serial.print(F("LeftHatX: "));
Serial.print(PS3.getAnalogHat(LeftHatX));
Serial.print("\t");
} if(PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117) {
Serial.print(F("LeftHatY: "));
Serial.print(PS3.getAnalogHat(LeftHatY));
Serial.print("\t");
} if(PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117) {
Serial.print(F("RightHatX: "));
Serial.print(PS3.getAnalogHat(RightHatX));
Serial.print("\t");
} if(PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117) {
Serial.print(F("RightHatY: "));
Serial.print(PS3.getAnalogHat(RightHatY));
}
Serial.println("");
}
//Analog button values can be read from almost all buttons
if(PS3.getAnalogButton(L2_ANALOG) > 0 || PS3.getAnalogButton(R2_ANALOG) > 0) {
if(PS3.getAnalogButton(L2_ANALOG) > 0) {
Serial.print(F("L2: "));
Serial.print(PS3.getAnalogButton(L2_ANALOG));
Serial.print("\t");
} if(PS3.getAnalogButton(R2_ANALOG) > 0) {
Serial.print(F("R2: "));
Serial.print(PS3.getAnalogButton(R2_ANALOG));
}
Serial.println("");
}
if(PS3.buttonPressed)
{
Serial.print(F("PS3 Controller"));
if(PS3.getButton(PS)) {
Serial.print(F(" - PS"));
PS3.disconnect();
} else {
if(PS3.getButton(TRIANGLE))
Serial.print(F(" - Traingle"));
if(PS3.getButton(CIRCLE))
Serial.print(F(" - Circle"));
if(PS3.getButton(CROSS))
Serial.print(F(" - Cross"));
if(PS3.getButton(SQUARE))
Serial.print(F(" - Square"));
if(PS3.getButton(UP)) {
Serial.print(F(" - Up"));
if(PS3.PS3Connected) {
PS3.setAllOff();
PS3.setLedOn(LED4);
}
} if(PS3.getButton(RIGHT)) {
Serial.print(F(" - Right"));
if(PS3.PS3Connected) {
PS3.setAllOff();
PS3.setLedOn(LED1);
}
} if(PS3.getButton(DOWN)) {
Serial.print(F(" - Down"));
if(PS3.PS3Connected) {
PS3.setAllOff();
PS3.setLedOn(LED2);
}
} if(PS3.getButton(LEFT)) {
Serial.print(F(" - Left"));
if(PS3.PS3Connected) {
PS3.setAllOff();
PS3.setLedOn(LED3);
}
}
if(PS3.getButton(L1))
Serial.print(F(" - L1"));
//if(PS3.getButton(L2))
//Serial.print(F(" - L2"));
if(PS3.getButton(L3))
Serial.print(F(" - L3"));
if(PS3.getButton(R1))
Serial.print(F(" - R1"));
//if(PS3.getButton(R2))
//Serial.print(F(" - R2"));
if(PS3.getButton(R3))
Serial.print(F(" - R3"));
if(PS3.getButton(SELECT)) {
Serial.print(F(" - Select - "));
Serial.print(PS3.getStatusString());
} if(PS3.getButton(START)) {
Serial.print(F(" - Start"));
printAngle = !printAngle;
while(PS3.getButton(START))
Usb.Task();
}
Serial.println("");
}
}
if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(PS3.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(PS3.getAngle(Roll));
}
}
else if(PS3.PS3MoveConnected)
{
if(PS3.getAnalogButton(T_ANALOG) > 0) {
Serial.print(F("T: "));
Serial.println(PS3.getAnalogButton(T_ANALOG));
} if(PS3.buttonPressed) {
Serial.print(F("PS3 Move Controller"));
if(PS3.getButton(PS)) {
Serial.print(F(" - PS"));
PS3.disconnect();
} else {
if(PS3.getButton(SELECT)) {
Serial.print(F(" - Select"));
printTemperature = !printTemperature;
while(PS3.getButton(SELECT))
Usb.Task();
} if(PS3.getButton(START)) {
Serial.print(F(" - Start"));
printAngle = !printAngle;
while(PS3.getButton(START))
Usb.Task();
} if(PS3.getButton(TRIANGLE)) {
Serial.print(F(" - Triangle"));
PS3.moveSetBulb(Red);
} if(PS3.getButton(CIRCLE)) {
Serial.print(F(" - Circle"));
PS3.moveSetBulb(Green);
} if(PS3.getButton(SQUARE)) {
Serial.print(F(" - Square"));
PS3.moveSetBulb(Blue);
} if(PS3.getButton(CROSS)) {
Serial.print(F(" - Cross"));
PS3.moveSetBulb(Yellow);
} if(PS3.getButton(MOVE)) {
PS3.moveSetBulb(Off);
Serial.print(F(" - Move"));
Serial.print(F(" - "));
Serial.print(PS3.getStatusString());
}
//if(PS3.getButton(T))
//Serial.print(F(" - T"));
Serial.println("");
}
}
if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(PS3.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(PS3.getAngle(Roll));
}
else if(printTemperature) {
Serial.print(F("Temperature: "));
Serial.println(PS3.getTemperature());
}
}
delay(1);
}

View file

@ -0,0 +1,188 @@
/*
Example sketch for the PS3 USB library - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <PS3USB.h>
USB Usb;
/* You can create the instance of the class in two ways */
PS3USB PS3(&Usb); // This will just create the instance
//PS3USB PS3(&Usb,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch
boolean printAngle;
uint8_t state = 0;
void setup() {
Serial.begin(115200);
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while(1); //halt
}
Serial.print(F("\r\nPS3 USB Library Started"));
}
void loop() {
Usb.Task();
if(PS3.PS3Connected || PS3.PS3NavigationConnected) {
if(PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117 || PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117 || PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117 || PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117) {
if(PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117) {
Serial.print(F("LeftHatX: "));
Serial.print(PS3.getAnalogHat(LeftHatX));
Serial.print("\t");
}
if(PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117) {
Serial.print(F("LeftHatY: "));
Serial.print(PS3.getAnalogHat(LeftHatY));
Serial.print("\t");
}
if(PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117) {
Serial.print(F("RightHatX: "));
Serial.print(PS3.getAnalogHat(RightHatX));
Serial.print("\t");
}
if(PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117) {
Serial.print(F("RightHatY: "));
Serial.print(PS3.getAnalogHat(RightHatY));
}
Serial.println("");
}
// Analog button values can be read from almost all buttons
if(PS3.getAnalogButton(L2_ANALOG) > 0 || PS3.getAnalogButton(R2_ANALOG) > 0) {
if(PS3.getAnalogButton(L2_ANALOG) > 0) {
Serial.print(F("L2: "));
Serial.print(PS3.getAnalogButton(L2_ANALOG));
Serial.print("\t");
}
if(PS3.getAnalogButton(R2_ANALOG) > 0) {
Serial.print(F("R2: "));
Serial.print(PS3.getAnalogButton(R2_ANALOG));
}
Serial.println("");
}
if(PS3.buttonPressed)
{
Serial.print(F("PS3 Controller"));
if(PS3.getButton(PS))
Serial.print(F(" - PS"));
if(PS3.getButton(TRIANGLE))
Serial.print(F(" - Traingle"));
if(PS3.getButton(CIRCLE))
Serial.print(F(" - Circle"));
if(PS3.getButton(CROSS))
Serial.print(F(" - Cross"));
if(PS3.getButton(SQUARE))
Serial.print(F(" - Square"));
if(PS3.getButton(UP)) {
Serial.print(F(" - Up"));
PS3.setAllOff();
PS3.setLedOn(LED4);
}
if(PS3.getButton(RIGHT)) {
Serial.print(F(" - Right"));
PS3.setAllOff();
PS3.setLedOn(LED1);
}
if(PS3.getButton(DOWN)) {
Serial.print(F(" - Down"));
PS3.setAllOff();
PS3.setLedOn(LED2);
}
if(PS3.getButton(LEFT)) {
Serial.print(F(" - Left"));
PS3.setAllOff();
PS3.setLedOn(LED3);
}
if(PS3.getButton(L1))
Serial.print(F(" - L1"));
//if(PS3.getButton(L2))
//Serial.print(F(" - L2"));
if(PS3.getButton(L3))
Serial.print(F(" - L3"));
if(PS3.getButton(R1))
Serial.print(F(" - R1"));
//if(PS3.getButton(R2))
//Serial.print(F(" - R2"));
if(PS3.getButton(R3))
Serial.print(F(" - R3"));
if(PS3.getButton(SELECT)) {
Serial.print(F(" - Select - "));
Serial.print(PS3.getStatusString());
}
if(PS3.getButton(START)) {
Serial.print(F(" - Start"));
printAngle = !printAngle;
while(PS3.getButton(START))
Usb.Task();
}
Serial.println("");
}
if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(PS3.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(PS3.getAngle(Roll));
}
}
else if(PS3.PS3MoveConnected) { // One can only set the color of the bulb, set the rumble, set and get the bluetooth address and calibrate the magnetometer via USB
switch(state) {
case 0:
PS3.moveSetRumble(0);
PS3.moveSetBulb(Off);
state = 1;
break;
case 1:
PS3.moveSetRumble(75);
PS3.moveSetBulb(Red);
state = 2;
break;
case 2:
PS3.moveSetRumble(125);
PS3.moveSetBulb(Green);
state = 3;
break;
case 3:
PS3.moveSetRumble(150);
PS3.moveSetBulb(Blue);
state = 4;
break;
case 4:
PS3.moveSetRumble(175);
PS3.moveSetBulb(Yellow);
state = 5;
break;
case 5:
PS3.moveSetRumble(200);
PS3.moveSetBulb(Lightblue);
state = 6;
break;
case 6:
PS3.moveSetRumble(225);
PS3.moveSetBulb(Purble);
state = 7;
break;
case 7:
PS3.moveSetRumble(250);
PS3.moveSetBulb(White);
state = 0;
break;
}
delay(1000);
}
}

View file

@ -1,201 +0,0 @@
/*
Example sketch for the PS3 Bluetooth library - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <PS3BT.h>
USB Usb;
/* You can create the instance of the class in two ways */
PS3BT BT(&Usb); // This will just create the instance
//PS3BT BT(&Usb,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch
boolean printTemperature;
boolean printAngle;
void setup()
{
Serial.begin(115200);
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while(1); //halt
}
Serial.print(F("\r\nPS3 Bluetooth Library Started"));
}
void loop()
{
Usb.Task();
if(BT.PS3BTConnected || BT.PS3NavigationBTConnected) {
if(BT.getAnalogHat(LeftHatX) > 137 || BT.getAnalogHat(LeftHatX) < 117 || BT.getAnalogHat(LeftHatY) > 137 || BT.getAnalogHat(LeftHatY) < 117 || BT.getAnalogHat(RightHatX) > 137 || BT.getAnalogHat(RightHatX) < 117 || BT.getAnalogHat(RightHatY) > 137 || BT.getAnalogHat(RightHatY) < 117) {
if(BT.getAnalogHat(LeftHatX) > 137 || BT.getAnalogHat(LeftHatX) < 117) {
Serial.print(F("LeftHatX: "));
Serial.print(BT.getAnalogHat(LeftHatX));
Serial.print("\t");
} if(BT.getAnalogHat(LeftHatY) > 137 || BT.getAnalogHat(LeftHatY) < 117) {
Serial.print(F("LeftHatY: "));
Serial.print(BT.getAnalogHat(LeftHatY));
Serial.print("\t");
} if(BT.getAnalogHat(RightHatX) > 137 || BT.getAnalogHat(RightHatX) < 117) {
Serial.print(F("RightHatX: "));
Serial.print(BT.getAnalogHat(RightHatX));
Serial.print("\t");
} if(BT.getAnalogHat(RightHatY) > 137 || BT.getAnalogHat(RightHatY) < 117) {
Serial.print(F("RightHatY: "));
Serial.print(BT.getAnalogHat(RightHatY));
}
Serial.println("");
}
//Analog button values can be read from almost all buttons
if(BT.getAnalogButton(L2_ANALOG) > 0 || BT.getAnalogButton(R2_ANALOG) > 0) {
if(BT.getAnalogButton(L2_ANALOG) > 0) {
Serial.print(F("L2: "));
Serial.print(BT.getAnalogButton(L2_ANALOG));
Serial.print("\t");
} if(BT.getAnalogButton(R2_ANALOG) > 0) {
Serial.print(F("R2: "));
Serial.print(BT.getAnalogButton(R2_ANALOG));
}
Serial.println("");
}
if(BT.buttonPressed)
{
Serial.print(F("PS3 Controller"));
if(BT.getButton(PS)) {
Serial.print(F(" - PS"));
BT.disconnect();
} else {
if(BT.getButton(TRIANGLE))
Serial.print(F(" - Traingle"));
if(BT.getButton(CIRCLE))
Serial.print(F(" - Circle"));
if(BT.getButton(CROSS))
Serial.print(F(" - Cross"));
if(BT.getButton(SQUARE))
Serial.print(F(" - Square"));
if(BT.getButton(UP)) {
Serial.print(F(" - Up"));
BT.setAllOff();
BT.setLedOn(LED4);
} if(BT.getButton(RIGHT)) {
Serial.print(F(" - Right"));
BT.setAllOff();
BT.setLedOn(LED1);
} if(BT.getButton(DOWN)) {
Serial.print(F(" - Down"));
BT.setAllOff();
BT.setLedOn(LED2);
} if(BT.getButton(LEFT)) {
Serial.print(F(" - Left"));
BT.setAllOff();
BT.setLedOn(LED3);
}
if(BT.getButton(L1))
Serial.print(F(" - L1"));
//if(BT.getButton(L2))
//Serial.print(F(" - L2"));
if(BT.getButton(L3))
Serial.print(F(" - L3"));
if(BT.getButton(R1))
Serial.print(F(" - R1"));
//if(BT.getButton(R2))
//Serial.print(F(" - R2"));
if(BT.getButton(R3))
Serial.print(F(" - R3"));
if(BT.getButton(SELECT)) {
Serial.print(F(" - Select - "));
Serial.print(BT.getStatusString());
} if(BT.getButton(START)) {
Serial.print(F(" - Start"));
printAngle = !printAngle;
while(BT.getButton(START))
Usb.Task();
}
Serial.println("");
}
}
if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(BT.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(BT.getAngle(Roll));
}
}
else if(BT.PS3MoveBTConnected)
{
if(BT.getAnalogButton(T_MOVE_ANALOG) > 0) {
Serial.print(F("T: "));
Serial.println(BT.getAnalogButton(T_MOVE_ANALOG));
} if(BT.buttonPressed) {
Serial.print(F("PS3 Move Controller"));
if(BT.getButton(PS_MOVE)) {
Serial.print(F(" - PS"));
BT.disconnect();
} else {
if(BT.getButton(SELECT_MOVE)) {
Serial.print(F(" - Select"));
printTemperature = !printTemperature;
while(BT.getButton(SELECT_MOVE))
Usb.Task();
} if(BT.getButton(START_MOVE)) {
Serial.print(F(" - Start"));
printAngle = !printAngle;
while(BT.getButton(START_MOVE))
Usb.Task();
} if(BT.getButton(TRIANGLE_MOVE)) {
Serial.print(F(" - Triangle"));
BT.moveSetBulb(Red);
} if(BT.getButton(CIRCLE_MOVE)) {
Serial.print(F(" - Circle"));
BT.moveSetBulb(Green);
} if(BT.getButton(SQUARE_MOVE)) {
Serial.print(F(" - Square"));
BT.moveSetBulb(Blue);
} if(BT.getButton(CROSS_MOVE)) {
Serial.print(F(" - Cross"));
BT.moveSetBulb(Yellow);
} if(BT.getButton(MOVE_MOVE)) {
BT.moveSetBulb(Off);
Serial.print(F(" - Move"));
Serial.print(F(" - "));
Serial.print(BT.getStatusString());
}
//if(BT.getButton(T))
//Serial.print(F(" - T"));
Serial.println("");
}
}
if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(BT.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(BT.getAngle(Roll));
}
else if(printTemperature) {
String templow;
String temphigh;
String input = String(BT.getSensor(tempMove));
if (input.length() > 3) {
temphigh = input.substring(0, 2);
templow = input.substring(2);
} else {
temphigh = input.substring(0, 1);
templow = input.substring(1);
}
Serial.print(F("Temperature: "));
Serial.print(temphigh);
Serial.print(F("."));
Serial.println(templow);
}
}
}

View file

@ -0,0 +1,109 @@
/*
Example sketch for the Xbox 360 USB library - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <XBOXUSB.h>
USB Usb;
XBOXUSB Xbox(&Usb);
void setup() {
Serial.begin(115200);
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while(1); //halt
}
Serial.print(F("\r\nXBOX USB Library Started"));
}
void loop() {
Usb.Task();
if(Xbox.Xbox360Connected) {
if(Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500 || Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500 || Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500 || Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) {
if(Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500) {
Serial.print(F("LeftHatX: "));
Serial.print(Xbox.getAnalogHat(LeftHatX));
Serial.print("\t");
}
if(Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500) {
Serial.print(F("LeftHatY: "));
Serial.print(Xbox.getAnalogHat(LeftHatY));
Serial.print("\t");
}
if(Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500) {
Serial.print(F("RightHatX: "));
Serial.print(Xbox.getAnalogHat(RightHatX));
Serial.print("\t");
}
if(Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) {
Serial.print(F("RightHatY: "));
Serial.print(Xbox.getAnalogHat(RightHatY));
}
Serial.println("");
}
if(Xbox.buttonPressed) {
Serial.print(F("Xbox 360 Controller"));
if(Xbox.getButton(UP)) {
Xbox.setLedOn(LED1);
Serial.print(F(" - UP"));
}
if(Xbox.getButton(DOWN)) {
Xbox.setLedOn(LED4);
Serial.print(F(" - DOWN"));
}
if(Xbox.getButton(LEFT)) {
Xbox.setLedOn(LED3);
Serial.print(F(" - LEFT"));
}
if(Xbox.getButton(RIGHT)) {
Xbox.setLedOn(LED2);
Serial.print(F(" - RIGHT"));
}
if(Xbox.getButton(START)) {
Xbox.setLedMode(ALTERNATING);
Serial.print(F(" - START"));
}
if(Xbox.getButton(BACK)) {
Xbox.setLedBlink(ALL);
Serial.print(F(" - BACK"));
}
if(Xbox.getButton(L3))
Serial.print(F(" - L3"));
if(Xbox.getButton(R3))
Serial.print(F(" - R3"));
if(Xbox.getButton(L1))
Serial.print(F(" - L1"));
if(Xbox.getButton(R1))
Serial.print(F(" - R1"));
if(Xbox.getButton(XBOX)) {
Xbox.setLedMode(ROTATING);
Serial.print(F(" - XBOX"));
}
if(Xbox.getButton(A))
Serial.print(F(" - A"));
if(Xbox.getButton(B))
Serial.print(F(" - B"));
if(Xbox.getButton(X))
Serial.print(F(" - X"));
if(Xbox.getButton(Y))
Serial.print(F(" - Y"));
if(Xbox.getButton(L2)) {
Serial.print(F(" - L2:"));
Serial.print(Xbox.getButton(L2));
}
if(Xbox.getButton(R2)) {
Serial.print(F(" - R2:"));
Serial.print(Xbox.getButton(R2));
}
Xbox.setRumbleOn(Xbox.getButton(L2),Xbox.getButton(R2));
Serial.println();
}
}
delay(1);
}

186
keywords.txt Normal file
View file

@ -0,0 +1,186 @@
####################################################
# Syntax Coloring Map For PS3 Bluetooth/USB Library
####################################################
####################################################
# Datatypes (KEYWORD1)
####################################################
PS3BT KEYWORD1
PS3USB KEYWORD1
####################################################
# Methods and Functions (KEYWORD2)
####################################################
setBdaddr KEYWORD2
setMoveBdaddr KEYWORD2
getButton KEYWORD2
getAnalogButton KEYWORD2
getAnalogHat KEYWORD2
getSensor KEYWORD2
getAngle KEYWORD2
getStatus KEYWORD2
getStatusString KEYWORD2
getTemperature KEYWORD2
disconnect KEYWORD2
setAllOff KEYWORD2
setRumbleOff KEYWORD2
setRumbleOn KEYWORD2
setLedOff KEYWORD2
setLedOn KEYWORD2
setLedToggle KEYWORD2
moveSetBulb KEYWORD2
moveSetRumble KEYWORD2
PS3Connected KEYWORD2
PS3MoveConnected KEYWORD2
PS3NavigationConnected KEYWORD2
buttonChanged KEYWORD2
buttonPressed KEYWORD2
buttonReleased KEYWORD2
isWatingForConnection KEYWORD2
####################################################
# Constants and enums (LITERAL1)
####################################################
LED1 LITERAL1
LED2 LITERAL1
LED3 LITERAL1
LED4 LITERAL1
LED5 LITERAL1
LED6 LITERAL1
LED7 LITERAL1
LED8 LITERAL1
LED9 LITERAL1
LED10 LITERAL1
Red LITERAL1
Green LITERAL1
Blue LITERAL1
Yellow LITERAL1
Lightblue LITERAL1
Purble LITERAL1
White LITERAL1
Off LITERAL1
SELECT LITERAL1
L3 LITERAL1
R3 LITERAL1
START LITERAL1
UP LITERAL1
RIGHT LITERAL1
DOWN LITERAL1
LEFT LITERAL1
L2 LITERAL1
R2 LITERAL1
L1 LITERAL1
R1 LITERAL1
TRIANGLE LITERAL1
CIRCLE LITERAL1
CROSS LITERAL1
SQUARE LITERAL1
PS LITERAL1
MOVE LITERAL1
T LITERAL1
UP_ANALOG LITERAL1
RIGHT_ANALOG LITERAL1
DOWN_ANALOG LITERAL1
LEFT_ANALOG LITERAL1
L2_ANALOG LITERAL1
R2_ANALOG LITERAL1
L1_ANALOG LITERAL1
R1_ANALOG LITERAL1
TRIANGLE_ANALOG LITERAL1
CIRCLE_ANALOG LITERAL1
CROSS_ANALOG LITERAL1
SQUARE_ANALOG LITERAL1
T_ANALOG LITERAL1
LeftHatX LITERAL1
LeftHatY LITERAL1
RightHatX LITERAL1
RightHatY LITERAL1
aX LITERAL1
aY LITERAL1
aZ LITERAL1
gZ LITERAL1
aXmove LITERAL1
aYmove LITERAL1
aZmove LITERAL1
gXmove LITERAL1
gYmove LITERAL1
gZmove LITERAL1
tempMove LITERAL1
mXmove LITERAL1
mZmove LITERAL1
mYmove LITERAL1
Pitch LITERAL1
Roll LITERAL1
Plugged LITERAL1
Unplugged LITERAL1
Charging LITERAL1
NotCharging LITERAL1
Shutdown LITERAL1
Dying LITERAL1
Low LITERAL1
High LITERAL1
Full LITERAL1
MoveCharging LITERAL1
MoveNotCharging LITERAL1
MoveShutdown LITERAL1
MoveDying LITERAL1
MoveLow LITERAL1
MoveHigh LITERAL1
MoveFull LITERAL1
CableRumble LITERAL1
Cable LITERAL1
BluetoothRumble LITERAL1
Bluetooth LITERAL1
RumbleHigh LITERAL1
RumbleLow LITERAL1
####################################################
# Syntax Coloring Map For Xbox 360 USB Library
####################################################
####################################################
# Datatypes (KEYWORD1)
####################################################
XBOXUSB KEYWORD1
####################################################
# Methods and Functions (KEYWORD2)
####################################################
setLedBlink KEYWORD2
setLedMode KEYWORD2
Xbox360Connected KEYWORD2
####################################################
# Constants and enums (LITERAL1)
####################################################
ALL LITERAL1
ROTATING LITERAL1
FASTBLINK LITERAL1
SLOWBLINK LITERAL1
ALTERNATING LITERAL1
BACK LITERAL1
XBOX LITERAL1
A LITERAL1
B LITERAL1
X LITERAL1
Y LITERAL1