From 39af47c7a12f42eb74097ef5208cfa8bc5a7885f Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Tue, 18 Jun 2013 22:26:31 -0400 Subject: [PATCH 01/32] Merge branches 'master' and 'master' of github.com:felis/USB_Host_Shield_2.0 From c3c80924ec9e38c8ed4f933b6fb4d6635476949e Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 4 Jul 2013 15:37:29 +0200 Subject: [PATCH 02/32] Forgot to set debug level --- SPP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SPP.cpp b/SPP.cpp index b60cd72a..cfaf37f2 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -231,7 +231,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) { } #ifdef EXTRADEBUG else { - Notify(PSTR("\r\nUnknown PDU: ")); + Notify(PSTR("\r\nUnknown PDU: "), 0x80); D_PrintHex (l2capinbuf[8], 0x80); } #endif From 2dc817f84aeb98a1772c2e02727e95817369b04e Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 14 Jul 2013 00:43:35 +0200 Subject: [PATCH 03/32] Added attachOnInit This will allow the user to call a function when the controller is initialized --- PS3BT.cpp | 15 ++++++++++++--- PS3BT.h | 26 +++++++++++++++++++++----- PS3USB.cpp | 22 ++++++++++++++++------ PS3USB.h | 16 ++++++++++++++++ Wii.cpp | 14 +++++++++++--- Wii.h | 23 +++++++++++++++++++---- XBOXRECV.cpp | 32 +++++++++++++++++++------------- XBOXRECV.h | 17 +++++++++++++++++ XBOXUSB.cpp | 15 +++++++++++---- XBOXUSB.h | 16 ++++++++++++++++ keywords.txt | 2 ++ 11 files changed, 160 insertions(+), 38 deletions(-) diff --git a/PS3BT.cpp b/PS3BT.cpp index d80f0b52..34afd011 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -516,25 +516,23 @@ void PS3BT::Run() { case L2CAP_HID_PS3_LED: if (millis() - timer > 1000) { // loop 1 second before sending the command if (remote_name[0] == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P') - setLedOn(LED1); #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80); #endif 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_USB_HOST Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80); #endif PS3NavigationConnected = true; } else if (remote_name[0] == 'M') { // First letter in Motion Controller ('M') - moveSetBulb(Red); timerBulbRumble = millis(); #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80); #endif PS3MoveConnected = true; } + onInit(); // Turn on the LED on the controller l2cap_state = L2CAP_DONE; } break; @@ -659,3 +657,14 @@ void PS3BT::moveSetRumble(uint8_t rumble) { HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); } + +void PS3BT::onInit() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else { + if (PS3MoveConnected) + moveSetBulb(Red); + else // Dualshock 3 or Navigation controller + setLedOn(LED1); + } +} \ No newline at end of file diff --git a/PS3BT.h b/PS3BT.h index 1336828e..5b00232f 100644 --- a/PS3BT.h +++ b/PS3BT.h @@ -207,19 +207,35 @@ public: * @param rumble The desired value in the range from 64-255. */ void moveSetRumble(uint8_t rumble); + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; /**@}*/ - /** Variable used to indicate if the normal playstation controller is successfully connected. */ + /** Variable used to indicate if the normal Playstation controller is successfully connected. */ bool PS3Connected; - /** Variable used to indicate if the move controller is successfully connected. */ + /** Variable used to indicate if the Move controller is successfully connected. */ bool PS3MoveConnected; - /** Variable used to indicate if the navigation controller is successfully connected. */ + /** Variable used to indicate if the Navigation controller is successfully connected. */ bool PS3NavigationConnected; private: - /* mandatory members */ + /* Mandatory members */ BTD *pBtd; + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void onInit(); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + void L2CAP_task(); // L2CAP state machine /* Variables filled from HCI event management */ @@ -229,7 +245,7 @@ private: /* variables used by high level L2CAP task */ uint8_t l2cap_state; - uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events + uint16_t l2cap_event_flag; // L2CAP flags of received Bluetooth events unsigned long timer; diff --git a/PS3USB.cpp b/PS3USB.cpp index 7bbcfd9d..7fbb0a46 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -183,10 +183,9 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { #endif PS3NavigationConnected = true; } - /* Set internal bluetooth address and request for data */ + /* 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++) @@ -199,12 +198,12 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nMotion Controller Connected"), 0x80); #endif PS3MoveConnected = true; - setMoveBdaddr(my_bdaddr); // Set internal bluetooth address - moveSetBulb(Red); - + setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address + writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work } - + onInit(); + #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); for (int8_t i = 5; i > 0; i--) { @@ -538,3 +537,14 @@ void PS3USB::setMoveBdaddr(uint8_t* BDADDR) { //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); } + +void PS3USB::onInit() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else { + if (PS3MoveConnected) + moveSetBulb(Red); + else // Dualshock 3 or Navigation controller + setLedOn(LED1); + } +} \ No newline at end of file diff --git a/PS3USB.h b/PS3USB.h index d0b45e47..23ae927c 100644 --- a/PS3USB.h +++ b/PS3USB.h @@ -224,6 +224,14 @@ public: * @param rumble The desired value in the range from 64-255. */ void moveSetRumble(uint8_t rumble); + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; /**@}*/ /** Variable used to indicate if the normal playstation controller is successfully connected. */ @@ -242,6 +250,14 @@ protected: EpInfo epInfo[PS3_MAX_ENDPOINTS]; private: + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void onInit(); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + bool bPollEnable; uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values diff --git a/Wii.cpp b/Wii.cpp index 9948354f..751bdd9b 100755 --- a/Wii.cpp +++ b/Wii.cpp @@ -326,7 +326,7 @@ void WII::ACLData(uint8_t* l2capinbuf) { #endif nunchuckConnected = false; // It must be the Nunchuck controller then l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - setLedStatus(); + onInit(); setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer } else { setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer @@ -779,7 +779,7 @@ void WII::Run() { case L2CAP_LED_STATE: if (nunchuck_connected_flag) nunchuckConnected = true; - setLedStatus(); + onInit(); l2cap_state = L2CAP_DONE; break; @@ -824,7 +824,7 @@ void WII::Run() { else if (stateCounter == 400) readExtensionType(); // Check if it has been activated else if (stateCounter == 450) { - //setLedStatus(); + onInit(); stateCounter = 0; unknownExtensionConnected = false; } @@ -1062,6 +1062,14 @@ uint16_t WII::getAnalogHat(AnalogHat a) { return output; } } + +void WII::onInit() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else + setLedStatus(); +} + /************************************************************/ /* The following functions are for the IR camera */ /************************************************************/ diff --git a/Wii.h b/Wii.h index 753947ba..60c9f07e 100755 --- a/Wii.h +++ b/Wii.h @@ -233,6 +233,14 @@ public: uint8_t getWiiState() { return wiiState; }; + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; /**@}*/ /**@{*/ @@ -418,8 +426,15 @@ public: #endif private: - /* Mandatory members */ - BTD *pBtd; + BTD *pBtd; // Pointer to BTD instance + + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void onInit(); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() void L2CAP_task(); // L2CAP state machine @@ -427,9 +442,9 @@ private: uint16_t hci_handle; bool activeConnection; // Used to indicate if it's already has established a connection - /* variables used by high level L2CAP task */ + /* Variables used by high level L2CAP task */ uint8_t l2cap_state; - uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events + uint16_t l2cap_event_flag; // l2cap flags of received Bluetooth events uint32_t ButtonState; uint32_t OldButtonState; diff --git a/XBOXRECV.cpp b/XBOXRECV.cpp index 56dbe567..1d4d7724 100644 --- a/XBOXRECV.cpp +++ b/XBOXRECV.cpp @@ -310,7 +310,7 @@ void XBOXRECV::readReport(uint8_t controller) { #endif if (Xbox360Connected[controller]) { #ifdef DEBUG_USB_HOST - char* str = 0; + const char* str = 0; switch (readBuf[1]) { case 0x80: str = PSTR(" as controller\r\n"); break; @@ -322,18 +322,7 @@ void XBOXRECV::readReport(uint8_t controller) { Notify(PSTR(": connected"), 0x80); Notify(str, 0x80); #endif - LED led; - switch (controller) { - case 0: led = LED1; - break; - case 1: led = LED2; - break; - case 2: led = LED3; - break; - case 3: led = LED4; - break; - } - setLedOn(led, controller); + onInit(controller); } #ifdef DEBUG_USB_HOST else @@ -529,3 +518,20 @@ void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) { XboxCommand(controller, writeBuf, 7); } + +void XBOXRECV::onInit(uint8_t controller) { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else { + LED led; + if (controller == 0) + led = LED1; + else if (controller == 1) + led = LED2; + if (controller == 2) + led = LED3; + else + led = LED4; + setLedOn(led, controller); + } +} diff --git a/XBOXRECV.h b/XBOXRECV.h index 9ae12aca..63bc8a70 100644 --- a/XBOXRECV.h +++ b/XBOXRECV.h @@ -200,6 +200,14 @@ public: * @return True if a button has changed. */ bool buttonChanged(uint8_t controller = 0); + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; /**@}*/ /** True if a wireless receiver is connected. */ @@ -216,6 +224,15 @@ protected: EpInfo epInfo[XBOX_MAX_ENDPOINTS]; private: + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + * @param controller The initialized controller. + */ + void onInit(uint8_t controller); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + bool bPollEnable; /* Variables to store the buttons */ diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp index e79c8a15..a5b76fc0 100644 --- a/XBOXUSB.cpp +++ b/XBOXUSB.cpp @@ -167,7 +167,7 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { if (rcode) goto FailSetDevTblEntry; - delay(200); //Give time for address change + delay(200); // Give time for address change rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1); if (rcode) @@ -176,12 +176,12 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80); #endif - setLedOn(LED1); + onInit(); Xbox360Connected = true; bPollEnable = true; - return 0; // successful configuration + return 0; // Successful configuration - /* diagnostic messages */ + /* Diagnostic messages */ FailGetDevDescr: #ifdef DEBUG_USB_HOST NotifyFailGetDevDescr(); @@ -345,3 +345,10 @@ void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) { XboxCommand(writeBuf, 8); } + +void XBOXUSB::onInit() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else + setLedOn(LED1); +} diff --git a/XBOXUSB.h b/XBOXUSB.h index c3f7bdd8..07839c48 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -168,6 +168,14 @@ public: * @param lm See ::LEDMode. */ void setLedMode(LEDMode lm); + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; /**@}*/ /** True if a Xbox 360 controller is connected. */ @@ -182,6 +190,14 @@ protected: EpInfo epInfo[XBOX_MAX_ENDPOINTS]; private: + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void onInit(); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + bool bPollEnable; /* Variables to store the buttons */ diff --git a/keywords.txt b/keywords.txt index 01dcbdc1..2d713b5c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -56,6 +56,8 @@ setLedToggle KEYWORD2 moveSetBulb KEYWORD2 moveSetRumble KEYWORD2 +attachOnInit KEYWORD2 + PS3Connected KEYWORD2 PS3MoveConnected KEYWORD2 PS3NavigationConnected KEYWORD2 From 759d3b69770d70fbba6ef59816dff747e88298a5 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 14 Jul 2013 01:28:47 +0200 Subject: [PATCH 04/32] Updated example to show how to use attachOnInit Also removed whitespace PS3Multi example --- examples/Bluetooth/PS3Multi/PS3Multi.ino | 77 ++++++++++++++---------- examples/Bluetooth/WiiMulti/WiiMulti.ino | 21 +++++-- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/examples/Bluetooth/PS3Multi/PS3Multi.ino b/examples/Bluetooth/PS3Multi/PS3Multi.ino index 6bcdcdf5..6c4805bb 100644 --- a/examples/Bluetooth/PS3Multi/PS3Multi.ino +++ b/examples/Bluetooth/PS3Multi/PS3Multi.ino @@ -8,13 +8,16 @@ #include USB Usb; BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so -PS3BT* PS3[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM! +PS3BT *PS3[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM! const uint8_t length = sizeof(PS3)/sizeof(PS3[0]); // Get the lenght of the array boolean printAngle[length]; +boolean oldControllerState[length]; void setup() { - for(uint8_t i=0;iattachOnInit(onInit); // onInit() is called upon a new connection - you can call the function whatever you like + } Serial.begin(115200); if (Usb.Init() == -1) { @@ -31,28 +34,29 @@ void loop() { if(PS3[i]->getAnalogHat(LeftHatX) > 137 || PS3[i]->getAnalogHat(LeftHatX) < 117 || PS3[i]->getAnalogHat(LeftHatY) > 137 || PS3[i]->getAnalogHat(LeftHatY) < 117 || PS3[i]->getAnalogHat(RightHatX) > 137 || PS3[i]->getAnalogHat(RightHatX) < 117 || PS3[i]->getAnalogHat(RightHatY) > 137 || PS3[i]->getAnalogHat(RightHatY) < 117) { Serial.print(F("\r\nLeftHatX: ")); Serial.print(PS3[i]->getAnalogHat(LeftHatX)); - Serial.print(F("\tLeftHatY: ")); + Serial.print(F("\tLeftHatY: ")); Serial.print(PS3[i]->getAnalogHat(LeftHatY)); if(!PS3[i]->PS3NavigationConnected) { // The Navigation controller only have one joystick - Serial.print(F("\tRightHatX: ")); + Serial.print(F("\tRightHatX: ")); Serial.print(PS3[i]->getAnalogHat(RightHatX)); - Serial.print(F("\tRightHatY: ")); - Serial.print(PS3[i]->getAnalogHat(RightHatY)); + Serial.print(F("\tRightHatY: ")); + Serial.print(PS3[i]->getAnalogHat(RightHatY)); } } //Analog button values can be read from almost all buttons if(PS3[i]->getAnalogButton(L2) || PS3[i]->getAnalogButton(R2)) { - Serial.print(F("\r\nL2: ")); + Serial.print(F("\r\nL2: ")); Serial.print(PS3[i]->getAnalogButton(L2)); if(!PS3[i]->PS3NavigationConnected) { - Serial.print(F("\tR2: ")); + Serial.print(F("\tR2: ")); Serial.print(PS3[i]->getAnalogButton(R2)); } } if(PS3[i]->getButtonClick(PS)) { Serial.print(F("\r\nPS")); PS3[i]->disconnect(); - } + oldControllerState[i] = false; // Reset value + } else { if(PS3[i]->getButtonClick(TRIANGLE)) Serial.print(F("\r\nTraingle")); @@ -64,56 +68,56 @@ void loop() { Serial.print(F("\r\nSquare")); if(PS3[i]->getButtonClick(UP)) { - Serial.print(F("\r\nUp")); + Serial.print(F("\r\nUp")); if(PS3[i]->PS3Connected) { PS3[i]->setAllOff(); PS3[i]->setLedOn(LED4); } - } + } if(PS3[i]->getButtonClick(RIGHT)) { Serial.print(F("\r\nRight")); if(PS3[i]->PS3Connected) { PS3[i]->setAllOff(); - PS3[i]->setLedOn(LED1); - } - } + PS3[i]->setLedOn(LED1); + } + } if(PS3[i]->getButtonClick(DOWN)) { Serial.print(F("\r\nDown")); if(PS3[i]->PS3Connected) { PS3[i]->setAllOff(); - PS3[i]->setLedOn(LED2); + PS3[i]->setLedOn(LED2); } - } - if(PS3[i]->getButtonClick(LEFT)) { - Serial.print(F("\r\nLeft")); + } + if(PS3[i]->getButtonClick(LEFT)) { + Serial.print(F("\r\nLeft")); if(PS3[i]->PS3Connected) { - PS3[i]->setAllOff(); - PS3[i]->setLedOn(LED3); - } + PS3[i]->setAllOff(); + PS3[i]->setLedOn(LED3); + } } if(PS3[i]->getButtonClick(L1)) - Serial.print(F("\r\nL1")); + Serial.print(F("\r\nL1")); if(PS3[i]->getButtonClick(L3)) - Serial.print(F("\r\nL3")); + Serial.print(F("\r\nL3")); if(PS3[i]->getButtonClick(R1)) - Serial.print(F("\r\nR1")); + Serial.print(F("\r\nR1")); if(PS3[i]->getButtonClick(R3)) Serial.print(F("\r\nR3")); if(PS3[i]->getButtonClick(SELECT)) { - Serial.print(F("\r\nSelect - ")); - Serial.print(PS3[i]->getStatusString()); - } + Serial.print(F("\r\nSelect - ")); + Serial.print(PS3[i]->getStatusString()); + } if(PS3[i]->getButtonClick(START)) { - Serial.print(F("\r\nStart")); + Serial.print(F("\r\nStart")); printAngle[i] = !printAngle[i]; - } + } } if(printAngle[i]) { - Serial.print(F("\r\nPitch: ")); - Serial.print(PS3[i]->getAngle(Pitch)); - Serial.print(F("\tRoll: ")); + Serial.print(F("\r\nPitch: ")); + Serial.print(PS3[i]->getAngle(Pitch)); + Serial.print(F("\tRoll: ")); Serial.print(PS3[i]->getAngle(Roll)); } } @@ -121,3 +125,12 @@ void loop() { //else if(PS3[i]->PS3MoveConnected) { } } + +void onInit() { + for (uint8_t i=0;iPS3Connected || PS3[i]->PS3NavigationConnected) && !oldControllerState[i]) { + oldControllerState[i] = true; // Used to check which is the new controller + PS3[i]->setLedOn((LED)i); // Cast directly to LED enum - see: "controllerEnums.h" + } + } +} diff --git a/examples/Bluetooth/WiiMulti/WiiMulti.ino b/examples/Bluetooth/WiiMulti/WiiMulti.ino index c0705d6e..c9bac283 100644 --- a/examples/Bluetooth/WiiMulti/WiiMulti.ino +++ b/examples/Bluetooth/WiiMulti/WiiMulti.ino @@ -8,14 +8,17 @@ #include USB Usb; BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so -WII* Wii[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM! +WII *Wii[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM! const uint8_t length = sizeof(Wii)/sizeof(Wii[0]); // Get the lenght of the array -bool printAngle[length]; +boolean printAngle[length]; +boolean oldControllerState[length]; void setup() { - for(uint8_t i=0;iattachOnInit(onInit); // onInit() is called upon a new connection - you can call the function whatever you like + } + Serial.begin(115200); if (Usb.Init() == -1) { Serial.print(F("\r\nOSC did not start")); @@ -31,6 +34,7 @@ void loop() { if(Wii[i]->getButtonClick(HOME)) { // You can use getButtonPress to see if the button is held down Serial.print(F("\r\nHOME")); Wii[i]->disconnect(); + oldControllerState[i] = false; // Reset value delay(1000); // This delay is needed for some Wiimotes, so it doesn't try to reconnect right away } else { @@ -105,3 +109,12 @@ void loop() { } } } + +void onInit() { + for (uint8_t i=0;iwiimoteConnected && !oldControllerState[i]) { + oldControllerState[i] = true; // Used to check which is the new controller + Wii[i]->setLedOn((LED)i); // Cast directly to LED enum - see: "controllerEnums.h" + } + } +} From b4b570d7c84179acc76c561814fd69ba99836831 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 14 Jul 2013 02:08:25 +0200 Subject: [PATCH 05/32] Added isReady to keywords --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 2d713b5c..2575d9a1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -62,6 +62,7 @@ PS3Connected KEYWORD2 PS3MoveConnected KEYWORD2 PS3NavigationConnected KEYWORD2 +isReady KEYWORD2 watingForConnection KEYWORD2 #################################################### From 8c3424cf282b33cd67a2182e18acda146edf19c7 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 14 Jul 2013 16:44:53 +0200 Subject: [PATCH 06/32] Forgot else if --- XBOXRECV.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XBOXRECV.cpp b/XBOXRECV.cpp index 1d4d7724..98dd95fd 100644 --- a/XBOXRECV.cpp +++ b/XBOXRECV.cpp @@ -528,7 +528,7 @@ void XBOXRECV::onInit(uint8_t controller) { led = LED1; else if (controller == 1) led = LED2; - if (controller == 2) + else if (controller == 2) led = LED3; else led = LED4; From 47b9b257d6146aa8dd707701500e4a446a335526 Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Mon, 15 Jul 2013 07:47:20 -0400 Subject: [PATCH 07/32] Make ADK work as per USB spec. --- adk.cpp | 14 ++++++++++---- adk.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/adk.cpp b/adk.cpp index ea6e6224..f07da6ac 100644 --- a/adk.cpp +++ b/adk.cpp @@ -58,14 +58,18 @@ ready(false) { } } +uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { + return Init(parent, port, lowspeed); // Just call Init. Yes, really! +} + /* Connection initialization of an Android phone */ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) { uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; uint8_t rcode; + uint8_t num_of_conf; // number of configurations UsbDevice *p = NULL; EpInfo *oldep_ptr = NULL; - uint8_t num_of_conf; // number of configurations // get memory address of USB device address pool AddressPool &addrPool = pUsb->GetAddressPool(); @@ -114,7 +118,6 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) { // 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) { @@ -126,6 +129,8 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) { }//if (rcode... //USBTRACE2("\r\nAddr:", bAddress); + // Spec says you should wait at least 200ms. + delay(300); p->lowspeed = false; @@ -222,7 +227,8 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) { if (rcode) { goto FailSwAcc; //init fails } - rcode = -1; + rcode = USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; + delay(1000); // Give Android a chance to do its reset. This is a guess, and possibly could be lower. goto SwAttempt; //switch to accessory mode attempted /* diagnostic messages */ @@ -266,7 +272,7 @@ SwAttempt: #ifdef DEBUG_USB_HOST USBTRACE("\r\nAccessory mode switch attempt"); #endif -//FailOnInit: + //FailOnInit: // USBTRACE("OnInit:"); // goto Fail; // diff --git a/adk.h b/adk.h index 4ea0ed63..590f008e 100644 --- a/adk.h +++ b/adk.h @@ -110,6 +110,7 @@ public: // USBDeviceConfig implementation + virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); virtual uint8_t Release(); From 1a1c2a18d3346731babaeff7953b803ee7d0a201 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Mon, 15 Jul 2013 18:20:58 +0200 Subject: [PATCH 08/32] Added DEVCLASSOK and VIDPIDOK to some drivers --- BTD.h | 17 +++++++++++++++++ PS3USB.h | 10 ++++++++++ XBOXRECV.h | 11 +++++++++++ XBOXUSB.h | 10 ++++++++++ adk.h | 4 ++++ 5 files changed, 52 insertions(+) diff --git a/BTD.h b/BTD.h index 329b2dda..8c4568f1 100755 --- a/BTD.h +++ b/BTD.h @@ -194,6 +194,23 @@ public: virtual bool isReady() { return bPollEnable; }; + /** + * Used by the USB core to check what this driver support. + * @param klass The device's USB class. + * @return Returns true if the device's USB class matches this driver. + */ + virtual boolean DEVCLASSOK(uint8_t klass) { return (klass == USB_CLASS_WIRELESS_CTRL); } + + /** + * Used by the USB core to check what this driver support. + * Used to set the Bluetooth address into the PS3 controllers. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this driver. + */ + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return (vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID)); + }; /**@}*/ /** @name UsbConfigXtracter implementation */ diff --git a/PS3USB.h b/PS3USB.h index d0b45e47..666a3859 100644 --- a/PS3USB.h +++ b/PS3USB.h @@ -104,6 +104,16 @@ public: virtual bool isReady() { return bPollEnable; }; + + /** + * Used by the USB core to check what this driver support. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this driver. + */ + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return (vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID)); + }; /**@}*/ /** diff --git a/XBOXRECV.h b/XBOXRECV.h index 9ae12aca..86364ca6 100644 --- a/XBOXRECV.h +++ b/XBOXRECV.h @@ -52,6 +52,7 @@ #define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver #define MADCATZ_VID 0x1BAD // For unofficial Mad Catz receivers +#define JOYTECH_VID 0x162E // For unofficial Joytech controllers #define XBOX_MAX_ENDPOINTS 9 @@ -103,6 +104,16 @@ public: virtual bool isReady() { return bPollEnable; }; + + /** + * Used by the USB core to check what this driver support. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this driver. + */ + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && (pid == XBOX_WIRELESS_RECEIVER_PID || pid == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID)); + }; /**@}*/ /** @name Xbox Controller functions */ diff --git a/XBOXUSB.h b/XBOXUSB.h index c3f7bdd8..661a54bf 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -99,6 +99,16 @@ public: virtual bool isReady() { return bPollEnable; }; + + /** + * Used by the USB core to check what this driver support. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this driver. + */ + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && pid != XBOX_WIRELESS_RECEIVER_PID && pid != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID); + }; /**@}*/ /** @name Xbox Controller functions */ diff --git a/adk.h b/adk.h index 590f008e..fb5e7818 100644 --- a/adk.h +++ b/adk.h @@ -126,6 +126,10 @@ public: return ready; }; + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return (vid == ADK_VID && (pid == ADK_PID || pid == ADB_PID)); + }; + //UsbConfigXtracter implementation virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); }; //class ADK : public USBDeviceConfig ... From 9f855fca16e225e7fd1ee80a4f0aecb7f7b90519 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Mon, 15 Jul 2013 18:22:13 +0200 Subject: [PATCH 09/32] Check Bluetooth address before trying to set it --- PS3USB.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/PS3USB.cpp b/PS3USB.cpp index 7bbcfd9d..8882c92c 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -183,8 +183,7 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { #endif PS3NavigationConnected = true; } - /* Set internal bluetooth address and request for data */ - setBdaddr(my_bdaddr); + /* Set internal Bluetooth address and request for data */ enable_sixaxis(); setLedOn(LED1); @@ -199,20 +198,25 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nMotion Controller Connected"), 0x80); #endif PS3MoveConnected = true; - setMoveBdaddr(my_bdaddr); // Set internal bluetooth address moveSetBulb(Red); writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work } + if (my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { + if (PS3MoveConnected) + setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address + else + setBdaddr(my_bdaddr); // Set internal Bluetooth address #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); - for (int8_t i = 5; i > 0; i--) { - D_PrintHex (my_bdaddr[i], 0x80); - Notify(PSTR(":"), 0x80); - } - D_PrintHex (my_bdaddr[0], 0x80); + Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); + for (int8_t i = 5; i > 0; i--) { + D_PrintHex (my_bdaddr[i], 0x80); + Notify(PSTR(":"), 0x80); + } + D_PrintHex (my_bdaddr[0], 0x80); #endif + } bPollEnable = true; Notify(PSTR("\r\n"), 0x80); From 3b429e633b391efc8128afeaaa1726cd0bfb4984 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Mon, 15 Jul 2013 19:31:47 +0200 Subject: [PATCH 10/32] Print error code in ADK code Also added space between message and error code --- adk.cpp | 8 ++++---- message.cpp | 11 +++++------ message.h | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/adk.cpp b/adk.cpp index f07da6ac..8bce6723 100644 --- a/adk.cpp +++ b/adk.cpp @@ -234,25 +234,25 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) { /* diagnostic messages */ FailGetDevDescr: #ifdef DEBUG_USB_HOST - NotifyFailGetDevDescr(); + NotifyFailGetDevDescr(rcode); goto Fail; #endif FailSetDevTblEntry: #ifdef DEBUG_USB_HOST - NotifyFailSetDevTblEntry(); + NotifyFailSetDevTblEntry(rcode); goto Fail; #endif FailGetConfDescr: #ifdef DEBUG_USB_HOST - NotifyFailGetConfDescr(); + NotifyFailGetConfDescr(rcode); goto Fail; #endif FailSetConfDescr: #ifdef DEBUG_USB_HOST - NotifyFailSetConfDescr(); + NotifyFailSetConfDescr(rcode); goto Fail; #endif diff --git a/message.cpp b/message.cpp index a0dd721e..6a4f021f 100644 --- a/message.cpp +++ b/message.cpp @@ -65,18 +65,18 @@ void E_Notify(double d, int lvl) { #ifdef DEBUG_USB_HOST void NotifyFailGetDevDescr(void) { - Notify(PSTR("\r\ngetDevDescr"), 0x80); + Notify(PSTR("\r\ngetDevDescr "), 0x80); } void NotifyFailSetDevTblEntry(void) { - Notify(PSTR("\r\nsetDevTblEn"), 0x80); + Notify(PSTR("\r\nsetDevTblEn "), 0x80); } void NotifyFailGetConfDescr(void) { - Notify(PSTR("\r\ngetConf"), 0x80); + Notify(PSTR("\r\ngetConf "), 0x80); } void NotifyFailSetConfDescr(void) { - Notify(PSTR("\r\nsetConf"), 0x80); + Notify(PSTR("\r\nsetConf "), 0x80); } void NotifyFailGetDevDescr(uint8_t reason) { @@ -95,12 +95,11 @@ void NotifyFailGetConfDescr(uint8_t reason) { NotifyFail(reason); } -/* Will we need this in the future? void NotifyFailSetConfDescr(uint8_t reason) { NotifyFailSetConfDescr(); NotifyFail(reason); } -*/ + void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) { Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80); D_PrintHex (VID, 0x80); diff --git a/message.h b/message.h index 584808c3..f0725003 100644 --- a/message.h +++ b/message.h @@ -43,6 +43,7 @@ void E_Notifyc(char c, int lvl); void NotifyFailGetDevDescr(uint8_t reason); void NotifyFailSetDevTblEntry(uint8_t reason); void NotifyFailGetConfDescr(uint8_t reason); +void NotifyFailSetConfDescr(uint8_t reason); void NotifyFailGetDevDescr(void); void NotifyFailSetDevTblEntry(void); void NotifyFailGetConfDescr(void); From 42a2261fe8fe2ccc24c14b08d0c7fa96f07d1f6f Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Mon, 15 Jul 2013 19:33:15 +0200 Subject: [PATCH 11/32] Check error code before breaking --- Usb.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Usb.cpp b/Usb.cpp index 30d13f13..6d4e8db5 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -692,12 +692,10 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) { for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { if (!devConfig[devConfigIndex]) continue; // no driver if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed - if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid)) { + if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass)) { rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); - break; - } else if (devConfig[devConfigIndex]->DEVCLASSOK(klass)) { - rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); - if (!rcode) break; + if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED) + break; } } From b957f5f4dc4b4f8ebd292462d0a89d3f3700c5a8 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Mon, 15 Jul 2013 19:34:56 +0200 Subject: [PATCH 12/32] Added delay after setting address --- BTD.cpp | 6 ++++-- PS3USB.cpp | 2 ++ XBOXRECV.cpp | 2 ++ XBOXUSB.cpp | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index dbb784b2..703da2b2 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -115,14 +115,16 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { bAddress = 0; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nsetAddr: "), 0x80); -#endif D_PrintHex (rcode, 0x80); +#endif return rcode; } #ifdef EXTRADEBUG Notify(PSTR("\r\nAddr: "), 0x80); D_PrintHex (bAddress, 0x80); #endif + delay(300); // Spec says you should wait at least 200ms + p->lowspeed = false; //get pointer to assigned address record @@ -157,7 +159,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) { if (my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\n\rOr set the Bluetooth address in the constructor of the PS3BT class"), 0x80); + Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\n\ror set the Bluetooth address in the constructor of the PS3BT class"), 0x80); #endif } else { if (PID == PS3_PID || PID == PS3NAVIGATION_PID) diff --git a/PS3USB.cpp b/PS3USB.cpp index 8882c92c..d1e6d157 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -128,6 +128,8 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nAddr: "), 0x80); D_PrintHex (bAddress, 0x80); #endif + delay(300); // Spec says you should wait at least 200ms + p->lowspeed = false; //get pointer to assigned address record diff --git a/XBOXRECV.cpp b/XBOXRECV.cpp index 56dbe567..34cba4b0 100644 --- a/XBOXRECV.cpp +++ b/XBOXRECV.cpp @@ -128,6 +128,8 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nAddr: "), 0x80); D_PrintHex (bAddress, 0x80); #endif + delay(300); // Spec says you should wait at least 200ms + p->lowspeed = false; //get pointer to assigned address record diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp index e79c8a15..2692ffd1 100644 --- a/XBOXUSB.cpp +++ b/XBOXUSB.cpp @@ -131,6 +131,8 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nAddr: "), 0x80); D_PrintHex (bAddress, 0x80); #endif + delay(300); // Spec says you should wait at least 200ms + p->lowspeed = false; //get pointer to assigned address record From 4dc4958e41b186611faec1aa9965354d693b0b16 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Mon, 15 Jul 2013 20:17:28 +0200 Subject: [PATCH 13/32] Updated comment --- PS3USB.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PS3USB.cpp b/PS3USB.cpp index d1e6d157..844ab3af 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -185,8 +185,7 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { #endif PS3NavigationConnected = true; } - /* Set internal Bluetooth address and request for data */ - enable_sixaxis(); + enable_sixaxis(); // The PS3 controller needs a special command before it starts sending data setLedOn(LED1); // Needed for PS3 Dualshock and Navigation commands to work From c0fde76241eef992919efae235311eb32dab9128 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Tue, 16 Jul 2013 18:36:07 +0200 Subject: [PATCH 14/32] Make sure it doesn't try to init a driver twice --- Usb.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Usb.cpp b/Usb.cpp index 6d4e8db5..31d9bb9b 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -708,6 +708,7 @@ uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) { for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) { if (!devConfig[devConfigIndex]) continue; if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed + if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass)) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed); //printf("ERROR ENUMERATING %2.2x\r\n", rcode); From 7ff9dea66b329b2f1a9215e7e733614babf9fc11 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 17:52:23 +0200 Subject: [PATCH 15/32] Added support for original Xbox controller --- XBOXUSBOLD.cpp | 332 ++++++++++++++++++++++++ XBOXUSBOLD.h | 196 ++++++++++++++ controllerEnums.h | 2 + examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino | 97 +++++++ keywords.txt | 4 + 5 files changed, 631 insertions(+) create mode 100644 XBOXUSBOLD.cpp create mode 100644 XBOXUSBOLD.h create mode 100644 examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino diff --git a/XBOXUSBOLD.cpp b/XBOXUSBOLD.cpp new file mode 100644 index 00000000..22226cd9 --- /dev/null +++ b/XBOXUSBOLD.cpp @@ -0,0 +1,332 @@ +/* Copyright (C) 2013 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 "XBOXUSBOLD.h" +// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h +//#define EXTRADEBUG // Uncomment to get even more debugging data +#define PRINTREPORT // Uncomment to print the report send by the Xbox controller + +/** Buttons on the controllers */ +const uint8_t XBOXOLDBUTTONS[] PROGMEM = { + 0x01, // UP + 0x08, // RIGHT + 0x02, // DOWN + 0x04, // LEFT + + 0x20, // BACK + 0x10, // START + 0x40, // L3 + 0x80, // R3 + + // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons + 4, // BLACK + 5, // WHTIE + 6, // L1 + 7, // R1 + + 1, // B + 0, // A + 2, // X + 3, // Y +}; + +XBOXUSBOLD::XBOXUSBOLD(USB *p) : +pUsb(p), // pointer to USB class instance - mandatory +bAddress(0), // device address - mandatory +bPollEnable(false) { // don't start polling before dongle is connected + for (uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; + } + + if (pUsb) // register in USB subsystem + pUsb->RegisterDeviceClass(this); //set devConfig[] entry +} + +uint8_t XBOXUSBOLD::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"), 0x80); +#endif + // check if address has already been assigned to an instance + if (bAddress) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nAddress in use"), 0x80); +#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_USB_HOST + Notify(PSTR("\r\nAddress not found"), 0x80); +#endif + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if (!p->epinfo) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nepinfo is null"), 0x80); +#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; + + VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; + PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; + + if ((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || PID != XBOX_OLD_PID) // We just check if it's a xbox controller using the Vendor ID + goto FailUnknownDevice; + + // 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_USB_HOST + Notify(PSTR("\r\nsetAddr: "), 0x80); +#endif + D_PrintHex (rcode, 0x80); + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: "), 0x80); + D_PrintHex (bAddress, 0x80); +#endif + delay(300); // Spec says you should wait at least 200ms + + 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; + + /* 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 XBOX controllers */ + + /* Initialize data structures for endpoints of device */ + epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 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 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 FailSetConfDescr; + +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nXbox Controller Connected\r\n"), 0x80); +#endif + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + XboxConnected = true; + bPollEnable = true; + return 0; // Successful configuration + + /* Diagnostic messages */ +FailGetDevDescr: +#ifdef DEBUG_USB_HOST + NotifyFailGetDevDescr(); + goto Fail; +#endif + +FailSetDevTblEntry: +#ifdef DEBUG_USB_HOST + NotifyFailSetDevTblEntry(); + goto Fail; +#endif + +FailSetConfDescr: +#ifdef DEBUG_USB_HOST + NotifyFailSetConfDescr(); + goto Fail; +#endif +FailUnknownDevice: +#ifdef DEBUG_USB_HOST + NotifyFailUnknownDevice(VID, PID); +#endif + rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + +Fail: +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nXbox Init Failed, error code: "), 0x80); + NotifyFail(rcode); +#endif + Release(); + return rcode; +} + +/* Performs a cleanup after failed Init() attempt */ +uint8_t XBOXUSBOLD::Release() { + XboxConnected = false; + pUsb->GetAddressPool().FreeAddress(bAddress); + bAddress = 0; + bPollEnable = false; + return 0; +} + +uint8_t XBOXUSBOLD::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(BUFFER_SIZE); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller +#endif + return 0; +} + +void XBOXUSBOLD::readReport() { + ButtonState = readBuf[2]; + + for (uint8_t i = 0; i < sizeof(buttonValues); i++) + buttonValues[i] = readBuf[i + 4]; // A, B, X, Y, BLACK, WHITE, L1, and R1 + + hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[12] << 8) | readBuf[13]); + hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[14] << 8) | readBuf[15]); + hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[16] << 8) | readBuf[17]); + hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[18] << 8) | readBuf[19]); + + //Notify(PSTR("\r\nButtonState"), 0x80); + //PrintHex(ButtonState, 0x80); + + if (ButtonState != OldButtonState || memcmp(buttonValues, oldButtonValues, sizeof(buttonValues)) != 0) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; + + for (uint8_t i = 0; i < sizeof(buttonValues); i++) { + if (oldButtonValues[i] == 0 && buttonValues[i] != 0) + buttonClicked[i] = true; // Update A, B, X, Y, BLACK, WHITE, L1, and R1 click state + oldButtonValues[i] = buttonValues[i]; + } + } +} + +void XBOXUSBOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller +#ifdef PRINTREPORT + if (readBuf == NULL) + return; + for (uint8_t i = 0; i < length; i++) { + D_PrintHex (readBuf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); +#endif +} + +uint8_t XBOXUSBOLD::getButtonPress(Button b) { + if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons + return buttonValues[pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])]; // Analog buttons + return (ButtonState & pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])); // Digital buttons +} + +bool XBOXUSBOLD::getButtonClick(Button b) { + uint8_t button; + if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons + button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); + if (buttonClicked[button]) + buttonClicked[button] = false; + return buttonClicked[button]; + } + + button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); // Digital buttons + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // clear "click" event + return click; +} + +int16_t XBOXUSBOLD::getAnalogHat(AnalogHat a) { + return hatValue[a]; +} + +/* Xbox Controller commands */ +void XBOXUSBOLD::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 XBOXUSBOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) { + writeBuf[0] = 0x00; + writeBuf[1] = 0x06; + writeBuf[2] = 0x00; + writeBuf[3] = rValue; // small weight + writeBuf[4] = 0x00; + writeBuf[5] = lValue; // big weight + + XboxCommand(writeBuf, 6); +} \ No newline at end of file diff --git a/XBOXUSBOLD.h b/XBOXUSBOLD.h new file mode 100644 index 00000000..ba117e88 --- /dev/null +++ b/XBOXUSBOLD.h @@ -0,0 +1,196 @@ +/* Copyright (C) 2013 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 _xboxusbold_h_ +#define _xboxusbold_h_ + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +#include "Usb.h" + #include "controllerEnums.h" + +/* Data Xbox 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 Xbox 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_OLD_PID 0x0289 // The original Xbox controller + +#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers +#define JOYTECH_VID 0x162E // For unofficial Joytech controllers + +// 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 + +/** This class implements support for a Xbox wired controller via USB. */ +class XBOXUSBOLD : public USBDeviceConfig { +public: + /** + * Constructor for the XBOXUSB class. + * @param pUsb Pointer to USB class instance. + */ + XBOXUSBOLD(USB *pUsb); + + /** @name USBDeviceConfig implementation */ + /** + * Initialize the Xbox Controller. + * @param parent Hub number. + * @param port Port number on the hub. + * @param lowspeed Speed of the device. + * @return 0 on success. + */ + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + /** + * Release the USB device. + * @return 0 on success. + */ + virtual uint8_t Release(); + /** + * Poll the USB Input endpoins and run the state machines. + * @return 0 on success. + */ + virtual uint8_t Poll(); + + /** + * Get the device address. + * @return The device address. + */ + virtual uint8_t GetAddress() { + return bAddress; + }; + + /** + * Used to check if the controller has been initialized. + * @return True if it's ready. + */ + virtual bool isReady() { + return bPollEnable; + }; + + /** + * Used by the USB core to check what this driver support. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this driver. + */ + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && pid == XBOX_OLD_PID); + }; + /**@}*/ + + /** @name Xbox Controller functions */ + /** + * getButtonPress(Button b) will return true as long as the button is held down. + * + * While getButtonClick(Button b) will only return it once. + * + * So you instance if you need to increase a variable once you would use getButtonClick(Button b), + * but if you need to drive a robot forward you would use getButtonPress(Button b). + * @param b ::Button to read. + * @return getButtonClick(Button b) will return a bool, but getButtonPress(Button b) + * will return a byte if reading ::L2 or ::R2. + */ + uint8_t getButtonPress(Button b); + bool getButtonClick(Button b); + /**@}*/ + + /** @name Xbox Controller functions */ + /** + * Return the analog value from the joysticks on the controller. + * @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY. + * @return Returns a signed 16-bit integer. + */ + int16_t getAnalogHat(AnalogHat a); + + /** Turn rumble off the controller. */ + void setRumbleOff() { + setRumbleOn(0, 0); + }; + /** + * Turn rumble on. + * @param lValue Left motor (big weight) inside the controller. + * @param rValue Right motor (small weight) inside the controller. + */ + void setRumbleOn(uint8_t lValue, uint8_t rValue); + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + /**@}*/ + + /** True if a Xbox controller is connected. */ + bool XboxConnected; + +protected: + /** Pointer to USB class instance. */ + USB *pUsb; + /** Device address. */ + uint8_t bAddress; + /** Endpoint info structure. */ + EpInfo epInfo[XBOX_MAX_ENDPOINTS]; + +private: + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + + bool bPollEnable; + + /* Variables to store the digital buttons */ + uint8_t ButtonState; + uint8_t OldButtonState; + uint8_t ButtonClickState; + + /* Variables to store the analog buttons */ + uint8_t buttonValues[8]; // A, B, X, Y, BLACK, WHITE, L1, and R1 + uint8_t oldButtonValues[8]; + bool buttonClicked[8]; + + int16_t hatValue[4]; // Joystick values + + 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(uint16_t length); // Print incoming date + + /* Private commands */ + void XboxCommand(uint8_t* data, uint16_t nbytes); +}; +#endif \ No newline at end of file diff --git a/controllerEnums.h b/controllerEnums.h index 5e35a268..5e0d6dc8 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -100,6 +100,8 @@ enum Button { Y = 15, XBOX = 16, SYNC = 17, + BLACK = 8, // Available on the original Xbox controller + WHITE = 9, // Available on the original Xbox controller /**@}*/ }; diff --git a/examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino b/examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino new file mode 100644 index 00000000..317e71f9 --- /dev/null +++ b/examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino @@ -0,0 +1,97 @@ +/* + Example sketch for the original Xbox 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; +XBOXUSBOLD 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 Library Started")); +} +void loop() { + Usb.Task(); + if(Xbox.XboxConnected) { + if(Xbox.getButtonPress(BLACK) || Xbox.getButtonPress(WHITE)) { + Serial.print("BLACK: "); + Serial.print(Xbox.getButtonPress(BLACK)); + Serial.print("\tWHITE: "); + Serial.println(Xbox.getButtonPress(WHITE)); + Xbox.setRumbleOn(Xbox.getButtonPress(BLACK),Xbox.getButtonPress(WHITE)); + } else + Xbox.setRumbleOn(0,0); + 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.getButtonClick(UP)) + Serial.println(F("Up")); + if(Xbox.getButtonClick(DOWN)) + Serial.println(F("Down")); + if(Xbox.getButtonClick(LEFT)) + Serial.println(F("Left")); + if(Xbox.getButtonClick(RIGHT)) + Serial.println(F("Right")); + + if(Xbox.getButtonClick(START)) + Serial.println(F("Start")); + if(Xbox.getButtonClick(BACK)) + Serial.println(F("Back")); + if(Xbox.getButtonClick(L3)) + Serial.println(F("L3")); + if(Xbox.getButtonClick(R3)) + Serial.println(F("R3")); + + if(Xbox.getButtonPress(A)) { + Serial.print(F("A: ")); + Serial.println(Xbox.getButtonPress(A)); + } + if(Xbox.getButtonPress(B)) { + Serial.print(F("B: ")); + Serial.println(Xbox.getButtonPress(B)); + } + if(Xbox.getButtonPress(X)) { + Serial.print(F("X: ")); + Serial.println(Xbox.getButtonPress(X)); + } + if(Xbox.getButtonPress(Y)) { + Serial.print(F("Y: ")); + Serial.println(Xbox.getButtonPress(Y)); + } + if(Xbox.getButtonPress(L1)) { + Serial.print(F("L1: ")); + Serial.println(Xbox.getButtonPress(L1)); + } + if(Xbox.getButtonPress(R1)) { + Serial.print(F("R1: ")); + Serial.println(Xbox.getButtonPress(R1)); + } + } + delay(1); +} diff --git a/keywords.txt b/keywords.txt index 2575d9a1..bee73590 100644 --- a/keywords.txt +++ b/keywords.txt @@ -164,6 +164,7 @@ RumbleLow LITERAL1 #################################################### XBOXUSB KEYWORD1 +XBOXUSBOLD KEYWORD1 XBOXRECV KEYWORD1 #################################################### @@ -195,6 +196,9 @@ BACK LITERAL1 XBOX LITERAL1 SYNC LITERAL1 +BLACK LITERAL1 +WHITE LITERAL1 + A LITERAL1 B LITERAL1 X LITERAL1 From 6039f1af4bbeea6fc78345cecf2abf862c31443e Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 18:21:44 +0200 Subject: [PATCH 16/32] Xbox libraries doesn't collide anymore PIDs for original Xbox controller is from: https://github.com/torvalds/linux/blob/acdb37c361dc87e165889a504e291c1e82ae133c/drivers/input/joystick/xpad.c#L119 --- XBOXRECV.cpp | 4 ++-- XBOXRECV.h | 6 +++--- XBOXUSB.cpp | 5 +++-- XBOXUSB.h | 9 +++++---- XBOXUSBOLD.cpp | 2 +- XBOXUSBOLD.h | 9 ++++++--- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/XBOXRECV.cpp b/XBOXRECV.cpp index 8a90aa97..3784f25a 100644 --- a/XBOXRECV.cpp +++ b/XBOXRECV.cpp @@ -94,9 +94,9 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) { VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; - if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a xbox receiver using the Vendor ID + if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a Xbox receiver using the Vendor ID goto FailUnknownDevice; - else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { + else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { // Check the PID as well #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80); #endif diff --git a/XBOXRECV.h b/XBOXRECV.h index 2425f8ac..13c8df58 100644 --- a/XBOXRECV.h +++ b/XBOXRECV.h @@ -48,12 +48,12 @@ // PID and VID of the different devices #define XBOX_VID 0x045E // Microsoft Corporation -#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver -#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver - #define MADCATZ_VID 0x1BAD // For unofficial Mad Catz receivers #define JOYTECH_VID 0x162E // For unofficial Joytech controllers +#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_MAX_ENDPOINTS 9 /** diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp index 461bf894..4469b7fc 100644 --- a/XBOXUSB.cpp +++ b/XBOXUSB.cpp @@ -92,7 +92,7 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; - if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) // We just check if it's a xbox controller using the Vendor ID + if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) // Check VID goto FailUnknownDevice; if (PID == XBOX_WIRELESS_PID) { #ifdef DEBUG_USB_HOST @@ -104,7 +104,8 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80); #endif goto FailUnknownDevice; - } + } else if (PID != XBOX_WIRED_PID) // Check PID + goto FailUnknownDevice; // Allocate new address according to device class bAddress = addrPool.AllocAddress(parent, false, port); diff --git a/XBOXUSB.h b/XBOXUSB.h index 7c866b8c..85b94cd1 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -40,13 +40,14 @@ // PID and VID of the different devices #define XBOX_VID 0x045E // Microsoft Corporation +#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers +#define JOYTECH_VID 0x162E // For unofficial Joytech controllers + +#define XBOX_WIRED_PID 0x028E // Microsoft 360 Wired controller #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 MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers -#define JOYTECH_VID 0x162E // For unofficial Joytech controllers - #define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer // Used in control endpoint header for HID Commands @@ -107,7 +108,7 @@ public: * @return Returns true if the device's VID and PID matches this driver. */ virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { - return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && pid != XBOX_WIRELESS_RECEIVER_PID && pid != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID); + return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && pid == XBOX_WIRED_PID); }; /**@}*/ diff --git a/XBOXUSBOLD.cpp b/XBOXUSBOLD.cpp index 22226cd9..f74b600d 100644 --- a/XBOXUSBOLD.cpp +++ b/XBOXUSBOLD.cpp @@ -116,7 +116,7 @@ uint8_t XBOXUSBOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) { VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; - if ((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || PID != XBOX_OLD_PID) // We just check if it's a xbox controller using the Vendor ID + if ((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_OLD_PID1 && PID != XBOX_OLD_PID2 && PID != XBOX_OLD_PID3 && PID != XBOX_OLD_PID4)) // Check if VID and PID match goto FailUnknownDevice; // Allocate new address according to device class diff --git a/XBOXUSBOLD.h b/XBOXUSBOLD.h index ba117e88..117ac1c2 100644 --- a/XBOXUSBOLD.h +++ b/XBOXUSBOLD.h @@ -40,11 +40,14 @@ // PID and VID of the different devices #define XBOX_VID 0x045E // Microsoft Corporation -#define XBOX_OLD_PID 0x0289 // The original Xbox controller - #define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers #define JOYTECH_VID 0x162E // For unofficial Joytech controllers +#define XBOX_OLD_PID1 0x0202 // Original Microsoft Xbox controller (US) +#define XBOX_OLD_PID2 0x0285 // Original Microsoft Xbox controller (Japan) +#define XBOX_OLD_PID3 0x0287 // Microsoft Microsoft Xbox Controller S +#define XBOX_OLD_PID4 0x0289 // Smaller Microsoft Xbox controller (US) + // 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 @@ -103,7 +106,7 @@ public: * @return Returns true if the device's VID and PID matches this driver. */ virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { - return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && pid == XBOX_OLD_PID); + return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && (pid == XBOX_OLD_PID1 || pid == XBOX_OLD_PID2 || pid == XBOX_OLD_PID3 || pid == XBOX_OLD_PID4)); }; /**@}*/ From d0ec18ab44023d3e3d809f11ed0279911ec90043 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 19:43:21 +0200 Subject: [PATCH 17/32] Fixed disconnect problem when using the old Wiimote with the external MotionPlus extension Now also updates the batteryLevel when getBatteryLevel is called --- Wii.cpp | 101 ++++++++++-------- Wii.h | 18 ++-- .../Bluetooth/WiiIRCamera/WiiIRCamera.ino | 12 +-- examples/Bluetooth/WiiMulti/WiiMulti.ino | 1 - 4 files changed, 72 insertions(+), 60 deletions(-) diff --git a/Wii.cpp b/Wii.cpp index 751bdd9b..7d5a869b 100755 --- a/Wii.cpp +++ b/Wii.cpp @@ -14,9 +14,7 @@ Web : http://www.tkjelectronics.com e-mail : kristianl@tkjelectronics.com - IR camera support added by: - Allan Glover - adglover9.81@gmail.com + IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus */ #include "Wii.h" @@ -109,7 +107,7 @@ void WII::Reset() { activateNunchuck = false; motionValuesReset = false; activeConnection = false; - pBtd->motionPlusInside = false; + motionPlusInside = false; pBtd->wiiUProController = false; wiiUProControllerConnected = false; l2cap_event_flag = 0; // Reset flags @@ -117,13 +115,17 @@ void WII::Reset() { } void WII::disconnect() { // Use this void to disconnect any of the controllers - if (motionPlusConnected && !pBtd->motionPlusInside) { // Disable the Motion Plus extension + if (!motionPlusInside) { // The old Wiimote needs a delay after the first command or it will automatically reconnect + if (motionPlusConnected) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80); + Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80); #endif - initExtension1(); // This will disable the Motion Plus extension - } - //First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection + initExtension1(); // This will disable the Motion Plus extension + } + timer = millis() + 1000; // We have to wait for the message before the rest of the channels can be deactivated + } else + timer = millis(); // Don't wait + // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection pBtd->l2cap_disconnection_request(hci_handle, 0x0A, interrupt_scid, interrupt_dcid); Reset(); l2cap_state = L2CAP_INTERRUPT_DISCONNECT; @@ -133,6 +135,7 @@ void WII::ACLData(uint8_t* l2capinbuf) { if (!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) { if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { + motionPlusInside = pBtd->motionPlusInside; pBtd->incomingWii = false; pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service activeConnection = true; @@ -254,7 +257,6 @@ void WII::ACLData(uint8_t* l2capinbuf) { #endif } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80); - if (wiimoteConnected) { if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes @@ -291,47 +293,51 @@ void WII::ACLData(uint8_t* l2capinbuf) { } switch (l2capinbuf[9]) { case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV +#ifdef EXTRADEBUG + Notify(PSTR("\r\nStatus report was received"), 0x80); +#endif wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) batteryLevel = l2capinbuf[15]; // Update battery level - if (l2capinbuf[12] & 0x01) { #ifdef DEBUG_USB_HOST + if (l2capinbuf[12] & 0x01) Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80); #endif - } - if (l2capinbuf[12] & 0x02) { // Check if a extension is connected + if (checkExtension) { // If this is false it means that the user must have called getBatteryLevel() + if (l2capinbuf[12] & 0x02) { // Check if a extension is connected #ifdef DEBUG_USB_HOST - if (!unknownExtensionConnected) - Notify(PSTR("\r\nExtension connected"), 0x80); + if (!unknownExtensionConnected) + Notify(PSTR("\r\nExtension connected"), 0x80); #endif - unknownExtensionConnected = true; + unknownExtensionConnected = true; #ifdef WIICAMERA if (!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera #endif setReportMode(false, 0x35); // Also read the extension - } else { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nExtension disconnected"), 0x80); -#endif - if (motionPlusConnected) { -#ifdef DEBUG_USB_HOST - Notify(PSTR(" - from Motion Plus"), 0x80); -#endif - l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - if (!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false - nunchuckConnected = false; - //else if(classicControllerConnected) - } else if (nunchuckConnected) { -#ifdef DEBUG_USB_HOST - Notify(PSTR(" - Nunchuck"), 0x80); -#endif - nunchuckConnected = false; // It must be the Nunchuck controller then - l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - onInit(); - setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer } else { - setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nExtension disconnected"), 0x80); +#endif + if (motionPlusConnected) { +#ifdef DEBUG_USB_HOST + Notify(PSTR(" - from Motion Plus"), 0x80); +#endif + l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; + if (!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false + nunchuckConnected = false; + //else if(classicControllerConnected) + } else if (nunchuckConnected) { +#ifdef DEBUG_USB_HOST + Notify(PSTR(" - Nunchuck"), 0x80); +#endif + nunchuckConnected = false; // It must be the Nunchuck controller then + l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; + onInit(); + setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer + } else + setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer } - } + } else + checkExtension = true; // Check for extensions by default break; case 0x21: // Read Memory Data if ((l2capinbuf[12] & 0x0F) == 0) { // No error @@ -351,6 +357,7 @@ void WII::ACLData(uint8_t* l2capinbuf) { Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80); #endif motionPlusConnected = true; + setReportMode(false, 0x35); // Also read the extension } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80); @@ -358,6 +365,7 @@ void WII::ACLData(uint8_t* l2capinbuf) { activateNunchuck = false; motionPlusConnected = true; nunchuckConnected = true; + setReportMode(false, 0x35); // Also read the extension } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80); @@ -572,7 +580,6 @@ void WII::ACLData(uint8_t* l2capinbuf) { #endif } } - } } L2CAP_task(); } @@ -647,7 +654,6 @@ void WII::L2CAP_task() { #endif pBtd->connectToWii = false; pBtd->pairWithWii = false; - wiimoteConnected = true; stateCounter = 0; l2cap_state = L2CAP_CHECK_MOTION_PLUS_STATE; } @@ -656,7 +662,7 @@ void WII::L2CAP_task() { /* The next states are in run() */ case L2CAP_INTERRUPT_DISCONNECT: - if (l2cap_disconnect_response_interrupt_flag) { + if (l2cap_disconnect_response_interrupt_flag && millis() > timer) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80); #endif @@ -681,11 +687,15 @@ void WII::L2CAP_task() { } void WII::Run() { + if (l2cap_state == L2CAP_INTERRUPT_DISCONNECT && millis() > timer) + L2CAP_task(); // Call the rest of the disconnection routine after we have waited long enough + switch (l2cap_state) { case L2CAP_WAIT: if (pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) { pBtd->l2capConnectionClaimed = true; activeConnection = true; + motionPlusInside = pBtd->motionPlusInside; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80); #endif @@ -779,6 +789,7 @@ void WII::Run() { case L2CAP_LED_STATE: if (nunchuck_connected_flag) nunchuckConnected = true; + wiimoteConnected = true; onInit(); l2cap_state = L2CAP_DONE; break; @@ -839,7 +850,7 @@ void WII::Run() { /************************************************************/ void WII::HID_Command(uint8_t* data, uint8_t nbytes) { - if (pBtd->motionPlusInside) + if (motionPlusInside) pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // It's the new wiimote with the Motion Plus Inside else pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); @@ -905,6 +916,12 @@ void WII::setLedStatus() { HID_Command(HIDBuffer, 3); } +uint8_t WII::getBatteryLevel() { + checkExtension = false; // This is needed so the library knows that the status response is a response to this function + statusRequest(); // This will update the battery level + return batteryLevel; +}; + void WII::setReportMode(bool continuous, uint8_t mode) { uint8_t cmd_buf[4]; cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) diff --git a/Wii.h b/Wii.h index 60c9f07e..33623f2a 100755 --- a/Wii.h +++ b/Wii.h @@ -14,9 +14,7 @@ Web : http://www.tkjelectronics.com e-mail : kristianl@tkjelectronics.com - IR camera support added by: - Allan Glover - adglover9.81@gmail.com + IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus */ #ifndef _wii_h_ @@ -215,17 +213,11 @@ public: */ void setLedStatus(); - /** - * Call this to update battery level and Wiimote state - */ - void statusRequest(); /** * Return the battery level of the Wiimote. * @return The battery level in the range 0-255. */ - uint8_t getBatteryLevel() { - return batteryLevel; - }; + uint8_t getBatteryLevel(); /** * Return the Wiimote state. * @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status. @@ -456,6 +448,8 @@ private: uint16_t stateCounter; bool unknownExtensionConnected; bool extensionConnected; + bool checkExtension; // Set to false when getBatteryLevel() is called otherwise if should be true + bool motionPlusInside; // True if it's a new Wiimote with the Motion Plus extension build into it /* L2CAP Channels */ uint8_t control_scid[2]; // L2CAP source CID for HID_Control @@ -472,6 +466,8 @@ private: void initExtension1(); void initExtension2(); + void statusRequest(); // Used to update the Wiimote state and battery level + void readData(uint32_t offset, uint16_t size, bool EEPROM); void readExtensionType(); void readCalData(); @@ -491,7 +487,7 @@ private: uint8_t batteryLevel; #ifdef WIICAMERA - /* Private function and variables for the readings from teh IR Camera */ + /* Private function and variables for the readings from the IR Camera */ void enableIRCamera1(); // Sets bit 2 of output report 13 void enableIRCamera2(); // Sets bit 2 of output report 1A void writeSensitivityBlock1(); diff --git a/examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino b/examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino index 67589475..720deaa6 100644 --- a/examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino +++ b/examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino @@ -2,13 +2,13 @@ Example sketch for the Wii libary showing the IR camera functionality. This example is for the Bluetooth Wii library developed for the USB shield from Circuits@Home -Created by Allan Glover and includes much from what Kristian Lauszus wrote in the existing -Wii example. Contact Kristian: http://blog.tkjelectronics.dk/ or send email at kristianl@tkjelectronics.com. +Created by Allan Glover and Kristian Lauszus. +Contact Kristian: http://blog.tkjelectronics.dk/ or send an email at kristianl@tkjelectronics.com. Contact Allan at adglover9.81@gmail.com To test the Wiimote IR camera, you will need access to an IR source. Sunlight will work but is not ideal. -The simpleist solution is to use the Wii sensor bar, i.e. emitter bar, supplied by the Wii system. Otherwise, -wire up a IR LED yourself. +The simpleist solution is to use the Wii sensor bar, i.e. emitter bar, supplied by the Wii system. +Otherwise, wire up a IR LED yourself. */ #include @@ -19,7 +19,7 @@ USB Usb; BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so /* You can create the instance of the class in two ways */ WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once -//WII Wii(&Btd); // After the wiimote pairs once with the line of code above, you can simply create the instance like so and re upload and then press any button on the Wiimote +//WII Wii(&Btd); // After the Wiimote pairs once with the line of code above, you can simply create the instance like so and re upload and then press any button on the Wiimote bool printAngle; uint8_t printObjects; @@ -109,7 +109,7 @@ void loop() { } } } - if(printAngle) { // There is no extension bytes avaliable, so the Motionplus or Nunchuck can't be read + if(printAngle) { // There is no extension bytes available, so the MotionPlus or Nunchuck can't be read Serial.print(F("\r\nPitch: ")); Serial.print(Wii.getPitch()); Serial.print(F("\tRoll: ")); diff --git a/examples/Bluetooth/WiiMulti/WiiMulti.ino b/examples/Bluetooth/WiiMulti/WiiMulti.ino index c9bac283..19813f19 100644 --- a/examples/Bluetooth/WiiMulti/WiiMulti.ino +++ b/examples/Bluetooth/WiiMulti/WiiMulti.ino @@ -35,7 +35,6 @@ void loop() { Serial.print(F("\r\nHOME")); Wii[i]->disconnect(); oldControllerState[i] = false; // Reset value - delay(1000); // This delay is needed for some Wiimotes, so it doesn't try to reconnect right away } else { if(Wii[i]->getButtonClick(LEFT)) { From 84a66bb5340840f93aec73eab5c1d3f373dff7f3 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 19:53:18 +0200 Subject: [PATCH 18/32] Fixed indent --- Wii.cpp | 638 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 319 insertions(+), 319 deletions(-) diff --git a/Wii.cpp b/Wii.cpp index 7d5a869b..367683d2 100755 --- a/Wii.cpp +++ b/Wii.cpp @@ -257,329 +257,329 @@ void WII::ACLData(uint8_t* l2capinbuf) { #endif } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80); - if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT - if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons - if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); - else if (wiiUProControllerConnected) - ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16)); - else if (motionPlusConnected) { - if (l2capinbuf[20] & 0x02) // Only update the wiimote buttons, since the extension bytes are from the Motion Plus - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000))); - else if (nunchuckConnected) // Update if it's a report from the Nunchuck - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14)); - //else if(classicControllerConnected) // Update if it's a report from the Classic Controller - } else if (nunchuckConnected) // The Nunchuck is directly connected - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16)); - //else if(classicControllerConnected) // The Classic Controller is directly connected - else if (!unknownExtensionConnected) - ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); + if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT + if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons + if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); + else if (wiiUProControllerConnected) + ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16)); + else if (motionPlusConnected) { + if (l2capinbuf[20] & 0x02) // Only update the wiimote buttons, since the extension bytes are from the Motion Plus + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000))); + else if (nunchuckConnected) // Update if it's a report from the Nunchuck + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14)); + //else if(classicControllerConnected) // Update if it's a report from the Classic Controller + } else if (nunchuckConnected) // The Nunchuck is directly connected + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16)); + //else if(classicControllerConnected) // The Classic Controller is directly connected + else if (!unknownExtensionConnected) + ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); #ifdef PRINTREPORT - Notify(PSTR("ButtonState: "), 0x80); - D_PrintHex (ButtonState, 0x80); - Notify(PSTR("\r\n"), 0x80); -#endif - if (ButtonState != OldButtonState) { - ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable - OldButtonState = ButtonState; - } - } - if (l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer - accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5)) - 500; - accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4)) - 500; - accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5)) - 500; - wiimotePitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; - wiimoteRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; - } - switch (l2capinbuf[9]) { - case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV -#ifdef EXTRADEBUG - Notify(PSTR("\r\nStatus report was received"), 0x80); -#endif - wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) - batteryLevel = l2capinbuf[15]; // Update battery level -#ifdef DEBUG_USB_HOST - if (l2capinbuf[12] & 0x01) - Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80); -#endif - if (checkExtension) { // If this is false it means that the user must have called getBatteryLevel() - if (l2capinbuf[12] & 0x02) { // Check if a extension is connected -#ifdef DEBUG_USB_HOST - if (!unknownExtensionConnected) - Notify(PSTR("\r\nExtension connected"), 0x80); -#endif - unknownExtensionConnected = true; -#ifdef WIICAMERA - if (!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera -#endif - setReportMode(false, 0x35); // Also read the extension - } else { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nExtension disconnected"), 0x80); -#endif - if (motionPlusConnected) { -#ifdef DEBUG_USB_HOST - Notify(PSTR(" - from Motion Plus"), 0x80); -#endif - l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - if (!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false - nunchuckConnected = false; - //else if(classicControllerConnected) - } else if (nunchuckConnected) { -#ifdef DEBUG_USB_HOST - Notify(PSTR(" - Nunchuck"), 0x80); -#endif - nunchuckConnected = false; // It must be the Nunchuck controller then - l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; - onInit(); - setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer - } else - setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer - } - } else - checkExtension = true; // Check for extensions by default - break; - case 0x21: // Read Memory Data - if ((l2capinbuf[12] & 0x0F) == 0) { // No error - // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers - if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nNunchuck connected"), 0x80); -#endif - l2cap_event_flag |= WII_FLAG_NUNCHUCK_CONNECTED; - } else if (l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nMotion Plus connected"), 0x80); -#endif - l2cap_event_flag |= WII_FLAG_MOTION_PLUS_CONNECTED; - } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80); -#endif - motionPlusConnected = true; - setReportMode(false, 0x35); // Also read the extension - } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80); -#endif - activateNunchuck = false; - motionPlusConnected = true; - nunchuckConnected = true; - setReportMode(false, 0x35); // Also read the extension - } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80); - Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80); -#endif - stateCounter = 300; // Skip the rest in "L2CAP_CHECK_MOTION_PLUS_STATE" - } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80); -#endif - wiiUProControllerConnected = true; - } -#ifdef DEBUG_USB_HOST - else { - Notify(PSTR("\r\nUnknown Device: "), 0x80); - D_PrintHex (l2capinbuf[13], 0x80); - D_PrintHex (l2capinbuf[14], 0x80); - Notify(PSTR("\r\nData: "), 0x80); - for (uint8_t i = 0; i < ((l2capinbuf[12] >> 4) + 1); i++) { // bit 4-7 is the length-1 - D_PrintHex (l2capinbuf[15 + i], 0x80); - Notify(PSTR(" "), 0x80); - } - } -#endif - } -#ifdef EXTRADEBUG - else { - Notify(PSTR("\r\nReport Error: "), 0x80); - D_PrintHex (l2capinbuf[13], 0x80); - D_PrintHex (l2capinbuf[14], 0x80); - } -#endif - break; - case 0x22: // Acknowledge output report, return function result -#ifdef DEBUG_USB_HOST - if (l2capinbuf[13] != 0x00) { // Check if there is an error - Notify(PSTR("\r\nCommand failed: "), 0x80); - D_PrintHex (l2capinbuf[12], 0x80); - } -#endif - break; - case 0x30: // Core buttons - (a1) 30 BB BB - break; - case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA - pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected - roll = wiimoteRoll; - break; - case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE - break; - case 0x33: // Core Buttons with Accelerometer and 12 IR bytes - (a1) 33 BB BB AA AA AA II II II II II II II II II II II II - pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus data available - roll = wiimoteRoll; -#ifdef WIICAMERA - // Read the IR data - IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position - IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position - IR_object_s1 = (l2capinbuf[17] & 0x0F); // size value, 0-15 - - IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4)); - IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2)); - IR_object_s2 = (l2capinbuf[20] & 0x0F); - - IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4)); - IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2)); - IR_object_s3 = (l2capinbuf[23] & 0x0F); - - IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4)); - IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2)); - IR_object_s4 = (l2capinbuf[26] & 0x0F); -#endif - break; - case 0x34: // Core Buttons with 19 Extension bytes - (a1) 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE - break; - /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */ - case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes - // (a1) 31 BB BB AA AA AA II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II - // corresponds to output report mode 0x3e - - /**** for reading in full mode: DOES NOT WORK YET ****/ - /* When it works it will also have intensity and bounding box data */ - /* - IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); - IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); - IR_object_s1 = (l2capinbuf[15] & 0x0F); - */ - break; - case 0x3F: - /* - IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); - IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); - IR_object_s1 = (l2capinbuf[15] & 0x0F); - */ - break; - case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes - // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE - if (motionPlusConnected) { - if (l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension - if (motionValuesReset) { // We will only use the values when the gyro value has been set - gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)) - gyroYawZero); - gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)) - gyroRollZero); - gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)) - gyroPitchZero); - - yawGyroSpeed = (double)gyroYawRaw / ((double)gyroYawZero / yawGyroScale); - rollGyroSpeed = -(double)gyroRollRaw / ((double)gyroRollZero / rollGyroScale); // We invert these values so they will fit the acc values - pitchGyroSpeed = (double)gyroPitchRaw / ((double)gyroPitchZero / pitchGyroScale); - - /* The onboard gyro has two ranges for slow and fast mode */ - if (!(l2capinbuf[18] & 0x02)) // Check if fast more is used - yawGyroSpeed *= 4.545; - if (!(l2capinbuf[18] & 0x01)) // Check if fast more is used - pitchGyroSpeed *= 4.545; - if (!(l2capinbuf[19] & 0x02)) // Check if fast more is used - rollGyroSpeed *= 4.545; - - pitch = (0.93 * (pitch + (pitchGyroSpeed * (double)(micros() - timer) / 1000000)))+(0.07 * wiimotePitch); // Use a complimentary filter to calculate the angle - roll = (0.93 * (roll + (rollGyroSpeed * (double)(micros() - timer) / 1000000)))+(0.07 * wiimoteRoll); - - gyroYaw += (yawGyroSpeed * ((double)(micros() - timer) / 1000000)); - gyroRoll += (rollGyroSpeed * ((double)(micros() - timer) / 1000000)); - gyroPitch += (pitchGyroSpeed * ((double)(micros() - timer) / 1000000)); - timer = micros(); - /* - // Uncomment these lines to tune the gyro scale variabels - Notify(PSTR("\r\ngyroYaw: "), 0x80); - Notify(gyroYaw, 0x80); - Notify(PSTR("\tgyroRoll: "), 0x80); - Notify(gyroRoll, 0x80); - Notify(PSTR("\tgyroPitch: "), 0x80); - Notify(gyroPitch, 0x80); - */ - /* - Notify(PSTR("\twiimoteRoll: "), 0x80); - Notify(wiimoteRoll, 0x80); - Notify(PSTR("\twiimotePitch: "), 0x80); - Notify(wiimotePitch, 0x80); - */ - } else { - if ((micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nThe gyro values has been reset"), 0x80); -#endif - gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)); - gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)); - gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)); - - rollGyroScale = 500; // You might need to adjust these - pitchGyroScale = 400; - yawGyroScale = 415; - - gyroYaw = 0; - gyroRoll = 0; - gyroPitch = 0; - - motionValuesReset = true; - timer = micros(); - } - } - } else { - if (nunchuckConnected) { - hatValues[HatX] = l2capinbuf[15]; - hatValues[HatY] = l2capinbuf[16]; - accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3)) - 416; - accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4)) - 416; - accZ = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5)) - 416; - nunchuckPitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; - nunchuckRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; - } - //else if(classicControllerConnected) { } - } - if (l2capinbuf[19] & 0x01) { - if (!extensionConnected) { - extensionConnected = true; - unknownExtensionConnected = true; -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80); -#endif - } - } else { - if (extensionConnected && !unknownExtensionConnected) { - extensionConnected = false; - unknownExtensionConnected = true; -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80); -#endif - nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent - } - } - - } else if (nunchuckConnected) { - hatValues[HatX] = l2capinbuf[15]; - hatValues[HatY] = l2capinbuf[16]; - accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2)) - 416; - accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4)) - 416; - accZ = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6)) - 416; - nunchuckPitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; - nunchuckRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; - - pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected - roll = wiimoteRoll; - } else if (wiiUProControllerConnected) { - hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8); - hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8); - hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8); - hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8); - } - break; -#ifdef DEBUG_USB_HOST - default: - Notify(PSTR("\r\nUnknown Report type: "), 0x80); - D_PrintHex (l2capinbuf[9], 0x80); - break; + Notify(PSTR("ButtonState: "), 0x80); + D_PrintHex (ButtonState, 0x80); + Notify(PSTR("\r\n"), 0x80); #endif + if (ButtonState != OldButtonState) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; } } + if (l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer + accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5)) - 500; + accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4)) - 500; + accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5)) - 500; + wiimotePitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; + wiimoteRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; + } + switch (l2capinbuf[9]) { + case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV +#ifdef EXTRADEBUG + Notify(PSTR("\r\nStatus report was received"), 0x80); +#endif + wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4) + batteryLevel = l2capinbuf[15]; // Update battery level +#ifdef DEBUG_USB_HOST + if (l2capinbuf[12] & 0x01) + Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80); +#endif + if (checkExtension) { // If this is false it means that the user must have called getBatteryLevel() + if (l2capinbuf[12] & 0x02) { // Check if a extension is connected +#ifdef DEBUG_USB_HOST + if (!unknownExtensionConnected) + Notify(PSTR("\r\nExtension connected"), 0x80); +#endif + unknownExtensionConnected = true; +#ifdef WIICAMERA + if (!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera +#endif + setReportMode(false, 0x35); // Also read the extension + } else { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nExtension disconnected"), 0x80); +#endif + if (motionPlusConnected) { +#ifdef DEBUG_USB_HOST + Notify(PSTR(" - from Motion Plus"), 0x80); +#endif + l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; + if (!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false + nunchuckConnected = false; + //else if(classicControllerConnected) + } else if (nunchuckConnected) { +#ifdef DEBUG_USB_HOST + Notify(PSTR(" - Nunchuck"), 0x80); +#endif + nunchuckConnected = false; // It must be the Nunchuck controller then + l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED; + onInit(); + setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer + } else + setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer + } + } else + checkExtension = true; // Check for extensions by default + break; + case 0x21: // Read Memory Data + if ((l2capinbuf[12] & 0x0F) == 0) { // No error + // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers + if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nNunchuck connected"), 0x80); +#endif + l2cap_event_flag |= WII_FLAG_NUNCHUCK_CONNECTED; + } else if (l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nMotion Plus connected"), 0x80); +#endif + l2cap_event_flag |= WII_FLAG_MOTION_PLUS_CONNECTED; + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80); +#endif + motionPlusConnected = true; + setReportMode(false, 0x35); // Also read the extension + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80); +#endif + activateNunchuck = false; + motionPlusConnected = true; + nunchuckConnected = true; + setReportMode(false, 0x35); // Also read the extension + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80); + Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80); +#endif + stateCounter = 300; // Skip the rest in "L2CAP_CHECK_MOTION_PLUS_STATE" + } else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80); +#endif + wiiUProControllerConnected = true; + } +#ifdef DEBUG_USB_HOST + else { + Notify(PSTR("\r\nUnknown Device: "), 0x80); + D_PrintHex (l2capinbuf[13], 0x80); + D_PrintHex (l2capinbuf[14], 0x80); + Notify(PSTR("\r\nData: "), 0x80); + for (uint8_t i = 0; i < ((l2capinbuf[12] >> 4) + 1); i++) { // bit 4-7 is the length-1 + D_PrintHex (l2capinbuf[15 + i], 0x80); + Notify(PSTR(" "), 0x80); + } + } +#endif + } +#ifdef EXTRADEBUG + else { + Notify(PSTR("\r\nReport Error: "), 0x80); + D_PrintHex (l2capinbuf[13], 0x80); + D_PrintHex (l2capinbuf[14], 0x80); + } +#endif + break; + case 0x22: // Acknowledge output report, return function result +#ifdef DEBUG_USB_HOST + if (l2capinbuf[13] != 0x00) { // Check if there is an error + Notify(PSTR("\r\nCommand failed: "), 0x80); + D_PrintHex (l2capinbuf[12], 0x80); + } +#endif + break; + case 0x30: // Core buttons - (a1) 30 BB BB + break; + case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA + pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected + roll = wiimoteRoll; + break; + case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE + break; + case 0x33: // Core Buttons with Accelerometer and 12 IR bytes - (a1) 33 BB BB AA AA AA II II II II II II II II II II II II + pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus data available + roll = wiimoteRoll; +#ifdef WIICAMERA + // Read the IR data + IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position + IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position + IR_object_s1 = (l2capinbuf[17] & 0x0F); // size value, 0-15 + + IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4)); + IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2)); + IR_object_s2 = (l2capinbuf[20] & 0x0F); + + IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4)); + IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2)); + IR_object_s3 = (l2capinbuf[23] & 0x0F); + + IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4)); + IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2)); + IR_object_s4 = (l2capinbuf[26] & 0x0F); +#endif + break; + case 0x34: // Core Buttons with 19 Extension bytes - (a1) 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE + break; + /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */ + case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes + // (a1) 31 BB BB AA AA AA II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II + // corresponds to output report mode 0x3e + + /**** for reading in full mode: DOES NOT WORK YET ****/ + /* When it works it will also have intensity and bounding box data */ + /* + IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); + IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); + IR_object_s1 = (l2capinbuf[15] & 0x0F); + */ + break; + case 0x3F: + /* + IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); + IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); + IR_object_s1 = (l2capinbuf[15] & 0x0F); + */ + break; + case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes + // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE + if (motionPlusConnected) { + if (l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension + if (motionValuesReset) { // We will only use the values when the gyro value has been set + gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)) - gyroYawZero); + gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)) - gyroRollZero); + gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)) - gyroPitchZero); + + yawGyroSpeed = (double)gyroYawRaw / ((double)gyroYawZero / yawGyroScale); + rollGyroSpeed = -(double)gyroRollRaw / ((double)gyroRollZero / rollGyroScale); // We invert these values so they will fit the acc values + pitchGyroSpeed = (double)gyroPitchRaw / ((double)gyroPitchZero / pitchGyroScale); + + /* The onboard gyro has two ranges for slow and fast mode */ + if (!(l2capinbuf[18] & 0x02)) // Check if fast more is used + yawGyroSpeed *= 4.545; + if (!(l2capinbuf[18] & 0x01)) // Check if fast more is used + pitchGyroSpeed *= 4.545; + if (!(l2capinbuf[19] & 0x02)) // Check if fast more is used + rollGyroSpeed *= 4.545; + + pitch = (0.93 * (pitch + (pitchGyroSpeed * (double)(micros() - timer) / 1000000)))+(0.07 * wiimotePitch); // Use a complimentary filter to calculate the angle + roll = (0.93 * (roll + (rollGyroSpeed * (double)(micros() - timer) / 1000000)))+(0.07 * wiimoteRoll); + + gyroYaw += (yawGyroSpeed * ((double)(micros() - timer) / 1000000)); + gyroRoll += (rollGyroSpeed * ((double)(micros() - timer) / 1000000)); + gyroPitch += (pitchGyroSpeed * ((double)(micros() - timer) / 1000000)); + timer = micros(); + /* + // Uncomment these lines to tune the gyro scale variabels + Notify(PSTR("\r\ngyroYaw: "), 0x80); + Notify(gyroYaw, 0x80); + Notify(PSTR("\tgyroRoll: "), 0x80); + Notify(gyroRoll, 0x80); + Notify(PSTR("\tgyroPitch: "), 0x80); + Notify(gyroPitch, 0x80); + */ + /* + Notify(PSTR("\twiimoteRoll: "), 0x80); + Notify(wiimoteRoll, 0x80); + Notify(PSTR("\twiimotePitch: "), 0x80); + Notify(wiimotePitch, 0x80); + */ + } else { + if ((micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nThe gyro values has been reset"), 0x80); +#endif + gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)); + gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)); + gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)); + + rollGyroScale = 500; // You might need to adjust these + pitchGyroScale = 400; + yawGyroScale = 415; + + gyroYaw = 0; + gyroRoll = 0; + gyroPitch = 0; + + motionValuesReset = true; + timer = micros(); + } + } + } else { + if (nunchuckConnected) { + hatValues[HatX] = l2capinbuf[15]; + hatValues[HatY] = l2capinbuf[16]; + accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3)) - 416; + accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4)) - 416; + accZ = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5)) - 416; + nunchuckPitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; + nunchuckRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; + } + //else if(classicControllerConnected) { } + } + if (l2capinbuf[19] & 0x01) { + if (!extensionConnected) { + extensionConnected = true; + unknownExtensionConnected = true; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80); +#endif + } + } else { + if (extensionConnected && !unknownExtensionConnected) { + extensionConnected = false; + unknownExtensionConnected = true; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80); +#endif + nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent + } + } + + } else if (nunchuckConnected) { + hatValues[HatX] = l2capinbuf[15]; + hatValues[HatY] = l2capinbuf[16]; + accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2)) - 416; + accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4)) - 416; + accZ = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6)) - 416; + nunchuckPitch = (atan2(accY, accZ) + PI) * RAD_TO_DEG; + nunchuckRoll = (atan2(accX, accZ) + PI) * RAD_TO_DEG; + + pitch = wiimotePitch; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected + roll = wiimoteRoll; + } else if (wiiUProControllerConnected) { + hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8); + hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8); + hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8); + hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8); + } + break; +#ifdef DEBUG_USB_HOST + default: + Notify(PSTR("\r\nUnknown Report type: "), 0x80); + D_PrintHex (l2capinbuf[9], 0x80); + break; +#endif + } + } } L2CAP_task(); } From f274fb7feee0982e1509b4452773ba5303a62e61 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 20:35:23 +0200 Subject: [PATCH 19/32] Renamed library --- XBOXUSBOLD.cpp => XBOXOLD.cpp | 26 +++++++++---------- XBOXUSBOLD.h => XBOXOLD.h | 14 +++++----- .../XBOXUSBOLD.ino => XBOXOLD/XBOXOLD.ino} | 4 +-- keywords.txt | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) rename XBOXUSBOLD.cpp => XBOXOLD.cpp (94%) rename XBOXUSBOLD.h => XBOXOLD.h (95%) rename examples/Xbox/{XBOXUSBOLD/XBOXUSBOLD.ino => XBOXOLD/XBOXOLD.ino} (98%) diff --git a/XBOXUSBOLD.cpp b/XBOXOLD.cpp similarity index 94% rename from XBOXUSBOLD.cpp rename to XBOXOLD.cpp index f74b600d..db600267 100644 --- a/XBOXUSBOLD.cpp +++ b/XBOXOLD.cpp @@ -15,10 +15,10 @@ e-mail : kristianl@tkjelectronics.com */ -#include "XBOXUSBOLD.h" +#include "XBOXOLD.h" // To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h //#define EXTRADEBUG // Uncomment to get even more debugging data -#define PRINTREPORT // Uncomment to print the report send by the Xbox controller +//#define PRINTREPORT // Uncomment to print the report send by the Xbox controller /** Buttons on the controllers */ const uint8_t XBOXOLDBUTTONS[] PROGMEM = { @@ -44,7 +44,7 @@ const uint8_t XBOXOLDBUTTONS[] PROGMEM = { 3, // Y }; -XBOXUSBOLD::XBOXUSBOLD(USB *p) : +XBOXOLD::XBOXOLD(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 @@ -59,7 +59,7 @@ bPollEnable(false) { // don't start polling before dongle is connected pUsb->RegisterDeviceClass(this); //set devConfig[] entry } -uint8_t XBOXUSBOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) { +uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) { uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; uint8_t rcode; UsbDevice *p = NULL; @@ -231,7 +231,7 @@ Fail: } /* Performs a cleanup after failed Init() attempt */ -uint8_t XBOXUSBOLD::Release() { +uint8_t XBOXOLD::Release() { XboxConnected = false; pUsb->GetAddressPool().FreeAddress(bAddress); bAddress = 0; @@ -239,7 +239,7 @@ uint8_t XBOXUSBOLD::Release() { return 0; } -uint8_t XBOXUSBOLD::Poll() { +uint8_t XBOXOLD::Poll() { if (!bPollEnable) return 0; uint16_t BUFFER_SIZE = EP_MAXPKTSIZE; @@ -251,7 +251,7 @@ uint8_t XBOXUSBOLD::Poll() { return 0; } -void XBOXUSBOLD::readReport() { +void XBOXOLD::readReport() { ButtonState = readBuf[2]; for (uint8_t i = 0; i < sizeof(buttonValues); i++) @@ -277,7 +277,7 @@ void XBOXUSBOLD::readReport() { } } -void XBOXUSBOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller +void XBOXOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller #ifdef PRINTREPORT if (readBuf == NULL) return; @@ -289,13 +289,13 @@ void XBOXUSBOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT #endif } -uint8_t XBOXUSBOLD::getButtonPress(Button b) { +uint8_t XBOXOLD::getButtonPress(Button b) { if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons return buttonValues[pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])]; // Analog buttons return (ButtonState & pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])); // Digital buttons } -bool XBOXUSBOLD::getButtonClick(Button b) { +bool XBOXOLD::getButtonClick(Button b) { uint8_t button; if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); @@ -310,17 +310,17 @@ bool XBOXUSBOLD::getButtonClick(Button b) { return click; } -int16_t XBOXUSBOLD::getAnalogHat(AnalogHat a) { +int16_t XBOXOLD::getAnalogHat(AnalogHat a) { return hatValue[a]; } /* Xbox Controller commands */ -void XBOXUSBOLD::XboxCommand(uint8_t* data, uint16_t nbytes) { +void XBOXOLD::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 XBOXUSBOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) { +void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) { writeBuf[0] = 0x00; writeBuf[1] = 0x06; writeBuf[2] = 0x00; diff --git a/XBOXUSBOLD.h b/XBOXOLD.h similarity index 95% rename from XBOXUSBOLD.h rename to XBOXOLD.h index 117ac1c2..3f49ee96 100644 --- a/XBOXUSBOLD.h +++ b/XBOXOLD.h @@ -15,8 +15,8 @@ e-mail : kristianl@tkjelectronics.com */ -#ifndef _xboxusbold_h_ -#define _xboxusbold_h_ +#ifndef _xboxold_h_ +#define _xboxold_h_ #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" @@ -28,7 +28,7 @@ #include "controllerEnums.h" /* Data Xbox taken from descriptors */ -#define EP_MAXPKTSIZE 32 // max size for data via USB +#define EP_MAXPKTSIZE 32 // Max size for data via USB /* Endpoint types */ #define EP_INTERRUPT 0x03 @@ -54,14 +54,14 @@ #define XBOX_MAX_ENDPOINTS 3 -/** This class implements support for a Xbox wired controller via USB. */ -class XBOXUSBOLD : public USBDeviceConfig { +/** This class implements support for a the original Xbox controller via USB. */ +class XBOXOLD : public USBDeviceConfig { public: /** - * Constructor for the XBOXUSB class. + * Constructor for the XBOXOLD class. * @param pUsb Pointer to USB class instance. */ - XBOXUSBOLD(USB *pUsb); + XBOXOLD(USB *pUsb); /** @name USBDeviceConfig implementation */ /** diff --git a/examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino b/examples/Xbox/XBOXOLD/XBOXOLD.ino similarity index 98% rename from examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino rename to examples/Xbox/XBOXOLD/XBOXOLD.ino index 317e71f9..36f121f1 100644 --- a/examples/Xbox/XBOXUSBOLD/XBOXUSBOLD.ino +++ b/examples/Xbox/XBOXOLD/XBOXOLD.ino @@ -4,9 +4,9 @@ send me an e-mail: kristianl@tkjelectronics.com */ -#include +#include USB Usb; -XBOXUSBOLD Xbox(&Usb); +XBOXOLD Xbox(&Usb); void setup() { Serial.begin(115200); diff --git a/keywords.txt b/keywords.txt index bee73590..bdd899c7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -164,7 +164,7 @@ RumbleLow LITERAL1 #################################################### XBOXUSB KEYWORD1 -XBOXUSBOLD KEYWORD1 +XBOXOLD KEYWORD1 XBOXRECV KEYWORD1 #################################################### From 40f9b44aef4fb3fac8c378eb7edef74ea638d28f Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 20:37:32 +0200 Subject: [PATCH 20/32] Added information about original Xbox controller and some other improvements to the readme --- README.md | 59 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index f1095b3f..7bf4d101 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir * __Alexei Glushchenko, Circuits@Home__ - * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries * __Kristian Lauszus, TKJ Electronics__ - - * Developer of the BTD, SPP, PS3, Wii, and Xbox libraries + * Developer of the [BTD](#Bluetooth), [SPP](#SPP), [PS3](#PS3), [Wii](#Wii), and [Xbox](#Xbox) libraries * __Andrew Kroll__ - * Major contributor to mass storage code @@ -53,23 +53,27 @@ For more information visit the following site: . +### Enable debugging + +By default serial debugging is disabled. To turn it on uncomment ```DEBUG_USB_HOST``` in [message.h](message.h). + ### Arduino ADK -To use this library with the official [Arduino ADK](http://arduino.cc/en/Main/ArduinoBoardADK) uncomment the following line in [avrpins.h](https://github.com/felis/USB_Host_Shield_2.0/blob/master/avrpins.h): +To use this library with the official [Arduino ADK](http://arduino.cc/en/Main/ArduinoBoardADK) uncomment the following line in [avrpins.h](avrpins.h): - -\#define BOARD\_MEGA_ADK - +``` +#define BOARD_MEGA_ADK +``` -### [Bluetooth libraries](https://github.com/felis/USB_Host_Shield_2.0/blob/master/BTD.cpp) +### [Bluetooth libraries](BTD.cpp) -The [BTD library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle. +The [BTD library](BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle. This library make it easy to add support for different Bluetooth services like a PS3 or a Wii controller or SPP which is a virtual serial port via Bluetooth. -Some different examples can be found in the [example directory](https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/Bluetooth). +Some different examples can be found in the [example directory](examples/Bluetooth). The BTD library will also make it possible to use multiple services at once, the following example sketch is an example of this: -### [SPP library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/SPP.cpp) +### [SPP library](SPP.cpp) SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth. It has been tested successfully on Windows, Mac OS X, Linux, and Android. @@ -82,9 +86,9 @@ More information can be found at these blog posts: To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple. It enables me to see the Bluetooth communication between my Mac and any device. -### PS3 Library +### PS3 Library -These libraries consist of the [PS3BT](https://github.com/felis/USB_Host_Shield_2.0/blob/master/PS3BT.cpp) and [PS3USB](https://github.com/felis/USB_Host_Shield_2.0/blob/master/PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB. +These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB. In order to use your Playstation controller via Bluetooth you have to set the Bluetooth address of the dongle internally to your PS3 Controller. This can be achieved by plugging the controller in via USB and letting the library set it automatically. @@ -110,15 +114,30 @@ Also a big thanks all the people behind these sites about the Motion controller: * * -### Xbox 360 Library +### Xbox Libraries + +The library supports both the original Xbox controller via USB and the Xbox 360 controller both via USB and wirelessly. + +#### Xbox library + +The [XBOXOLD](XBOXOLD.cpp) class implements support for the original Xbox controller via USB. + +All the information are from the following sites: + +* +* +* +* + +#### Xbox 360 Library The library support one Xbox 360 via USB or up to four Xbox 360 controllers wirelessly by using a [Xbox 360 wireless receiver](http://blog.tkjelectronics.dk/wp-content/uploads/xbox360-wireless-receiver.jpg). -To use it via USB use the [XBOXUSB](https://github.com/felis/USB_Host_Shield_2.0/blob/master/XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](https://github.com/felis/USB_Host_Shield_2.0/blob/master/XBOXRECV.cpp) library. +To use it via USB use the [XBOXUSB](XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](XBOXRECV.cpp) library. __Note that a Wireless controller can NOT be used via USB!__ -Examples code can be found in the [examples directory](https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/Xbox). +Examples code can be found in the [examples directory](examples/Xbox). Also see the following blog posts: @@ -132,23 +151,23 @@ All the information regarding the Xbox 360 controller protocol are form these si * * -### [Wii library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/Wii.cpp) +### [Wii library](Wii.cpp) -The [Wii](https://github.com/felis/USB_Host_Shield_2.0/blob/master/Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth. +The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth. First you have to pair with the controller, this is done automatically by the library if you create the instance like so: - +``` WII Wii(&Btd,PAIR); - +``` And then press 1 & 2 at once on the Wiimote or press sync if you are using a Wii U Pro Controller. After that you can simply create the instance like so: - +``` WII Wii(&Btd); - +``` Then just press any button any button on the Wiimote and it will connect to the dongle. From ae1d782a3220721dbdbd170ee6c4ae873fde957f Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 20:43:23 +0200 Subject: [PATCH 21/32] Fixed links to headers My viewer doesn't work exactly the same way as Github --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7bf4d101..40ad39e3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir * __Alexei Glushchenko, Circuits@Home__ - * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries * __Kristian Lauszus, TKJ Electronics__ - - * Developer of the [BTD](#Bluetooth), [SPP](#SPP), [PS3](#PS3), [Wii](#Wii), and [Xbox](#Xbox) libraries + * Developer of the [BTD](#bluetooth-libraries), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries * __Andrew Kroll__ - * Major contributor to mass storage code @@ -64,7 +64,7 @@ To use this library with the official [Arduino ADK](http://arduino.cc/en/Main/Ar #define BOARD_MEGA_ADK ``` -### [Bluetooth libraries](BTD.cpp) +### [Bluetooth libraries](BTD.cpp) The [BTD library](BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle. This library make it easy to add support for different Bluetooth services like a PS3 or a Wii controller or SPP which is a virtual serial port via Bluetooth. @@ -73,7 +73,7 @@ Some different examples can be found in the [example directory](examples/Bluetoo The BTD library will also make it possible to use multiple services at once, the following example sketch is an example of this: -### [SPP library](SPP.cpp) +### [SPP library](SPP.cpp) SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth. It has been tested successfully on Windows, Mac OS X, Linux, and Android. @@ -86,7 +86,7 @@ More information can be found at these blog posts: To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple. It enables me to see the Bluetooth communication between my Mac and any device. -### PS3 Library +### PS3 Library These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB. @@ -114,7 +114,7 @@ Also a big thanks all the people behind these sites about the Motion controller: * * -### Xbox Libraries +### Xbox Libraries The library supports both the original Xbox controller via USB and the Xbox 360 controller both via USB and wirelessly. @@ -151,7 +151,7 @@ All the information regarding the Xbox 360 controller protocol are form these si * * -### [Wii library](Wii.cpp) +### [Wii library](Wii.cpp) The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth. From 2ff619dcc7539a847316b13b33a4c55da1a0b5f4 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 20:52:06 +0200 Subject: [PATCH 22/32] Forgot to create hub instance --- examples/Xbox/XBOXOLD/XBOXOLD.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/Xbox/XBOXOLD/XBOXOLD.ino b/examples/Xbox/XBOXOLD/XBOXOLD.ino index 36f121f1..f0297bc1 100644 --- a/examples/Xbox/XBOXOLD/XBOXOLD.ino +++ b/examples/Xbox/XBOXOLD/XBOXOLD.ino @@ -5,7 +5,10 @@ */ #include +#include + USB Usb; +USBHub Hub1(&Usb); // The controller has a built in hub, so this instance is needed XBOXOLD Xbox(&Usb); void setup() { From eb035e9b77db5e1893c12a5fcabdffd019afcaf8 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Thu, 18 Jul 2013 22:24:28 +0200 Subject: [PATCH 23/32] Fixed links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40ad39e3..29abf19d 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,8 @@ The [XBOXOLD](XBOXOLD.cpp) class implements support for the original Xbox contro All the information are from the following sites: -* -* +* +* * * From dcdc1b26f787829fd1fdb44c9205349eca395ad9 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Fri, 19 Jul 2013 12:49:13 +0200 Subject: [PATCH 24/32] Reduced buffer sizes --- BTD.h | 2 +- XBOXOLD.cpp | 2 ++ XBOXOLD.h | 1 - XBOXRECV.h | 2 +- XBOXUSB.h | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/BTD.h b/BTD.h index 8c4568f1..cdfee0b8 100755 --- a/BTD.h +++ b/BTD.h @@ -467,7 +467,7 @@ private: 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 + uint8_t l2capoutbuf[14]; //General purpose buffer for l2cap out data /* State machines */ void HCI_event_task(); // Poll the HCI event pipe diff --git a/XBOXOLD.cpp b/XBOXOLD.cpp index db600267..883a231f 100644 --- a/XBOXOLD.cpp +++ b/XBOXOLD.cpp @@ -321,6 +321,8 @@ void XBOXOLD::XboxCommand(uint8_t* data, uint16_t nbytes) { } void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) { + uint8_t writeBuf[6]; + writeBuf[0] = 0x00; writeBuf[1] = 0x06; writeBuf[2] = 0x00; diff --git a/XBOXOLD.h b/XBOXOLD.h index 3f49ee96..b7780b2a 100644 --- a/XBOXOLD.h +++ b/XBOXOLD.h @@ -188,7 +188,6 @@ private: int16_t hatValue[4]; // Joystick values 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(uint16_t length); // Print incoming date diff --git a/XBOXRECV.h b/XBOXRECV.h index 13c8df58..ccce3b4d 100644 --- a/XBOXRECV.h +++ b/XBOXRECV.h @@ -260,7 +260,7 @@ private: unsigned long timer; // Timing for checkStatus() signals uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data - uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data + uint8_t writeBuf[7]; // General purpose buffer for output data void readReport(uint8_t controller); // read incoming data void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging diff --git a/XBOXUSB.h b/XBOXUSB.h index 85b94cd1..11d4bbad 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -222,7 +222,7 @@ private: bool R2Clicked; uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data - uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data + uint8_t writeBuf[8]; // General purpose buffer for output data void readReport(); // read incoming data void printReport(); // print incoming date - Uncomment for debugging From 65ba9c1366a8846e5a4eda7c9da65834f0bbee44 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sat, 20 Jul 2013 12:57:23 +0200 Subject: [PATCH 25/32] Minor --- PS3USB.cpp | 2 +- XBOXOLD.cpp | 2 +- XBOXUSB.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PS3USB.cpp b/PS3USB.cpp index 4fe12575..0d02a9e1 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -120,8 +120,8 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) { bAddress = 0; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nsetAddr: "), 0x80); -#endif D_PrintHex (rcode, 0x80); +#endif return rcode; } #ifdef EXTRADEBUG diff --git a/XBOXOLD.cpp b/XBOXOLD.cpp index 883a231f..f766e329 100644 --- a/XBOXOLD.cpp +++ b/XBOXOLD.cpp @@ -136,8 +136,8 @@ uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) { bAddress = 0; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nsetAddr: "), 0x80); -#endif D_PrintHex (rcode, 0x80); +#endif return rcode; } #ifdef EXTRADEBUG diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp index 4469b7fc..7279f636 100644 --- a/XBOXUSB.cpp +++ b/XBOXUSB.cpp @@ -124,8 +124,8 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { bAddress = 0; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nsetAddr: "), 0x80); -#endif D_PrintHex (rcode, 0x80); +#endif return rcode; } #ifdef EXTRADEBUG From 8e6ab3f3ae6fc86a18c78c010b6d9b351b488a4d Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sat, 20 Jul 2013 22:07:03 +0200 Subject: [PATCH 26/32] Clear buttonState properly Caused an issue on some dongles --- PS3BT.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/PS3BT.cpp b/PS3BT.cpp index 34afd011..6f9a4d23 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -459,9 +459,6 @@ void PS3BT::L2CAP_task() { if (remote_name[0] == 'M') { // First letter in Motion Controller ('M') for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed l2capinbuf[i] = 0; - ButtonState = 0; - OldButtonState = 0; - l2cap_state = L2CAP_HID_PS3_LED; } else l2cap_state = L2CAP_HID_ENABLE_SIXAXIS; @@ -502,12 +499,9 @@ void PS3BT::Run() { if (millis() - timer > 1000) { // loop 1 second before sending the command for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed l2capinbuf[i] = 0; - ButtonState = 0; - OldButtonState = 0; - - enable_sixaxis(); for (uint8_t i = 15; i < 19; i++) l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position + enable_sixaxis(); l2cap_state = L2CAP_HID_PS3_LED; timer = millis(); } @@ -532,6 +526,10 @@ void PS3BT::Run() { #endif PS3MoveConnected = true; } + ButtonState = 0; // Clear all values + OldButtonState = 0; + ButtonClickState = 0; + onInit(); // Turn on the LED on the controller l2cap_state = L2CAP_DONE; } From b30c56a86e096ef3147cebc66e761f6ad2b1acfd Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Thu, 8 Aug 2013 20:21:05 -0400 Subject: [PATCH 27/32] Control switch via GPX pin. --- Usb.cpp | 10 +++++----- usbhost.h | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Usb.cpp b/Usb.cpp index 31d9bb9b..8884774d 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -110,14 +110,14 @@ uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_l USBTRACE("\r\n"); */ regWr(rPERADDR, addr); //set peripheral address - + uint8_t mode = regRd(rMODE); - + //Serial.print("\r\nMode: "); //Serial.println( mode, HEX); //Serial.print("\r\nLS: "); //Serial.println(p->lowspeed, HEX); - + // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise @@ -512,10 +512,10 @@ void USB::Task(void) //USB state machine if (delay < millis()) usb_task_state = USB_STATE_CONFIGURING; break; case USB_STATE_CONFIGURING: - + //Serial.print("\r\nConf.LS: "); //Serial.println(lowspeed, HEX); - + rcode = Configuring(0, 0, lowspeed); if (rcode) { diff --git a/usbhost.h b/usbhost.h index 819ba971..e25e6805 100644 --- a/usbhost.h +++ b/usbhost.h @@ -18,6 +18,13 @@ e-mail : support@circuitsathome.com #ifndef _USBHOST_H_ #define _USBHOST_H_ +// So we can use delay() -- xxxajk +#if defined(ARDUINO) && ARDUINO >=100 +#include "Arduino.h" +#else +#include +#endif + #include "avrpins.h" #include "max3421e.h" #include "usb_ch9.h" @@ -94,7 +101,7 @@ MAX3421e< SS, INTR >::MAX3421e() { #endif /* MAX3421E - full-duplex SPI, level interrupt */ - regWr(rPINCTL, (bmFDUPSPI + bmINTLEVEL)); + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET)); }; /* write single byte into MAX3421 register */ @@ -218,6 +225,10 @@ int8_t MAX3421e< SS, INTR >::Init() { if(reset() == 0) { //OSCOKIRQ hasn't asserted in time return( -1); } + + // Delay 1 second to ensure any capacitors are drained. + delay(1000); + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection @@ -230,6 +241,10 @@ int8_t MAX3421e< SS, INTR >::Init() { regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt regWr(rCPUCTL, 0x01); //enable interrupt pin + + // GPX pin on. This is done here so that busprobe will fail if we have a switch connected. + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); + return( 0); } From f93c9d8a9a3fd43b575a6a8f8bafc26ac0a4edb5 Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Fri, 9 Aug 2013 00:10:13 -0400 Subject: [PATCH 28/32] merge testusbhostFAT library updates --- examples/testusbhostFAT/Arduino_Makefile_master | 2 +- examples/testusbhostFAT/generic_storage | 2 +- examples/testusbhostFAT/xmem2 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/testusbhostFAT/Arduino_Makefile_master b/examples/testusbhostFAT/Arduino_Makefile_master index f379bae0..76e5edb2 160000 --- a/examples/testusbhostFAT/Arduino_Makefile_master +++ b/examples/testusbhostFAT/Arduino_Makefile_master @@ -1 +1 @@ -Subproject commit f379bae02aa3d9c3da558ba2041558b88db95bbb +Subproject commit 76e5edb248b9078916cf46bdd4fd1a9e8201ca64 diff --git a/examples/testusbhostFAT/generic_storage b/examples/testusbhostFAT/generic_storage index 071b65b9..e717f2df 160000 --- a/examples/testusbhostFAT/generic_storage +++ b/examples/testusbhostFAT/generic_storage @@ -1 +1 @@ -Subproject commit 071b65b923b2656bb1e1b622de5272b4ed9a4996 +Subproject commit e717f2df099491439877cc0d44a660688685dd54 diff --git a/examples/testusbhostFAT/xmem2 b/examples/testusbhostFAT/xmem2 index 8bcf5f90..e5f9968b 160000 --- a/examples/testusbhostFAT/xmem2 +++ b/examples/testusbhostFAT/xmem2 @@ -1 +1 @@ -Subproject commit 8bcf5f90f8bd967378b6eeebd7fd943f125fbc18 +Subproject commit e5f9968b42fb4970ec037290e5942e83accd4fad From 0169e99af7a115d85d497ab80c61b956aab856ca Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Fri, 9 Aug 2013 00:18:25 -0400 Subject: [PATCH 29/32] Updates to testusbhostFAT --- examples/testusbhostFAT/testusbhostFAT.ino | 276 +++++++++++---------- 1 file changed, 139 insertions(+), 137 deletions(-) diff --git a/examples/testusbhostFAT/testusbhostFAT.ino b/examples/testusbhostFAT/testusbhostFAT.ino index b7b792f9..3b521a6c 100755 --- a/examples/testusbhostFAT/testusbhostFAT.ino +++ b/examples/testusbhostFAT/testusbhostFAT.ino @@ -30,6 +30,7 @@ #if WANT_HUB_TEST #include #endif +#include #include #include #include @@ -41,9 +42,12 @@ #if HAVE_XMEM #define GOD_MODE 0 #endif -static FILE mystdout; +static FILE tty_stdio; +static FILE tty_stderr; +USB Usb; + +#define LED 13 // the pin that the LED is attached to -int led = 13; // the pin that the LED is attached to volatile int brightness = 0; // how bright the LED is volatile int fadeAmount = 80; // how many points to fade the LED by volatile uint8_t current_state = 1; @@ -63,13 +67,18 @@ PCPartition *PT; #if WANT_HUB_TEST #define MAX_HUBS 2 -static USBHub *Hubs[MAX_HUBS]; +USBHub *Hubs[MAX_HUBS]; #endif static PFAT *Fats[_VOLUMES]; static part_t parts[_VOLUMES]; static storage_t sto[_VOLUMES]; +/*make sure this is a power of two. */ +#define mbxs 128 +static uint8_t My_Buff_x[mbxs]; /* File read buffer */ + + #define prescale1 ((1 << WGM12) | (1 << CS10)) #define prescale8 ((1 << WGM12) | (1 << CS11)) #define prescale64 ((1 << WGM12) | (1 << CS10) | (1 << CS11)) @@ -78,85 +87,99 @@ static storage_t sto[_VOLUMES]; extern "C" unsigned int freeHeap(); -/* -unsigned int getHeapend(){ - extern unsigned int __heap_start; - - if ((unsigned int)__brkval == 0) { - return (unsigned int)&__heap_start; - } else { - return (unsigned int)__brkval; - } +static int tty_stderr_putc(char c, FILE *t) { + USB_HOST_SERIAL.write(c); } -unsigned int freeHeap() { - if (SP < (unsigned int)__malloc_heap_start) { - return ((unsigned int)__malloc_heap_end - getHeapend()); - } else { - return (SP - getHeapend()); - } -} - */ -static int my_putc(char c, FILE *t) { +static int tty_std_putc(char c, FILE *t) { Serial.write(c); } +static int tty_std_getc(FILE *t) { + while (!Serial.available()); + return Serial.read(); +} + void setup() { + boolean serr = false; for (int i = 0; i < _VOLUMES; i++) { Fats[i] = NULL; + sto[i].private_data = new pvt_t; + ((pvt_t *)sto[i].private_data)->B = 255; // impossible } // Set this to higher values to enable more debug information // minimum 0x00, maximum 0xff UsbDEBUGlvl = 0x51; - // declare pin 9 to be an output: - pinMode(led, OUTPUT); + // make LED pin as an output: + pinMode(LED, OUTPUT); pinMode(2, OUTPUT); + // Ensure TX is off + _SFR_BYTE(UCSR0B) &= ~_BV(TXEN0); // Initialize 'debug' serial port - Serial.begin(115200); + USB_HOST_SERIAL.begin(115200); + // Do not start primary Serial port if already started. + if (bit_is_clear(UCSR0B, TXEN0)) { + Serial.begin(115200); + serr = true; + } - //fdevopen(&my_putc, 0); - // too bad we can't tinker with iob directly, oh well. - mystdout.put = my_putc; - mystdout.get = NULL; - mystdout.flags = _FDEV_SETUP_WRITE; - mystdout.udata = 0; - stdout = &mystdout; + // Set up stdio/stderr + tty_stdio.put = tty_std_putc; + tty_stdio.get = tty_std_getc; + tty_stdio.flags = _FDEV_SETUP_RW; + tty_stdio.udata = 0; + stdout = &tty_stdio; + stdin = &tty_stdio; - // Blink pin 9: + tty_stderr.put = tty_stderr_putc; + tty_stderr.get = NULL; + tty_stderr.flags = _FDEV_SETUP_WRITE; + tty_stderr.udata = 0; + stderr = &tty_stderr; + + // Blink LED delay(500); - analogWrite(led, 255); + analogWrite(LED, 255); delay(500); - analogWrite(led, 0); + analogWrite(LED, 0); delay(500); - analogWrite(led, 255); - delay(500); - analogWrite(led, 0); - delay(500); - analogWrite(led, 255); - delay(500); - analogWrite(led, 0); printf_P(PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n")); printf_P(PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl); printf_P(PSTR("'+' and '-' increase/decrease by 0x01\r\n")); printf_P(PSTR("'.' and ',' increase/decrease by 0x10\r\n")); printf_P(PSTR("'t' will run a 10MB write/read test and print out the time it took.\r\n")); - printf_P(PSTR("'e' will toggle vbus off for a few moments.\r\n")); - printf_P(PSTR("\r\n\r\nLong filename support: " + printf_P(PSTR("'e' will toggle vbus off for a few moments.\r\n\r\n")); + printf_P(PSTR("Long filename support: " #if _USE_LFN "Enabled" #else "Disabled" #endif "\r\n")); - analogWrite(led, 255); + if (serr) { + fprintf_P(stderr, PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n")); + fprintf_P(stderr, PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl); + fprintf_P(stderr, PSTR("Long filename support: " +#if _USE_LFN + "Enabled" +#else + "Disabled" +#endif + "\r\n")); + } + analogWrite(LED, 255); delay(500); - analogWrite(led, 0); + analogWrite(LED, 0); + delay(500); + analogWrite(LED, 255); + delay(500); + analogWrite(LED, 0); + delay(500); + analogWrite(LED, 255); + delay(500); + analogWrite(LED, 0); delay(500); - delay(100); - analogWrite(led, 255); - delay(100); - analogWrite(led, 0); LEDnext_time = millis() + 1; #ifdef EXT_RAM printf_P(PSTR("Total EXT RAM banks %i\r\n"), xmem::getTotalBanks()); @@ -263,8 +286,8 @@ ISR(TIMER3_COMPA_vect) { if (millis() >= LEDnext_time) { LEDnext_time = millis() + 30; - // set the brightness of pin 9: - analogWrite(led, brightness); + // set the brightness of LED + analogWrite(LED, brightness); // change the brightness for next time through the loop: brightness = brightness + fadeAmount; @@ -281,7 +304,6 @@ ISR(TIMER3_COMPA_vect) { } } - bool isfat(uint8_t t) { return (t == 0x01 || t == 0x04 || t == 0x06 || t == 0x0b || t == 0x0c || t == 0x0e || t == 0x1); } @@ -289,17 +311,10 @@ bool isfat(uint8_t t) { void die(FRESULT rc) { printf_P(PSTR("Failed with rc=%u.\r\n"), rc); //for (;;); - } -/*make sure this is a power of two. */ -#define mbxs 128 - void loop() { - uint8_t My_Buff_x[mbxs]; /* File read buffer */ FIL My_File_Object_x; /* File object */ - DIR My_Dir_Object_x; /* Directory object */ - FILINFO My_File_Info_Object_x; /* File information object */ // Print a heap status report about every 10 seconds. if (millis() >= HEAPnext_time) { @@ -342,16 +357,6 @@ void loop() { printf_P(PSTR("USB state = %x\r\n"), current_state); if (current_state == USB_STATE_RUNNING) { fadeAmount = 30; - /* - partsready = false; - for (int i = 0; i < cpart; i++) { - if (Fats[i] != NULL) - delete Fats[i]; - } - fatready = false; - notified = false; - cpart = 0; - */ } if (current_state == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) { fadeAmount = 80; @@ -365,17 +370,6 @@ void loop() { notified = false; cpart = 0; } -#if 0 - if (current_state == 0xa0) { - printf_P(PSTR("VBUS off\r\n")); - // safe to do here - Usb.gpioWr(0x00); - digitalWrite(2, 0); - usbon = false; - usbon_time = millis() + 2000; - change = false; - } -#endif last_state = current_state; } @@ -386,7 +380,7 @@ void loop() { } // This is horrible, and needs to be moved elsewhere! - for (int B = 0; B < MAX_DRIVERS; B++) { + for (int B = 0; B < MAX_USB_MS_DRIVERS; B++) { if (!partsready && Bulk[B]->GetAddress() != NULL) { // Build a list. int ML = Bulk[B]->GetbMaxLUN(); @@ -395,9 +389,8 @@ void loop() { for (int i = 0; i < ML; i++) { if (Bulk[B]->LUNIsGood(i)) { partsready = true; - sto[i].private_data = &info[i]; - info[i].lun = i; - info[i].B = B; + ((pvt_t *)sto[i].private_data)->lun = i; + ((pvt_t *)sto[i].private_data)->B = B; sto[i].Read = *PRead; sto[i].Write = *PWrite; sto[i].Reads = *PReads; @@ -477,7 +470,6 @@ void loop() { if (fatready) { FRESULT rc; /* Result code */ UINT bw, br, i; - ULONG ii, wt, rt, start, end; if (!notified) { fadeAmount = 5; @@ -488,7 +480,7 @@ void loop() { else { printf_P(PSTR("\r\nType the file content.\r\n")); for (;;) { - rc = f_read(&My_File_Object_x, &(My_Buff_x[0]), mbxs, &br); /* Read a chunk of file */ + rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &br); /* Read a chunk of file */ if (rc || !br) break; /* Error or end of file */ for (i = 0; i < br; i++) { /* Type the data */ @@ -528,55 +520,67 @@ void loop() { goto out; } outdir: - printf_P(PSTR("\r\nOpen root directory.\r\n")); - rc = f_opendir(&My_Dir_Object_x, "0:/"); - if (rc) { - die(rc); - goto out; - } - - printf_P(PSTR("\r\nDirectory listing...\r\n")); - printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap()); - for (;;) { - rc = f_readdir(&My_Dir_Object_x, &My_File_Info_Object_x); /* Read a directory item */ - if (rc || !My_File_Info_Object_x.fname[0]) break; /* Error or end of dir */ - - if (My_File_Info_Object_x.fattrib & AM_DIR) { - Serial.write('d'); - } else { - Serial.write('-'); - } - Serial.write('r'); - - if (My_File_Info_Object_x.fattrib & AM_RDO) { - Serial.write('-'); - } else { - Serial.write('w'); - } - if (My_File_Info_Object_x.fattrib & AM_HID) { - Serial.write('h'); - } else { - Serial.write('-'); + { +#if _USE_LFN + char lfn[_MAX_LFN + 1]; + FILINFO My_File_Info_Object_x; /* File information object */ + My_File_Info_Object_x.lfname = lfn; +#endif + DIR My_Dir_Object_x; /* Directory object */ + printf_P(PSTR("\r\nOpen root directory.\r\n")); + rc = f_opendir(&My_Dir_Object_x, "0:/"); + if (rc) { + die(rc); + goto out; } - if (My_File_Info_Object_x.fattrib & AM_SYS) { - Serial.write('s'); - } else { - Serial.write('-'); - } + printf_P(PSTR("\r\nDirectory listing...\r\n")); + printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap()); + for (;;) { +#if _USE_LFN + My_File_Info_Object_x.lfsize = _MAX_LFN; +#endif - if (My_File_Info_Object_x.fattrib & AM_ARC) { - Serial.write('a'); - } else { - Serial.write('-'); - } + rc = f_readdir(&My_Dir_Object_x, &My_File_Info_Object_x); /* Read a directory item */ + if (rc || !My_File_Info_Object_x.fname[0]) break; /* Error or end of dir */ + + if (My_File_Info_Object_x.fattrib & AM_DIR) { + Serial.write('d'); + } else { + Serial.write('-'); + } + Serial.write('r'); + + if (My_File_Info_Object_x.fattrib & AM_RDO) { + Serial.write('-'); + } else { + Serial.write('w'); + } + if (My_File_Info_Object_x.fattrib & AM_HID) { + Serial.write('h'); + } else { + Serial.write('-'); + } + + if (My_File_Info_Object_x.fattrib & AM_SYS) { + Serial.write('s'); + } else { + Serial.write('-'); + } + + if (My_File_Info_Object_x.fattrib & AM_ARC) { + Serial.write('a'); + } else { + Serial.write('-'); + } #if _USE_LFN - if (*My_File_Info_Object_x.lfname) - printf_P(PSTR(" %8lu %s (%s)\r\n"), My_File_Info_Object_x.fsize, My_File_Info_Object_x.fname, My_File_Info_Object_x.lfname); - else + if (*My_File_Info_Object_x.lfname) + printf_P(PSTR(" %8lu %s (%s)\r\n"), My_File_Info_Object_x.fsize, My_File_Info_Object_x.fname, My_File_Info_Object_x.lfname); + else #endif - printf_P(PSTR(" %8lu %s\r\n"), My_File_Info_Object_x.fsize, &(My_File_Info_Object_x.fname[0])); + printf_P(PSTR(" %8lu %s\r\n"), My_File_Info_Object_x.fsize, &(My_File_Info_Object_x.fname[0])); + } } out: if (rc) die(rc); @@ -584,18 +588,17 @@ out: } - - - if (runtest) { + ULONG ii, wt, rt, start, end; runtest = false; + f_unlink("0:/10MB.bin"); printf_P(PSTR("\r\nCreate a new 10MB test file (10MB.bin).\r\n")); - for (bw = 0; bw < mbxs; bw++) My_Buff_x[bw] = bw & 0xff; rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_WRITE | FA_CREATE_ALWAYS); if (rc) goto failed; + for (bw = 0; bw < mbxs; bw++) My_Buff_x[bw] = bw & 0xff; start = millis(); - for (ii = 10485760 / mbxs; ii > 0; ii--) { - rc = f_write(&My_File_Object_x, &My_Buff_x[0], mbxs, &bw); + for (ii = 10485760LU / mbxs; ii > 0LU; ii--) { + rc = f_write(&My_File_Object_x, My_Buff_x, mbxs, &bw); if (rc || !bw) goto failed; } rc = f_close(&My_File_Object_x); @@ -607,7 +610,7 @@ out: start = millis(); if (rc) goto failed; for (;;) { - rc = f_read(&My_File_Object_x, &My_Buff_x[0], mbxs, &bw); /* Read a chunk of file */ + rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &bw); /* Read a chunk of file */ if (rc || !bw) break; /* Error or end of file */ } end = millis(); @@ -617,7 +620,6 @@ out: rt = end - start; printf_P(PSTR("Time to read 10485760 bytes: %lu ms (%lu sec)\r\nDelete test file\r\n"), rt, (500 + rt) / 1000UL); failed: - rc = f_unlink("0:/10MB.bin"); if (rc) die(rc); printf_P(PSTR("10MB timing test finished.\r\n")); } From a57215fb727e481c75b6b4625c4c2f257a357e95 Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Fri, 9 Aug 2013 02:17:01 -0400 Subject: [PATCH 30/32] GPX vbus controls --- usbhost.h | 53 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/usbhost.h b/usbhost.h index e25e6805..538d9641 100644 --- a/usbhost.h +++ b/usbhost.h @@ -59,6 +59,11 @@ typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi; typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi; #endif +typedef enum VBUS_t { + on = 0, + off = GPX_VBDET +}; + template< typename SS, typename INTR > class MAX3421e /* : public spi */ { static uint8_t vbusState; @@ -72,6 +77,11 @@ public: uint8_t gpioRd(); uint16_t reset(); int8_t Init(); + int8_t Init(int mseconds); + + void vbusPower(VBUS_t state) { + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state)); + } uint8_t getVbusState(void) { return vbusState; @@ -207,17 +217,6 @@ uint16_t MAX3421e< SS, INTR >::reset() { } return( i); } -///* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ -//template< typename SS, typename INTR > -//int8_t MAX3421e< SS, INTR >::Init() -//{ -// if( reset() == 0 ) { //OSCOKIRQ hasn't asserted in time -// return ( -1 ); -// } -// regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host -// -// return( 0 ); -//} /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ template< typename SS, typename INTR > @@ -226,8 +225,36 @@ int8_t MAX3421e< SS, INTR >::Init() { return( -1); } - // Delay 1 second to ensure any capacitors are drained. - delay(1000); + // GPX pin on. + regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL)); + + regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host + + regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection + + /* check if device is connected */ + regWr(rHCTL, bmSAMPLEBUS); // sample USB bus + while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish + + busprobe(); //check if anything is connected + + regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt + regWr(rCPUCTL, 0x01); //enable interrupt pin + + return( 0); +} + +/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ +template< typename SS, typename INTR > +int8_t MAX3421e< SS, INTR >::Init(int mseconds) { + if(reset() == 0) { //OSCOKIRQ hasn't asserted in time + return( -1); + } + + // Delay a minimum of 1 second to ensure any capacitors are drained. + // 1 second is required to make sure we do not smoke a Microdrive! + if(mseconds < 1000) mseconds = 1000; + delay(mseconds); regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host From b150524807e8f8a0dfc6693e16891ca73bd8774b Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Fri, 9 Aug 2013 02:24:46 -0400 Subject: [PATCH 31/32] testusbhostFAT updates --- examples/testusbhostFAT/Arduino_Makefile_master | 2 +- examples/testusbhostFAT/generic_storage | 2 +- examples/testusbhostFAT/xmem2 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/testusbhostFAT/Arduino_Makefile_master b/examples/testusbhostFAT/Arduino_Makefile_master index f379bae0..76e5edb2 160000 --- a/examples/testusbhostFAT/Arduino_Makefile_master +++ b/examples/testusbhostFAT/Arduino_Makefile_master @@ -1 +1 @@ -Subproject commit f379bae02aa3d9c3da558ba2041558b88db95bbb +Subproject commit 76e5edb248b9078916cf46bdd4fd1a9e8201ca64 diff --git a/examples/testusbhostFAT/generic_storage b/examples/testusbhostFAT/generic_storage index 071b65b9..e717f2df 160000 --- a/examples/testusbhostFAT/generic_storage +++ b/examples/testusbhostFAT/generic_storage @@ -1 +1 @@ -Subproject commit 071b65b923b2656bb1e1b622de5272b4ed9a4996 +Subproject commit e717f2df099491439877cc0d44a660688685dd54 diff --git a/examples/testusbhostFAT/xmem2 b/examples/testusbhostFAT/xmem2 index 8bcf5f90..e5f9968b 160000 --- a/examples/testusbhostFAT/xmem2 +++ b/examples/testusbhostFAT/xmem2 @@ -1 +1 @@ -Subproject commit 8bcf5f90f8bd967378b6eeebd7fd943f125fbc18 +Subproject commit e5f9968b42fb4970ec037290e5942e83accd4fad From 3d16d6f9d6d19152f57e2dd6c1aa72e2530bdbcc Mon Sep 17 00:00:00 2001 From: "Andrew J. Kroll" Date: Fri, 9 Aug 2013 02:27:34 -0400 Subject: [PATCH 32/32] testusbhostFAT Updates --- examples/testusbhostFAT/testusbhostFAT.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/testusbhostFAT/testusbhostFAT.ino b/examples/testusbhostFAT/testusbhostFAT.ino index 3b521a6c..a7dfa361 100755 --- a/examples/testusbhostFAT/testusbhostFAT.ino +++ b/examples/testusbhostFAT/testusbhostFAT.ino @@ -196,7 +196,7 @@ void setup() { printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap()); } #endif - while (Usb.Init() == -1) { + while (Usb.Init(1000) == -1) { printf_P(PSTR("No\r\n")); Notify(PSTR("OSC did not start."), 0x40); }