diff --git a/PS3BTREADME b/EXTRAREADME similarity index 65% rename from PS3BTREADME rename to EXTRAREADME index 2004ef7f..36515a06 100644 --- a/PS3BTREADME +++ b/EXTRAREADME @@ -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. 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). -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: -"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 "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 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! \ No newline at end of file diff --git a/PS3BT.cpp b/PS3BT.cpp index 92c8a640..8f9ae9af 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -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_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, 0xff, 0x27, 0x10, 0x00, 0x32, @@ -62,25 +62,6 @@ bPollEnable(false) // don't start polling before dongle is connected 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; iRegisterDeviceClass(this); //set devConfig[] entry -} - uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed) { 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[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_counter = 0; @@ -388,6 +369,9 @@ void PS3BT::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) /* Performs a cleanup after failed Init() attempt */ uint8_t PS3BT::Release() { + PS3Connected = false; + PS3MoveConnected = false; + PS3NavigationConnected = false; pUsb->GetAddressPool().FreeAddress(bAddress); bAddress = 0; bPollEnable = false; @@ -399,24 +383,20 @@ uint8_t PS3BT::Poll() if (!bPollEnable) return 0; 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 - ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected - } - qNextPollTime = millis() + pollInterval; // Poll time + ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected + } return 0; } 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 */ uint8_t buf[8]; buf[0] = 0x01; buf[1] = 0x00; 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) 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) { - /* Store the bluetooth address */ - for(uint8_t i = 0; i <6;i++) - my_bdaddr[i] = BDADDR[i]; - /* Set the internal bluetooth address */ uint8_t buf[11]; buf[0] = 0x05; @@ -446,7 +422,7 @@ void PS3BT::setMoveBdaddr(uint8_t* BDADDR) buf[10] = 0x12; 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) 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) return false; - if ((l2capinbuf[(uint16_t)b >> 8] & ((uint8_t)b & 0xff)) > 0) - return true; - else - return false; + 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; + else + return false; + } else { + if((l2capinbuf[(uint16_t)b >> 8] & ((uint8_t)b & 0xff))) + return true; + else + return false; + } } uint8_t PS3BT::getAnalogButton(AnalogButton a) { @@ -482,87 +465,75 @@ uint8_t PS3BT::getAnalogHat(AnalogHat a) return 0; return (uint8_t)(l2capinbuf[(uint16_t)a]); } -int32_t PS3BT::getSensor(Sensor a) +int16_t PS3BT::getSensor(Sensor a) { if (l2capinbuf == NULL) return 0; if (a == aX || a == aY || a == aZ || a == gZ) 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 - if (a == mXmove) + /*if (a == mXmove) 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) 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) - 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 - return 0; + return ((l2capinbuf[(uint16_t)a + 1] << 0x0F) | (l2capinbuf[(uint16_t)a] << 0x0C)); + */ + if (a == mXmove || a == mYmove) + 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) - return (((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4) | (l2capinbuf[(uint16_t)a] << 4)); + else if (a == tempMove) // The tempearature is 12 bits long too + return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4)); 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 accXval; double accYval; double accZval; - if(PS3BTConnected) { + if(PS3Connected) { // Data for the Kionix KXPC4 used in the DualShock 3 - double sensivity = 204.6; // 0.66/3.3*1023 (660mV/g) - double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) - accXval = ((double)getSensor(aX)-zeroG) / sensivity; // Convert to g's - accXval *= 2; - accYval = ((double)getSensor(aY)-zeroG) / sensivity; // Convert to g's - 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 - const uint16_t sensivity = 28285; // Find by experimenting - accXval = (double)getSensor(aXmove)/sensivity; - accYval = (double)getSensor(aYmove)/sensivity; - accZval = (double)getSensor(aZmove)/sensivity; - - 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); + 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); + } else if(PS3MoveConnected) { + // It's a Kionix KXSC4 inside the Motion controller + const uint16_t zeroG = 0x8000; + accXval = -(int16_t)(getSensor(aXmove)-zeroG); + accYval = (int16_t)(getSensor(aYmove)-zeroG); + accZval = (int16_t)(getSensor(aZmove)-zeroG); } - 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 // 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; + double angle = (atan2(accYval,accZval)+PI)*RAD_TO_DEG; return angle; } else { - double angle = (atan2(-accXval,-accZval)+PI)*RAD_TO_DEG; + double angle = (atan2(accXval,accZval)+PI)*RAD_TO_DEG; 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) { if (l2capinbuf == NULL) @@ -573,7 +544,7 @@ bool PS3BT::getStatus(Status c) } String PS3BT::getStatusString() { - if (PS3BTConnected || PS3NavigationBTConnected) + if (PS3Connected || PS3NavigationConnected) { char statusOutput[100]; @@ -605,7 +576,7 @@ String PS3BT::getStatusString() return statusOutput; } - else if(PS3MoveBTConnected) + else if(PS3MoveConnected) { char statusOutput[50]; @@ -625,12 +596,12 @@ String PS3BT::getStatusString() } void PS3BT::disconnect()//Use this void to disconnect any of the controllers { - if (PS3BTConnected) - PS3BTConnected = false; - else if (PS3MoveBTConnected) - PS3MoveBTConnected = false; - else if (PS3NavigationBTConnected) - PS3NavigationBTConnected = false; + if (PS3Connected) + PS3Connected = false; + else if (PS3MoveConnected) + PS3MoveConnected = false; + else if (PS3NavigationConnected) + PS3NavigationConnected = false; //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); @@ -648,10 +619,16 @@ void PS3BT::HCI_event_task() { case EV_COMMAND_COMPLETE: hci_event_flag |= HCI_FLAG_CMD_COMPLETE; // set command complete flag - if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10))// parameters from read local bluetooth address - { - for (uint8_t i = 0; i < 6; i++) - my_bdaddr[i] = hcibuf[6 + i]; + 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++) + my_bdaddr[i] = hcibuf[6 + i]; + hci_event_flag |= HCI_FLAG_READ_BDADDR; + } } break; @@ -683,10 +660,7 @@ void PS3BT::HCI_event_task() hci_event_flag |= HCI_FLAG_DISCONN_COMPLETE; //set disconnect commend complete flag hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE; // clear connection complete flag } - break; - - case EV_NUM_COMPLETE_PKT: - break; + break; case EV_REMOTE_NAME_COMPLETE: if (!hcibuf[2]) // check if reading is OK @@ -707,7 +681,11 @@ void PS3BT::HCI_event_task() hci_event_flag |= HCI_FLAG_INCOMING_REQUEST; 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: break; @@ -782,8 +760,9 @@ void PS3BT::HCI_task() hci_counter = 0; } break; + case HCI_BDADDR_STATE: - if (hci_cmd_complete) + if (hci_read_bdaddr_complete) { #ifdef DEBUG Notify(PSTR("\r\nLocal Bluetooth Address: ")); @@ -794,8 +773,25 @@ void PS3BT::HCI_task() } PrintHex(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 hci_state = HCI_SCANNING_STATE; } + break; + break; case HCI_SCANNING_STATE: #ifdef DEBUG @@ -957,14 +953,14 @@ void PS3BT::ACL_event_task() Notify(PSTR(" Identifier: ")); PrintHex(l2capinbuf[9]); */ - if ((l2capinbuf[13] | l2capinbuf[12]) == L2CAP_PSM_HID_CTRL) + if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == L2CAP_PSM_HID_CTRL) { identifier = l2capinbuf[9]; control_scid[0] = l2capinbuf[14]; control_scid[1] = l2capinbuf[15]; 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]; 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]) { #ifdef DEBUG - Notify(PSTR("\r\nDisconnected Request: Disconnected Control")); + Notify(PSTR("\r\nDisconnect Request: Control Channel")); #endif identifier = l2capinbuf[9]; 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]) { #ifdef DEBUG - Notify(PSTR("\r\nDisconnected Request: Disconnected Interrupt")); + Notify(PSTR("\r\nDisconnect Request: Interrupt Channel")); #endif identifier = l2capinbuf[9]; 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]) { - //Serial.print("\r\nDisconnected Response: Disconnected Control"); + //Serial.print("\r\nDisconnect Response: Control Channel"); identifier = l2capinbuf[9]; l2cap_event_flag |= L2CAP_EV_CONTROL_DISCONNECT_RESPONSE; } 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]; 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 { //Serial.print("\r\nL2CAP Interrupt"); - if(PS3BTConnected || PS3MoveBTConnected || PS3NavigationBTConnected) + if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) { readReport(); #ifdef PRINTREPORT @@ -1169,30 +1165,29 @@ void PS3BT::L2CAP_task() #ifdef DEBUG Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n")); #endif - PS3BTConnected = true; + PS3Connected = true; } else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N') setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller #ifdef DEBUG Notify(PSTR("\r\nNavigation Controller Enabled\r\n")); #endif - PS3NavigationBTConnected = true; + PS3NavigationConnected = true; } else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M') moveSetBulb(Red); timerBulbRumble = millis(); #ifdef DEBUG Notify(PSTR("\r\nMotion Controller Enabled\r\n")); #endif - PS3MoveBTConnected = true; + PS3MoveConnected = true; } l2cap_state = L2CAP_EV_L2CAP_DONE; } break; 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 (dtimeBulbRumble > 4000)//Send at least every 4th second + if (millis() - timerBulbRumble > 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 timerBulbRumble = millis(); @@ -1231,11 +1226,13 @@ void PS3BT::L2CAP_task() /************************************************************/ void PS3BT::readReport() { + if (l2capinbuf == NULL) + return; 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)); - else if(PS3MoveBTConnected) + else if(PS3MoveConnected) ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16)); //Notify(PSTR("\r\nButtonState"); @@ -1265,7 +1262,9 @@ void PS3BT::readReport() } 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 { for(uint8_t i = 10; i < 58;i++) @@ -1319,6 +1318,13 @@ void PS3BT::hci_read_bdaddr() hcibuf[1] = 0x04 << 2; // HCI OGF = 4 hcibuf[2] = 0x00; 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() { @@ -1511,12 +1517,10 @@ void PS3BT::HID_Command(uint8_t* data, uint16_t nbytes) buf[7] = control_scid[1]; 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 (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 + 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 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) { - //check if LED is already off - 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); - } + HIDBuffer[11] &= ~((uint8_t)(((uint16_t)a & 0x0f) << 1)); + HID_Command(HIDBuffer, HID_BUFFERSIZE); } 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); } void PS3BT::enable_sixaxis()//Command used to enable the Dualshock 3 and Navigation controller to send data via USB @@ -1609,12 +1611,10 @@ void PS3BT::HIDMove_Command(uint8_t* data,uint16_t nbytes) buf[7] = interrupt_scid[1]; 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 (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 + 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 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" { - //set the Bulb's values into the write buffer - HIDMoveBuffer[3] = (uint8_t)(color >> 16); - HIDMoveBuffer[4] = (uint8_t)(color >> 8); - HIDMoveBuffer[5] = (uint8_t)(color); - - HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); + moveSetBulb((uint8_t)(color >> 16),(uint8_t)(color >> 8),(uint8_t)(color)); } 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 HIDMoveBuffer[7] = rumble; diff --git a/PS3BT.h b/PS3BT.h index 8c1f43df..ae038dad 100644 --- a/PS3BT.h +++ b/PS3BT.h @@ -62,13 +62,14 @@ #define HCI_INIT_STATE 0 #define HCI_RESET_STATE 1 #define HCI_BDADDR_STATE 2 -#define HCI_SCANNING_STATE 3 -#define HCI_CONNECT_IN_STATE 4 -#define HCI_REMOTE_NAME_STATE 5 -#define HCI_CONNECTED_STATE 6 -#define HCI_DISABLE_SCAN 7 -#define HCI_DONE_STATE 8 -#define HCI_DISCONNECT_STATE 9 +#define HCI_LOCAL_VERSION_STATE 3 +#define HCI_SCANNING_STATE 4 +#define HCI_CONNECT_IN_STATE 5 +#define HCI_REMOTE_NAME_STATE 6 +#define HCI_CONNECTED_STATE 7 +#define HCI_DISABLE_SCAN 8 +#define HCI_DONE_STATE 9 +#define HCI_DISCONNECT_STATE 10 /* HCI event flags*/ #define HCI_FLAG_CMD_COMPLETE 0x01 @@ -76,6 +77,8 @@ #define HCI_FLAG_DISCONN_COMPLETE 0x04 #define HCI_FLAG_REMOTE_NAME_COMPLETE 0x08 #define HCI_FLAG_INCOMING_REQUEST 0x10 +#define HCI_FLAG_READ_BDADDR 0x20 +#define HCI_FLAG_READ_VERSION 0x40 /*Macros for HCI event flag tests */ #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_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_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 */ #define EV_COMMAND_COMPLETE 0x0E @@ -174,24 +179,24 @@ enum LED }; enum Colors { - //Used to set the colors of the move controller - Red = 0xFF0000,//((255 << 16) | (0 << 8) | 0); - Green = 0xFF00,//((0 << 16) | (255 << 8) | 0); - Blue = 0xFF,//((0 << 16) | (0 << 8) | 255); + // 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,//((255 << 16) | (235 << 8) | 4); - Lightblue = 0xFFFF,//((0 << 16) | (255 << 8) | 255); - Purble = 0xFF00FF,//((255 << 16) | (0 << 8) | 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,//((255 << 16) | (255 << 8) | 255); - Off = 0x00,//((0 << 16) | (0 << 8) | 0); + 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 + // Sixaxis Dualshcock 3 & Navigation controller SELECT = (11 << 8) | 0x01, L3 = (11 << 8) | 0x02, R3 = (11 << 8) | 0x04, @@ -212,7 +217,13 @@ enum Button PS = (13 << 8) | 0x01, - //Playstation Move Controller + 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 SELECT_MOVE = (10 << 8) | 0x01, START_MOVE = (10 << 8) | 0x08, @@ -222,8 +233,9 @@ enum Button SQUARE_MOVE = (11 << 8) | 0x80, PS_MOVE = (12 << 8) | 0x01, - 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 + 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 + */ }; enum AnalogButton { @@ -243,7 +255,7 @@ enum AnalogButton SQUARE_ANALOG = 34, //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 { @@ -315,9 +327,8 @@ enum Rumble class PS3BT : public USBDeviceConfig, public UsbConfigXtracter { -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); +public: + 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); // USBDeviceConfig implementation virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); @@ -338,10 +349,11 @@ public: bool getButton(Button b); uint8_t getAnalogButton(AnalogButton a); uint8_t getAnalogHat(AnalogHat a); - int32_t getSensor(Sensor a); + int16_t getSensor(Sensor a); double getAngle(Angle a); bool getStatus(Status c); String getStatusString(); + String getTemperature(); void disconnect(); // use this void to disconnect any of the controllers /* HID Commands */ @@ -351,17 +363,18 @@ public: 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 PS3BTConnected;// 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 PS3NavigationBTConnected;// Variable used to indicate if the navigation controller is successfully connected + 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 pressed + bool buttonReleased;//Indicate if a button has been released protected: /* mandatory members */ @@ -389,6 +402,7 @@ private: int16_t hci_handle; 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 hci_version; /* variables used by high level HCI task */ uint8_t hci_state; //current state of bluetooth hci connection @@ -405,11 +419,9 @@ private: uint32_t ButtonState; uint32_t OldButtonState; 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 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 l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in 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_disable(); void hci_read_bdaddr(); + void hci_read_local_version_information(); void hci_accept_connection(); void hci_remote_name(); void hci_disconnect(); diff --git a/PS3USB.cpp b/PS3USB.cpp new file mode 100644 index 00000000..26e7f49d --- /dev/null +++ b/PS3USB.cpp @@ -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; iRegisterDeviceClass(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(rcode); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: ")); + PrintHex(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(VID); + Notify(PSTR(" PID: ")); + PrintHex(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(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(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(my_bdaddr[i]); + Serial.print(":"); + } + PrintHex(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(my_bdaddr[i]); + Serial.print(":"); + } + PrintHex(my_bdaddr[0]); +#endif + return; +} \ No newline at end of file diff --git a/PS3USB.h b/PS3USB.h new file mode 100644 index 00000000..a89faae7 --- /dev/null +++ b/PS3USB.h @@ -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 diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp new file mode 100644 index 00000000..a5411c2b --- /dev/null +++ b/XBOXUSB.cpp @@ -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; iRegisterDeviceClass(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(rcode); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: ")); + PrintHex(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(VID); + Notify(PSTR(" PID: ")); + PrintHex(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(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(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); +} \ No newline at end of file diff --git a/XBOXUSB.h b/XBOXUSB.h new file mode 100644 index 00000000..b688eb0b --- /dev/null +++ b/XBOXUSB.h @@ -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 diff --git a/avrpins.h b/avrpins.h index bb41602c..df37def9 100644 --- a/avrpins.h +++ b/avrpins.h @@ -20,9 +20,13 @@ e-mail : support@circuitsathome.com #ifndef _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 */ //#define BOARD_MEGA_ADK +#endif +/* Uncomment the following if you are using a Teensy 2.0 */ +//#define BOARD_TEENSY #include @@ -501,7 +505,47 @@ template #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 // http://www.pjrc.com/teensy/pinout.html #define P0 Pb0 diff --git a/examples/PS3/PS3BT/PS3BT.ino b/examples/PS3/PS3BT/PS3BT.ino new file mode 100644 index 00000000..122d984a --- /dev/null +++ b/examples/PS3/PS3BT/PS3BT.ino @@ -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 +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); +} diff --git a/examples/PS3/PS3USB/PS3USB.ino b/examples/PS3/PS3USB/PS3USB.ino new file mode 100644 index 00000000..0741d220 --- /dev/null +++ b/examples/PS3/PS3USB/PS3USB.ino @@ -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 +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); + } +} + diff --git a/examples/PS3BT/PS3BT.ino b/examples/PS3BT/PS3BT.ino deleted file mode 100644 index 2b6fbd95..00000000 --- a/examples/PS3BT/PS3BT.ino +++ /dev/null @@ -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 -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); - } - } -} diff --git a/examples/XBOX360USB/XBOX360USB.ino b/examples/XBOX360USB/XBOX360USB.ino new file mode 100644 index 00000000..580129fe --- /dev/null +++ b/examples/XBOX360USB/XBOX360USB.ino @@ -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 +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); +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 00000000..930a08e8 --- /dev/null +++ b/keywords.txt @@ -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 \ No newline at end of file