Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Wii.cpp Source File

Wii.cpp

00001 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
00002 
00003  This software may be distributed and modified under the terms of the GNU
00004  General Public License version 2 (GPL2) as published by the Free Software
00005  Foundation and appearing in the file GPL2.TXT included in the packaging of
00006  this file. Please note that GPL2 Section 2[b] requires that all works based
00007  on this software must also be made publicly available under the terms of
00008  the GPL2 ("Copyleft").
00009 
00010  Contact information
00011  -------------------
00012 
00013  Kristian Lauszus, TKJ Electronics
00014  Web      :  http://www.tkjelectronics.com
00015  e-mail   :  kristianl@tkjelectronics.com
00016 
00017  IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus
00018  */
00019 
00020 #include "Wii.h"
00021 // To enable serial debugging see "settings.h"
00022 //#define EXTRADEBUG // Uncomment to get even more debugging data
00023 //#define PRINTREPORT // Uncomment to print the report send by the Wii controllers
00024 
00025 const uint8_t WII_LEDS[] PROGMEM = {
00026         0x00, // OFF
00027         0x10, // LED1
00028         0x20, // LED2
00029         0x40, // LED3
00030         0x80, // LED4
00031 
00032         0x90, // LED5
00033         0xA0, // LED6
00034         0xC0, // LED7
00035         0xD0, // LED8
00036         0xE0, // LED9
00037         0xF0, // LED10
00038 };
00039 
00040 const uint32_t WII_BUTTONS[] PROGMEM = {
00041         0x00008, // UP
00042         0x00002, // RIGHT
00043         0x00004, // DOWN
00044         0x00001, // LEFT
00045 
00046         0, // Skip
00047         0x00010, // PLUS
00048         0x00100, // TWO
00049         0x00200, // ONE
00050 
00051         0x01000, // MINUS
00052         0x08000, // HOME
00053         0x10000, // Z
00054         0x20000, // C
00055 
00056         0x00400, // B
00057         0x00800, // A
00058 };
00059 const uint32_t WII_PROCONTROLLER_BUTTONS[] PROGMEM = {
00060         0x00100, // UP
00061         0x00080, // RIGHT
00062         0x00040, // DOWN
00063         0x00200, // LEFT
00064 
00065         0, // Skip
00066         0x00004, // PLUS
00067         0x20000, // L3
00068         0x10000, // R3
00069 
00070         0x00010, // MINUS
00071         0x00008, // HOME
00072         0, 0, // Skip
00073 
00074         0x04000, // B
00075         0x01000, // A
00076         0x00800, // X
00077         0x02000, // Y
00078 
00079         0x00020, // L
00080         0x00002, // R
00081         0x08000, // ZL
00082         0x00400, // ZR
00083 };
00084 
00085 WII::WII(BTD *p, bool pair) :
00086 BluetoothService(p) // Pointer to USB class instance - mandatory
00087 {
00088         pBtd->pairWithWii = pair;
00089 
00090         HIDBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
00091 
00092         /* Set device cid for the control and intterrupt channelse - LSB */
00093         control_dcid[0] = 0x60; // 0x0060
00094         control_dcid[1] = 0x00;
00095         interrupt_dcid[0] = 0x61; // 0x0061
00096         interrupt_dcid[1] = 0x00;
00097 
00098         Reset();
00099 }
00100 
00101 void WII::Reset() {
00102         wiimoteConnected = false;
00103         nunchuckConnected = false;
00104         motionPlusConnected = false;
00105         activateNunchuck = false;
00106         motionValuesReset = false;
00107         activeConnection = false;
00108         motionPlusInside = false;
00109         pBtd->wiiUProController = false;
00110         wiiUProControllerConnected = false;
00111         wiiBalanceBoardConnected = false;
00112         l2cap_event_flag = 0; // Reset flags
00113         l2cap_state = L2CAP_WAIT;
00114 }
00115 
00116 void WII::disconnect() { // Use this void to disconnect any of the controllers
00117         if(!motionPlusInside) { // The old Wiimote needs a delay after the first command or it will automatically reconnect
00118                 if(motionPlusConnected) {
00119 #ifdef DEBUG_USB_HOST
00120                         Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80);
00121 #endif
00122                         initExtension1(); // This will disable the Motion Plus extension
00123                 }
00124                 timer = (uint32_t)millis() + 1000; // We have to wait for the message before the rest of the channels can be deactivated
00125         } else
00126                 timer = (uint32_t)millis(); // Don't wait
00127         // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
00128         pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
00129         Reset();
00130         l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
00131 }
00132 
00133 void WII::ACLData(uint8_t* l2capinbuf) {
00134         if(!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) {
00135                 if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
00136                         if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
00137                                 motionPlusInside = pBtd->motionPlusInside;
00138                                 pBtd->incomingWii = false;
00139                                 pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
00140                                 activeConnection = true;
00141                                 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
00142                                 l2cap_state = L2CAP_WAIT;
00143                         }
00144                 }
00145         }
00146 
00147         if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
00148                 if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
00149                         if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
00150 #ifdef DEBUG_USB_HOST
00151                                 Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
00152                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00153                                 Notify(PSTR(" "), 0x80);
00154                                 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00155                                 Notify(PSTR(" "), 0x80);
00156                                 D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
00157                                 Notify(PSTR(" "), 0x80);
00158                                 D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
00159                                 Notify(PSTR(" "), 0x80);
00160                                 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
00161                                 Notify(PSTR(" "), 0x80);
00162                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00163 #endif
00164                         } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
00165                                 if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
00166                                         if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
00167                                                 //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
00168                                                 identifier = l2capinbuf[9];
00169                                                 control_scid[0] = l2capinbuf[12];
00170                                                 control_scid[1] = l2capinbuf[13];
00171                                                 l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
00172                                         } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
00173                                                 //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
00174                                                 identifier = l2capinbuf[9];
00175                                                 interrupt_scid[0] = l2capinbuf[12];
00176                                                 interrupt_scid[1] = l2capinbuf[13];
00177                                                 l2cap_set_flag(L2CAP_FLAG_INTERRUPT_CONNECTED);
00178                                         }
00179                                 }
00180                         } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
00181 #ifdef EXTRADEBUG
00182                                 Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
00183                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00184                                 Notify(PSTR(" "), 0x80);
00185                                 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00186                                 Notify(PSTR(" SCID: "), 0x80);
00187                                 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
00188                                 Notify(PSTR(" "), 0x80);
00189                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00190                                 Notify(PSTR(" Identifier: "), 0x80);
00191                                 D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
00192 #endif
00193                                 if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
00194                                         identifier = l2capinbuf[9];
00195                                         control_scid[0] = l2capinbuf[14];
00196                                         control_scid[1] = l2capinbuf[15];
00197                                         l2cap_set_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST);
00198                                 } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) {
00199                                         identifier = l2capinbuf[9];
00200                                         interrupt_scid[0] = l2capinbuf[14];
00201                                         interrupt_scid[1] = l2capinbuf[15];
00202                                         l2cap_set_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST);
00203                                 }
00204                         } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
00205                                 if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
00206                                         if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
00207                                                 //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
00208                                                 identifier = l2capinbuf[9];
00209                                                 l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
00210                                         } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
00211                                                 //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
00212                                                 identifier = l2capinbuf[9];
00213                                                 l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
00214                                         }
00215                                 }
00216                         } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
00217                                 if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
00218                                         //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
00219                                         pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
00220                                 } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
00221                                         //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
00222                                         pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
00223                                 }
00224                         } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
00225                                 if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
00226 #ifdef DEBUG_USB_HOST
00227                                         Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
00228 #endif
00229                                         identifier = l2capinbuf[9];
00230                                         pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
00231                                         Reset();
00232                                 } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
00233 #ifdef DEBUG_USB_HOST
00234                                         Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
00235 #endif
00236                                         identifier = l2capinbuf[9];
00237                                         pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid);
00238                                         Reset();
00239                                 }
00240                         } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
00241                                 if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
00242                                         //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
00243                                         identifier = l2capinbuf[9];
00244                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE);
00245                                 } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
00246                                         //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
00247                                         identifier = l2capinbuf[9];
00248                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE);
00249                                 }
00250                         }
00251 #ifdef EXTRADEBUG
00252                         else {
00253                                 identifier = l2capinbuf[9];
00254                                 Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
00255                                 D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
00256                         }
00257 #endif
00258                 } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
00259                         //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
00260                         if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
00261                                 if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons
00262                                         if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes
00263                                                 ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
00264                                         else if(wiiUProControllerConnected)
00265                                                 ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16));
00266                                         else if(motionPlusConnected) {
00267                                                 if(l2capinbuf[20] & 0x02) // Only update the Wiimote buttons, since the extension bytes are from the Motion Plus
00268                                                         ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000)));
00269                                                 else if(nunchuckConnected) // Update if it's a report from the Nunchuck
00270                                                         ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14));
00271                                                 //else if(classicControllerConnected) // Update if it's a report from the Classic Controller
00272                                         } else if(nunchuckConnected) // The Nunchuck is directly connected
00273                                                 ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16));
00274                                                 //else if(classicControllerConnected) // The Classic Controller is directly connected
00275                                         else if(!unknownExtensionConnected)
00276                                                 ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
00277 #ifdef PRINTREPORT
00278                                         Notify(PSTR("ButtonState: "), 0x80);
00279                                         D_PrintHex<uint32_t > (ButtonState, 0x80);
00280                                         Notify(PSTR("\r\n"), 0x80);
00281 #endif
00282                                         if(ButtonState != OldButtonState) {
00283                                                 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
00284                                                 OldButtonState = ButtonState;
00285                                         }
00286                                 }
00287                                 if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer
00288                                         accXwiimote = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5)) - 500;
00289                                         accYwiimote = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4)) - 500;
00290                                         accZwiimote = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5)) - 500;
00291                                 }
00292                                 switch(l2capinbuf[9]) {
00293                                         case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV
00294 #ifdef EXTRADEBUG
00295                                                 Notify(PSTR("\r\nStatus report was received"), 0x80);
00296 #endif
00297                                                 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)
00298                                                 batteryLevel = l2capinbuf[15]; // Update battery level
00299 
00300                                                 if(!checkBatteryLevel) { // If this is true it means that the user must have called getBatteryLevel()
00301                                                         if(l2capinbuf[12] & 0x02) { // Check if a extension is connected
00302 #ifdef DEBUG_USB_HOST
00303                                                                 if(!unknownExtensionConnected)
00304                                                                         Notify(PSTR("\r\nExtension connected"), 0x80);
00305 #endif
00306                                                                 unknownExtensionConnected = true;
00307 #ifdef WIICAMERA
00308                                                                 if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
00309 #endif
00310                                                                         setReportMode(false, 0x35); // Also read the extension
00311                                                         } else {
00312 #ifdef DEBUG_USB_HOST
00313                                                                 Notify(PSTR("\r\nExtension disconnected"), 0x80);
00314 #endif
00315                                                                 if(motionPlusConnected) {
00316 #ifdef DEBUG_USB_HOST
00317                                                                         Notify(PSTR(" - from Motion Plus"), 0x80);
00318 #endif
00319                                                                         wii_clear_flag(WII_FLAG_NUNCHUCK_CONNECTED);
00320                                                                         if(!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false
00321                                                                                 nunchuckConnected = false;
00322                                                                         //else if(classicControllerConnected)
00323                                                                 } else if(nunchuckConnected) {
00324 #ifdef DEBUG_USB_HOST
00325                                                                         Notify(PSTR(" - Nunchuck"), 0x80);
00326 #endif
00327                                                                         nunchuckConnected = false; // It must be the Nunchuck controller then
00328                                                                         wii_clear_flag(WII_FLAG_NUNCHUCK_CONNECTED);
00329                                                                         onInit();
00330 #ifdef WIICAMERA
00331                                                                         if(!isIRCameraEnabled()) // We still want to read from the IR camera, so do not change the report mode
00332 #endif
00333                                                                                 setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
00334                                                                 } else {
00335 #ifdef WIICAMERA
00336                                                                         if(!isIRCameraEnabled()) // We still want to read from the IR camera, so do not change the report mode
00337 #endif
00338                                                                                 setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
00339                                                                 }
00340                                                         }
00341                                                 }
00342                                                 else {
00343 #ifdef EXTRADEBUG
00344                                                         Notify(PSTR("\r\nChecking battery level"), 0x80);
00345 #endif
00346                                                         checkBatteryLevel = false; // Check for extensions by default
00347                                                 }
00348 #ifdef DEBUG_USB_HOST
00349                                                 if(l2capinbuf[12] & 0x01)
00350                                                         Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80);
00351 #endif
00352 
00353                                                 break;
00354                                         case 0x21: // Read Memory Data
00355                                                 if((l2capinbuf[12] & 0x0F) == 0) { // No error
00356                                                         uint8_t reportLength = (l2capinbuf[12] >> 4) + 1; // // Bit 4-7 is the length - 1
00357                                                         // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
00358                                                         if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) {
00359 #ifdef DEBUG_USB_HOST
00360                                                                 Notify(PSTR("\r\nNunchuck connected"), 0x80);
00361 #endif
00362                                                                 wii_set_flag(WII_FLAG_NUNCHUCK_CONNECTED);
00363                                                         } else if(l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) {
00364 #ifdef DEBUG_USB_HOST
00365                                                                 Notify(PSTR("\r\nMotion Plus connected"), 0x80);
00366 #endif
00367                                                                 wii_set_flag(WII_FLAG_MOTION_PLUS_CONNECTED);
00368                                                         } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) {
00369 #ifdef DEBUG_USB_HOST
00370                                                                 Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80);
00371 #endif
00372                                                                 motionPlusConnected = true;
00373 #ifdef WIICAMERA
00374                                                                 if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
00375 #endif
00376                                                                         setReportMode(false, 0x35); // Also read the extension
00377                                                         } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) {
00378 #ifdef DEBUG_USB_HOST
00379                                                                 Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80);
00380 #endif
00381                                                                 activateNunchuck = false;
00382                                                                 motionPlusConnected = true;
00383                                                                 nunchuckConnected = true;
00384 #ifdef WIICAMERA
00385                                                                 if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
00386 #endif
00387                                                                         setReportMode(false, 0x35); // Also read the extension
00388                                                         } 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) {
00389 #ifdef DEBUG_USB_HOST
00390                                                                 Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80);
00391                                                                 Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80);
00392 #endif
00393                                                                 stateCounter = 300; // Skip the rest in "WII_CHECK_MOTION_PLUS_STATE"
00394                                                         } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) {
00395 #ifdef DEBUG_USB_HOST
00396                                                                 Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80);
00397 #endif
00398                                                                 wiiUProControllerConnected = true;
00399                                                         } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x02) {
00400 #ifdef DEBUG_USB_HOST
00401                                                                 Notify(PSTR("\r\nWii Balance Board connected"), 0x80);
00402 #endif
00403                                                                 setReportMode(false, 0x32); // Read the Wii Balance Board extension
00404                                                                 wii_set_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD);
00405                                                         }
00406                                                         // Wii Balance Board calibration reports (24 bits in total)
00407                                                         else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x24 && reportLength == 16) { // First 16-bit
00408                                                                 for(uint8_t i = 0; i < 2; i++) {
00409                                                                         for(uint8_t j = 0; j < 4; j++)
00410                                                                                 wiiBalanceBoardCal[i][j] = l2capinbuf[16 + 8 * i + 2 * j] | l2capinbuf[15 + 8 * i + 2 * j] << 8;
00411                                                                 }
00412                                                         } else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x34 && reportLength == 8) { // Last 8-bit
00413                                                                 for(uint8_t j = 0; j < 4; j++)
00414                                                                         wiiBalanceBoardCal[2][j] = l2capinbuf[16 + 2 * j] | l2capinbuf[15 + 2 * j] << 8;
00415 #ifdef DEBUG_USB_HOST
00416                                                                 Notify(PSTR("\r\nWii Balance Board calibration values read successfully"), 0x80);
00417 #endif
00418                                                                 wii_clear_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD);
00419                                                                 wiiBalanceBoardConnected = true;
00420                                                         }
00421 #ifdef DEBUG_USB_HOST
00422                                                         else {
00423                                                                 Notify(PSTR("\r\nUnknown Device: "), 0x80);
00424                                                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00425                                                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00426                                                                 Notify(PSTR("\r\nData: "), 0x80);
00427                                                                 for(uint8_t i = 0; i < reportLength; i++) {
00428                                                                         D_PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80);
00429                                                                         Notify(PSTR(" "), 0x80);
00430                                                                 }
00431                                                         }
00432 #endif
00433                                                 }
00434 #ifdef EXTRADEBUG
00435                                                 else {
00436                                                         Notify(PSTR("\r\nReport Error: "), 0x80);
00437                                                         D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00438                                                         D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00439                                                 }
00440 #endif
00441                                                 break;
00442                                         case 0x22: // Acknowledge output report, return function result
00443 #ifdef DEBUG_USB_HOST
00444                                                 if(l2capinbuf[13] != 0x00) { // Check if there is an error
00445                                                         Notify(PSTR("\r\nCommand failed: "), 0x80);
00446                                                         D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00447                                                 }
00448 #endif
00449                                                 break;
00450                                         case 0x30: // Core buttons - (a1) 30 BB BB
00451                                                 break;
00452                                         case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA
00453                                                 break;
00454                                         case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE
00455                                                 // See: http://wiibrew.org/wiki/Wii_Balance_Board#Data_Format
00456                                                 wiiBalanceBoardRaw[TopRight] = l2capinbuf[13] | l2capinbuf[12] << 8; // Top right
00457                                                 wiiBalanceBoardRaw[BotRight] = l2capinbuf[15] | l2capinbuf[14] << 8; // Bottom right
00458                                                 wiiBalanceBoardRaw[TopLeft] = l2capinbuf[17] | l2capinbuf[16] << 8; // Top left
00459                                                 wiiBalanceBoardRaw[BotLeft] = l2capinbuf[19] | l2capinbuf[18] << 8; // Bottom left
00460                                                 break;
00461                                         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
00462 #ifdef WIICAMERA
00463                                                 // Read the IR data
00464                                                 IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position
00465                                                 IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position
00466                                                 IR_object_s1 = (l2capinbuf[17] & 0x0F); // Size value, 0-15
00467 
00468                                                 IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4));
00469                                                 IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2));
00470                                                 IR_object_s2 = (l2capinbuf[20] & 0x0F);
00471 
00472                                                 IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4));
00473                                                 IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2));
00474                                                 IR_object_s3 = (l2capinbuf[23] & 0x0F);
00475 
00476                                                 IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4));
00477                                                 IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2));
00478                                                 IR_object_s4 = (l2capinbuf[26] & 0x0F);
00479 #endif
00480                                                 break;
00481                                         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
00482                                                 break;
00483                                                 /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */
00484                                         case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes
00485                                                 // (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
00486                                                 // corresponds to output report mode 0x3e
00487 
00488                                                 /**** for reading in full mode: DOES NOT WORK YET ****/
00489                                                 /* When it works it will also have intensity and bounding box data */
00490                                                 /*
00491                                                 IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4));
00492                                                 IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2));
00493                                                 IR_object_s1 = (l2capinbuf[15] & 0x0F);
00494                                                  */
00495                                                 break;
00496                                         case 0x3F:
00497                                                 /*
00498                                                 IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4));
00499                                                 IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2));
00500                                                 IR_object_s1 = (l2capinbuf[15] & 0x0F);
00501                                                  */
00502                                                 break;
00503                                         case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes
00504                                                 // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
00505 #if 1 // Set this to 0 if you don't want to use an extension, this reduceds the size of the library a lot!
00506                                                 if(motionPlusConnected) {
00507                                                         if(l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension
00508                                                                 if(motionValuesReset) { // We will only use the values when the gyro value has been set
00509                                                                         gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)) - gyroYawZero);
00510                                                                         gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)) - gyroRollZero);
00511                                                                         gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)) - gyroPitchZero);
00512 
00513                                                                         yawGyroSpeed = (float)gyroYawRaw / ((float)gyroYawZero / yawGyroScale);
00514                                                                         rollGyroSpeed = -(float)gyroRollRaw / ((float)gyroRollZero / rollGyroScale); // We invert these values so they will fit the acc values
00515                                                                         pitchGyroSpeed = (float)gyroPitchRaw / ((float)gyroPitchZero / pitchGyroScale);
00516 
00517                                                                         /* The onboard gyro has two ranges for slow and fast mode */
00518                                                                         if(!(l2capinbuf[18] & 0x02)) // Check if fast mode is used
00519                                                                                 yawGyroSpeed *= 4.545;
00520                                                                         if(!(l2capinbuf[18] & 0x01)) // Check if fast mode is used
00521                                                                                 pitchGyroSpeed *= 4.545;
00522                                                                         if(!(l2capinbuf[19] & 0x02)) // Check if fast mode is used
00523                                                                                 rollGyroSpeed *= 4.545;
00524 
00525                                                                         compPitch = (0.93f * (compPitch + (pitchGyroSpeed * (float)((uint32_t)micros() - timer) / 1000000.0f)))+(0.07f * getWiimotePitch()); // Use a complimentary filter to calculate the angle
00526                                                                         compRoll = (0.93f * (compRoll + (rollGyroSpeed * (float)((uint32_t)micros() - timer) / 1000000.0f)))+(0.07f * getWiimoteRoll());
00527 
00528                                                                         gyroYaw += (yawGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f));
00529                                                                         gyroRoll += (rollGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f));
00530                                                                         gyroPitch += (pitchGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f));
00531                                                                         timer = (uint32_t)micros();
00532                                                                         /*
00533                                                                         // Uncomment these lines to tune the gyro scale variabels
00534                                                                         Notify(PSTR("\r\ngyroYaw: "), 0x80);
00535                                                                         Notify(gyroYaw, 0x80);
00536                                                                         Notify(PSTR("\tgyroRoll: "), 0x80);
00537                                                                         Notify(gyroRoll, 0x80);
00538                                                                         Notify(PSTR("\tgyroPitch: "), 0x80);
00539                                                                         Notify(gyroPitch, 0x80);
00540                                                                          */
00541                                                                         /*
00542                                                                         Notify(PSTR("\twiimoteRoll: "), 0x80);
00543                                                                         Notify(wiimoteRoll, 0x80);
00544                                                                         Notify(PSTR("\twiimotePitch: "), 0x80);
00545                                                                         Notify(wiimotePitch, 0x80);
00546                                                                          */
00547                                                                 } else {
00548                                                                         if((int32_t)((uint32_t)micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values
00549 #ifdef DEBUG_USB_HOST
00550                                                                                 Notify(PSTR("\r\nThe gyro values has been reset"), 0x80);
00551 #endif
00552                                                                                 gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6));
00553                                                                                 gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6));
00554                                                                                 gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6));
00555 
00556                                                                                 rollGyroScale = 500; // You might need to adjust these
00557                                                                                 pitchGyroScale = 400;
00558                                                                                 yawGyroScale = 415;
00559 
00560                                                                                 gyroYaw = 0;
00561                                                                                 gyroRoll = 0;
00562                                                                                 gyroPitch = 0;
00563 
00564                                                                                 motionValuesReset = true;
00565                                                                                 timer = (uint32_t)micros();
00566                                                                         }
00567                                                                 }
00568                                                         } else {
00569                                                                 if(nunchuckConnected) {
00570                                                                         hatValues[HatX] = l2capinbuf[15];
00571                                                                         hatValues[HatY] = l2capinbuf[16];
00572                                                                         accXnunchuck = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3)) - 416;
00573                                                                         accYnunchuck = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4)) - 416;
00574                                                                         accZnunchuck = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5)) - 416;
00575                                                                 }
00576                                                                 //else if(classicControllerConnected) { }
00577                                                         }
00578                                                         if(l2capinbuf[19] & 0x01) {
00579                                                                 if(!extensionConnected) {
00580                                                                         extensionConnected = true;
00581                                                                         unknownExtensionConnected = true;
00582 #ifdef DEBUG_USB_HOST
00583                                                                         Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80);
00584 #endif
00585                                                                 }
00586                                                         } else {
00587                                                                 if(extensionConnected && !unknownExtensionConnected) {
00588                                                                         extensionConnected = false;
00589                                                                         unknownExtensionConnected = true;
00590 #ifdef DEBUG_USB_HOST
00591                                                                         Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80);
00592 #endif
00593                                                                         nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent
00594                                                                 }
00595                                                         }
00596 
00597                                                 } else if(nunchuckConnected) {
00598                                                         hatValues[HatX] = l2capinbuf[15];
00599                                                         hatValues[HatY] = l2capinbuf[16];
00600                                                         accXnunchuck = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2)) - 416;
00601                                                         accYnunchuck = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4)) - 416;
00602                                                         accZnunchuck = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6)) - 416;
00603                                                 } else if(wiiUProControllerConnected) {
00604                                                         hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8);
00605                                                         hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8);
00606                                                         hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8);
00607                                                         hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8);
00608                                                 }
00609 #endif
00610                                                 break;
00611 #ifdef DEBUG_USB_HOST
00612                                         default:
00613                                                 Notify(PSTR("\r\nUnknown Report type: "), 0x80);
00614                                                 D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
00615                                                 break;
00616 #endif
00617                                 }
00618                         }
00619                 }
00620                 L2CAP_task();
00621         }
00622 }
00623 
00624 void WII::L2CAP_task() {
00625         switch(l2cap_state) {
00626                         /* These states are used if the Wiimote is the host */
00627                 case L2CAP_CONTROL_SUCCESS:
00628                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) {
00629 #ifdef DEBUG_USB_HOST
00630                                 Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
00631 #endif
00632                                 l2cap_state = L2CAP_INTERRUPT_SETUP;
00633                         }
00634                         break;
00635 
00636                 case L2CAP_INTERRUPT_SETUP:
00637                         if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)) {
00638 #ifdef DEBUG_USB_HOST
00639                                 Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
00640 #endif
00641                                 pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
00642                                 wait_ms(1);
00643                                 pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL);
00644                                 identifier++;
00645                                 wait_ms(1);
00646                                 pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
00647 
00648                                 l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
00649                         }
00650                         break;
00651 
00652                         /* These states are used if the Arduino is the host */
00653                 case L2CAP_CONTROL_CONNECT_REQUEST:
00654                         if(l2cap_check_flag(L2CAP_FLAG_CONTROL_CONNECTED)) {
00655 #ifdef DEBUG_USB_HOST
00656                                 Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
00657 #endif
00658                                 identifier++;
00659                                 pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
00660                                 l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
00661                         }
00662                         break;
00663 
00664                 case L2CAP_CONTROL_CONFIG_REQUEST:
00665                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) {
00666 #ifdef DEBUG_USB_HOST
00667                                 Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
00668 #endif
00669                                 identifier++;
00670                                 pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM);
00671                                 l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
00672                         }
00673                         break;
00674 
00675                 case L2CAP_INTERRUPT_CONNECT_REQUEST:
00676                         if(l2cap_check_flag(L2CAP_FLAG_INTERRUPT_CONNECTED)) {
00677 #ifdef DEBUG_USB_HOST
00678                                 Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
00679 #endif
00680                                 identifier++;
00681                                 pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
00682                                 l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
00683                         }
00684                         break;
00685 
00686                 case L2CAP_INTERRUPT_CONFIG_REQUEST:
00687                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established
00688 #ifdef DEBUG_USB_HOST
00689                                 Notify(PSTR("\r\nHID Channels Established"), 0x80);
00690 #endif
00691                                 pBtd->connectToWii = false;
00692                                 pBtd->pairWithWii = false;
00693                                 stateCounter = 0;
00694                                 l2cap_state = WII_CHECK_MOTION_PLUS_STATE;
00695                         }
00696                         break;
00697 
00698                         /* The next states are in run() */
00699 
00700                 case L2CAP_INTERRUPT_DISCONNECT:
00701                         if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE) && ((int32_t)((uint32_t)millis() - timer) >= 0L)) {
00702 #ifdef DEBUG_USB_HOST
00703                                 Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
00704 #endif
00705                                 identifier++;
00706                                 pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
00707                                 l2cap_state = L2CAP_CONTROL_DISCONNECT;
00708                         }
00709                         break;
00710 
00711                 case L2CAP_CONTROL_DISCONNECT:
00712                         if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)) {
00713 #ifdef DEBUG_USB_HOST
00714                                 Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
00715 #endif
00716                                 pBtd->hci_disconnect(hci_handle);
00717                                 hci_handle = -1; // Reset handle
00718                                 l2cap_event_flag = 0; // Reset flags
00719                                 l2cap_state = L2CAP_WAIT;
00720                         }
00721                         break;
00722         }
00723 }
00724 
00725 void WII::Run() {
00726         if(l2cap_state == L2CAP_INTERRUPT_DISCONNECT && ((int32_t)((uint32_t)millis() - timer) >= 0L))
00727                 L2CAP_task(); // Call the rest of the disconnection routine after we have waited long enough
00728 
00729         switch(l2cap_state) {
00730                 case L2CAP_WAIT:
00731                         if(pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) {
00732                                 pBtd->l2capConnectionClaimed = true;
00733                                 activeConnection = true;
00734                                 motionPlusInside = pBtd->motionPlusInside;
00735 #ifdef DEBUG_USB_HOST
00736                                 Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
00737 #endif
00738                                 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
00739                                 l2cap_event_flag = 0; // Reset flags
00740                                 identifier = 0;
00741                                 pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM);
00742                                 l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
00743                         } else if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)) {
00744 #ifdef DEBUG_USB_HOST
00745                                 Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
00746 #endif
00747                                 pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
00748                                 wait_ms(1);
00749                                 pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL);
00750                                 identifier++;
00751                                 wait_ms(1);
00752                                 pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
00753                                 l2cap_state = L2CAP_CONTROL_SUCCESS;
00754                         }
00755                         break;
00756 
00757                 case WII_CHECK_MOTION_PLUS_STATE:
00758 #ifdef DEBUG_USB_HOST
00759                         if(stateCounter == 0) // Only print onnce
00760                                 Notify(PSTR("\r\nChecking if a Motion Plus is connected"), 0x80);
00761 #endif
00762                         stateCounter++;
00763                         if(stateCounter % 200 == 0)
00764                                 checkMotionPresent(); // Check if there is a motion plus connected
00765                         if(wii_check_flag(WII_FLAG_MOTION_PLUS_CONNECTED)) {
00766                                 stateCounter = 0;
00767                                 l2cap_state = WII_INIT_MOTION_PLUS_STATE;
00768                                 timer = (uint32_t)micros();
00769 
00770                                 if(unknownExtensionConnected) {
00771 #ifdef DEBUG_USB_HOST
00772                                         Notify(PSTR("\r\nA extension is also connected"), 0x80);
00773 #endif
00774                                         activateNunchuck = true; // For we will just set this to true as this the only extension supported so far
00775                                 }
00776 
00777                         } else if(stateCounter == 601) { // We will try three times to check for the motion plus
00778 #ifdef DEBUG_USB_HOST
00779                                 Notify(PSTR("\r\nNo Motion Plus was detected"), 0x80);
00780 #endif
00781                                 stateCounter = 0;
00782                                 l2cap_state = WII_CHECK_EXTENSION_STATE;
00783                         }
00784                         break;
00785 
00786                 case WII_CHECK_EXTENSION_STATE: // This is used to check if there is anything plugged in to the extension port
00787 #ifdef DEBUG_USB_HOST
00788                         if(stateCounter == 0) // Only print onnce
00789                                 Notify(PSTR("\r\nChecking if there is any extension connected"), 0x80);
00790 #endif
00791                         stateCounter++; // We use this counter as there has to be a short delay between the commands
00792                         if(stateCounter == 1)
00793                                 statusRequest(); // See if a new device has connected
00794                         if(stateCounter == 100) {
00795                                 if(unknownExtensionConnected) // Check if there is a extension is connected to the port
00796                                         initExtension1();
00797                                 else
00798                                         stateCounter = 499;
00799                         } else if(stateCounter == 200)
00800                                 initExtension2();
00801                         else if(stateCounter == 300) {
00802                                 readExtensionType();
00803                                 unknownExtensionConnected = false;
00804                         } else if(stateCounter == 400) {
00805                                 if(wii_check_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD)) {
00806 #ifdef DEBUG_USB_HOST
00807                                         Notify(PSTR("\r\nReading Wii Balance Board calibration values"), 0x80);
00808 #endif
00809                                         readWiiBalanceBoardCalibration();
00810                                 } else
00811                                         stateCounter = 499;
00812                         } else if(stateCounter == 500) {
00813                                 stateCounter = 0;
00814                                 l2cap_state = TURN_ON_LED;
00815                         }
00816                         break;
00817 
00818                 case WII_INIT_MOTION_PLUS_STATE:
00819                         stateCounter++;
00820                         if(stateCounter == 1)
00821                                 initMotionPlus();
00822                         else if(stateCounter == 100)
00823                                 activateMotionPlus();
00824                         else if(stateCounter == 200)
00825                                 readExtensionType(); // Check if it has been activated
00826                         else if(stateCounter == 300) {
00827                                 stateCounter = 0;
00828                                 unknownExtensionConnected = false; // The motion plus will send a status report when it's activated, we will set this to false so it doesn't reinitialize the Motion Plus
00829                                 l2cap_state = TURN_ON_LED;
00830                         }
00831                         break;
00832 
00833                 case TURN_ON_LED:
00834                         if(wii_check_flag(WII_FLAG_NUNCHUCK_CONNECTED))
00835                                 nunchuckConnected = true;
00836                         wiimoteConnected = true;
00837                         onInit();
00838                         l2cap_state = L2CAP_DONE;
00839                         break;
00840 
00841                 case L2CAP_DONE:
00842                         if(unknownExtensionConnected) {
00843 #ifdef DEBUG_USB_HOST
00844                                 if(stateCounter == 0) // Only print once
00845                                         Notify(PSTR("\r\nChecking extension port"), 0x80);
00846 #endif
00847                                 stateCounter++; // We will use this counter as there has to be a short delay between the commands
00848                                 if(stateCounter == 50)
00849                                         statusRequest();
00850                                 else if(stateCounter == 100)
00851                                         initExtension1();
00852                                 else if(stateCounter == 150)
00853                                         if((extensionConnected && motionPlusConnected) || (unknownExtensionConnected && !motionPlusConnected))
00854                                                 initExtension2();
00855                                         else
00856                                                 stateCounter = 299; // There is no extension connected
00857                                 else if(stateCounter == 200)
00858                                         readExtensionType();
00859                                 else if(stateCounter == 250) {
00860                                         if(wii_check_flag(WII_FLAG_NUNCHUCK_CONNECTED)) {
00861 #ifdef DEBUG_USB_HOST
00862                                                 Notify(PSTR("\r\nNunchuck was reconnected"), 0x80);
00863 #endif
00864                                                 activateNunchuck = true;
00865                                                 nunchuckConnected = true;
00866                                         }
00867                                         if(!motionPlusConnected)
00868                                                 stateCounter = 449;
00869                                 } else if(stateCounter == 300) {
00870                                         if(motionPlusConnected) {
00871 #ifdef DEBUG_USB_HOST
00872                                                 Notify(PSTR("\r\nReactivating the Motion Plus"), 0x80);
00873 #endif
00874                                                 initMotionPlus();
00875                                         } else
00876                                                 stateCounter = 449;
00877                                 } else if(stateCounter == 350)
00878                                         activateMotionPlus();
00879                                 else if(stateCounter == 400)
00880                                         readExtensionType(); // Check if it has been activated
00881                                 else if(stateCounter == 450) {
00882                                         onInit();
00883                                         stateCounter = 0;
00884                                         unknownExtensionConnected = false;
00885                                 }
00886                         } else
00887                                 stateCounter = 0;
00888                         break;
00889         }
00890 }
00891 
00892 /************************************************************/
00893 /*                    HID Commands                          */
00894 /************************************************************/
00895 
00896 void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
00897         if(motionPlusInside)
00898                 pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // It's the new Wiimote with the Motion Plus Inside or Wii U Pro controller
00899         else
00900                 pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]);
00901 }
00902 
00903 void WII::setAllOff() {
00904         HIDBuffer[1] = 0x11;
00905         HIDBuffer[2] = 0x00;
00906         HID_Command(HIDBuffer, 3);
00907 }
00908 
00909 void WII::setRumbleOff() {
00910         HIDBuffer[1] = 0x11;
00911         HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble
00912         HID_Command(HIDBuffer, 3);
00913 }
00914 
00915 void WII::setRumbleOn() {
00916         HIDBuffer[1] = 0x11;
00917         HIDBuffer[2] |= 0x01; // Bit 0 control the rumble
00918         HID_Command(HIDBuffer, 3);
00919 }
00920 
00921 void WII::setRumbleToggle() {
00922         HIDBuffer[1] = 0x11;
00923         HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble
00924         HID_Command(HIDBuffer, 3);
00925 }
00926 
00927 void WII::setLedRaw(uint8_t value) {
00928         HIDBuffer[1] = 0x11;
00929         HIDBuffer[2] = value | (HIDBuffer[2] & 0x01); // Keep the rumble bit
00930         HID_Command(HIDBuffer, 3);
00931 }
00932 
00933 void WII::setLedOff(LEDEnum a) {
00934         HIDBuffer[1] = 0x11;
00935         HIDBuffer[2] &= ~(pgm_read_byte(&WII_LEDS[(uint8_t)a]));
00936         HID_Command(HIDBuffer, 3);
00937 }
00938 
00939 void WII::setLedOn(LEDEnum a) {
00940         if(a == OFF)
00941                 setLedRaw(0);
00942         else {
00943                 HIDBuffer[1] = 0x11;
00944                 HIDBuffer[2] |= pgm_read_byte(&WII_LEDS[(uint8_t)a]);
00945                 HID_Command(HIDBuffer, 3);
00946         }
00947 }
00948 
00949 void WII::setLedToggle(LEDEnum a) {
00950         HIDBuffer[1] = 0x11;
00951         HIDBuffer[2] ^= pgm_read_byte(&WII_LEDS[(uint8_t)a]);
00952         HID_Command(HIDBuffer, 3);
00953 }
00954 
00955 void WII::setLedStatus() {
00956         HIDBuffer[1] = 0x11;
00957         HIDBuffer[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit
00958         if(wiimoteConnected)
00959                 HIDBuffer[2] |= 0x10; // If it's connected LED1 will light up
00960         if(motionPlusConnected)
00961                 HIDBuffer[2] |= 0x20; // If it's connected LED2 will light up
00962         if(nunchuckConnected)
00963                 HIDBuffer[2] |= 0x40; // If it's connected LED3 will light up
00964 
00965         HID_Command(HIDBuffer, 3);
00966 }
00967 
00968 uint8_t WII::getBatteryLevel() {
00969         checkBatteryLevel = true; // This is needed so the library knows that the status response is a response to this function
00970         statusRequest(); // This will update the battery level
00971         return batteryLevel;
00972 };
00973 
00974 void WII::setReportMode(bool continuous, uint8_t mode) {
00975 #ifdef EXTRADEBUG
00976         Notify(PSTR("\r\nReport mode was changed to: "), 0x80);
00977         D_PrintHex<uint8_t > (mode, 0x80);
00978 #endif
00979         uint8_t cmd_buf[4];
00980         cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
00981         cmd_buf[1] = 0x12;
00982         if(continuous)
00983                 cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit
00984         else
00985                 cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Keep the rumble bit
00986         cmd_buf[3] = mode;
00987         HID_Command(cmd_buf, 4);
00988 }
00989 
00990 void WII::statusRequest() {
00991         uint8_t cmd_buf[3];
00992         cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
00993         cmd_buf[1] = 0x15;
00994         cmd_buf[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit
00995         HID_Command(cmd_buf, 3);
00996 }
00997 
00998 /************************************************************/
00999 /*                    Memmory Commands                      */
01000 /************************************************************/
01001 
01002 void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) {
01003         uint8_t cmd_buf[23];
01004         cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
01005         cmd_buf[1] = 0x16; // Write data
01006         cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Write to memory, clear bit 2 to write to EEPROM
01007         cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16);
01008         cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8);
01009         cmd_buf[5] = (uint8_t)(offset & 0xFF);
01010         cmd_buf[6] = size;
01011         uint8_t i = 0;
01012         for(; i < size; i++)
01013                 cmd_buf[7 + i] = data[i];
01014         for(; i < 16; i++) // Set the rest to zero
01015                 cmd_buf[7 + i] = 0x00;
01016         HID_Command(cmd_buf, 23);
01017 }
01018 
01019 void WII::initExtension1() {
01020         uint8_t buf[1];
01021         buf[0] = 0x55;
01022         writeData(0xA400F0, 1, buf);
01023 }
01024 
01025 void WII::initExtension2() {
01026         uint8_t buf[1];
01027         buf[0] = 0x00;
01028         writeData(0xA400FB, 1, buf);
01029 }
01030 
01031 void WII::initMotionPlus() {
01032         uint8_t buf[1];
01033         buf[0] = 0x55;
01034         writeData(0xA600F0, 1, buf);
01035 }
01036 
01037 void WII::activateMotionPlus() {
01038         uint8_t buf[1];
01039         if(pBtd->wiiUProController) {
01040 #ifdef DEBUG_USB_HOST
01041                 Notify(PSTR("\r\nActivating Wii U Pro Controller"), 0x80);
01042 #endif
01043                 buf[0] = 0x00; // It seems like you can send anything but 0x04, 0x05, and 0x07
01044         } else if(activateNunchuck) {
01045 #ifdef DEBUG_USB_HOST
01046                 Notify(PSTR("\r\nActivating Motion Plus in pass-through mode"), 0x80);
01047 #endif
01048                 buf[0] = 0x05; // Activate nunchuck pass-through mode
01049         }//else if(classicControllerConnected && extensionConnected)
01050                 //buf[0] = 0x07;
01051         else {
01052 #ifdef DEBUG_USB_HOST
01053                 Notify(PSTR("\r\nActivating Motion Plus in normal mode"), 0x80);
01054 #endif
01055                 buf[0] = 0x04; // Don't use any extension
01056         }
01057         writeData(0xA600FE, 1, buf);
01058 }
01059 
01060 void WII::readData(uint32_t offset, uint16_t size, bool EEPROM) {
01061         uint8_t cmd_buf[8];
01062         cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
01063         cmd_buf[1] = 0x17; // Read data
01064         if(EEPROM)
01065                 cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Read from EEPROM
01066         else
01067                 cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Read from memory
01068         cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16);
01069         cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8);
01070         cmd_buf[5] = (uint8_t)(offset & 0xFF);
01071         cmd_buf[6] = (uint8_t)((size & 0xFF00) >> 8);
01072         cmd_buf[7] = (uint8_t)(size & 0xFF);
01073 
01074         HID_Command(cmd_buf, 8);
01075 }
01076 
01077 void WII::readExtensionType() {
01078         readData(0xA400FA, 6, false);
01079 }
01080 
01081 void WII::readCalData() {
01082         readData(0x0016, 8, true);
01083 }
01084 
01085 void WII::checkMotionPresent() {
01086         readData(0xA600FA, 6, false);
01087 }
01088 
01089 void WII::readWiiBalanceBoardCalibration() {
01090         readData(0xA40024, 24, false);
01091 }
01092 
01093 /************************************************************/
01094 /*                    WII Commands                          */
01095 /************************************************************/
01096 
01097 bool WII::getButtonPress(ButtonEnum b) { // Return true when a button is pressed
01098         if(wiiUProControllerConnected)
01099                 return (ButtonState & pgm_read_dword(&WII_PROCONTROLLER_BUTTONS[(uint8_t)b]));
01100         else
01101                 return (ButtonState & pgm_read_dword(&WII_BUTTONS[(uint8_t)b]));
01102 }
01103 
01104 bool WII::getButtonClick(ButtonEnum b) { // Only return true when a button is clicked
01105         uint32_t button;
01106         if(wiiUProControllerConnected)
01107                 button = pgm_read_dword(&WII_PROCONTROLLER_BUTTONS[(uint8_t)b]);
01108         else
01109                 button = pgm_read_dword(&WII_BUTTONS[(uint8_t)b]);
01110         bool click = (ButtonClickState & button);
01111         ButtonClickState &= ~button; // clear "click" event
01112         return click;
01113 }
01114 
01115 uint8_t WII::getAnalogHat(HatEnum a) {
01116         if(!nunchuckConnected)
01117                 return 127; // Return center position
01118         else {
01119                 uint8_t output = hatValues[(uint8_t)a];
01120                 if(output == 0xFF || output == 0x00) // The joystick will only read 255 or 0 when the cable is unplugged or initializing, so we will just return the center position
01121                         return 127;
01122                 else
01123                         return output;
01124         }
01125 }
01126 
01127 uint16_t WII::getAnalogHat(AnalogHatEnum a) {
01128         if(!wiiUProControllerConnected)
01129                 return 2000;
01130         else {
01131                 uint16_t output = hatValues[(uint8_t)a];
01132                 if(output == 0x00) // The joystick will only read 0 when it is first initializing, so we will just return the center position
01133                         return 2000;
01134                 else
01135                         return output;
01136         }
01137 }
01138 
01139 void WII::onInit() {
01140         if(pFuncOnInit)
01141                 pFuncOnInit(); // Call the user function
01142         else
01143                 setLedStatus();
01144 }
01145 
01146 /************************************************************/
01147 /*                 Wii Balance Board Commands               */
01148 /************************************************************/
01149 
01150 float WII::getWeight(BalanceBoardEnum pos) {
01151         // Use interpolating between two points - based on: https://github.com/skorokithakis/gr8w8upd8m8/blob/master/gr8w8upd8m8.py
01152         // wiiBalanceBoardCal[pos][0] is calibration values for 0 kg
01153         // wiiBalanceBoardCal[pos][1] is calibration values for 17 kg
01154         // wiiBalanceBoardCal[pos][2] is calibration values for 34 kg
01155         if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[0][pos])
01156             return 0.0f; // Below 0 kg
01157         else if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[1][pos]) // Between 0 and 17 kg
01158             return 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[0][pos]) / (float)(wiiBalanceBoardCal[1][pos] - wiiBalanceBoardCal[0][pos]);
01159         else // More than 17 kg
01160             return 17.0f + 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[1][pos]) / (float)(wiiBalanceBoardCal[2][pos] - wiiBalanceBoardCal[1][pos]);
01161 };
01162 
01163 float WII::getTotalWeight() {
01164         return getWeight(TopRight) + getWeight(BotRight) + getWeight(TopLeft) + getWeight(BotLeft);
01165 };
01166 
01167 /************************************************************/
01168 /*       The following functions are for the IR camera      */
01169 /************************************************************/
01170 
01171 #ifdef WIICAMERA
01172 
01173 void WII::IRinitialize() { // Turns on and initialises the IR camera
01174 
01175         enableIRCamera1();
01176 #ifdef DEBUG_USB_HOST
01177         Notify(PSTR("\r\nEnable IR Camera1 Complete"), 0x80);
01178 #endif
01179         wait_ms(80);
01180 
01181         enableIRCamera2();
01182 #ifdef DEBUG_USB_HOST
01183         Notify(PSTR("\r\nEnable IR Camera2 Complete"), 0x80);
01184 #endif
01185         wait_ms(80);
01186 
01187         write0x08Value();
01188 #ifdef DEBUG_USB_HOST
01189         Notify(PSTR("\r\nWrote hex number 0x08"), 0x80);
01190 #endif
01191         wait_ms(80);
01192 
01193         writeSensitivityBlock1();
01194 #ifdef DEBUG_USB_HOST
01195         Notify(PSTR("\r\nWrote Sensitivity Block 1"), 0x80);
01196 #endif
01197         wait_ms(80);
01198 
01199         writeSensitivityBlock2();
01200 #ifdef DEBUG_USB_HOST
01201         Notify(PSTR("\r\nWrote Sensitivity Block 2"), 0x80);
01202 #endif
01203         wait_ms(80);
01204 
01205         uint8_t mode_num = 0x03;
01206         setWiiModeNumber(mode_num); // Change input for whatever mode you want i.e. 0x01, 0x03, or 0x05
01207 #ifdef DEBUG_USB_HOST
01208         Notify(PSTR("\r\nSet Wii Mode Number To 0x"), 0x80);
01209         D_PrintHex<uint8_t > (mode_num, 0x80);
01210 #endif
01211         wait_ms(80);
01212 
01213         write0x08Value();
01214 #ifdef DEBUG_USB_HOST
01215         Notify(PSTR("\r\nWrote Hex Number 0x08"), 0x80);
01216 #endif
01217         wait_ms(80);
01218 
01219         setReportMode(false, 0x33);
01220         //setReportMode(false, 0x3f); // For full reporting mode, doesn't work yet
01221 #ifdef DEBUG_USB_HOST
01222         Notify(PSTR("\r\nSet Report Mode to 0x33"), 0x80);
01223 #endif
01224         wait_ms(80);
01225 
01226         statusRequest(); // Used to update wiiState - call isIRCameraEnabled() afterwards to check if it actually worked
01227 #ifdef DEBUG_USB_HOST
01228         Notify(PSTR("\r\nIR Initialized"), 0x80);
01229 #endif
01230 }
01231 
01232 void WII::enableIRCamera1() {
01233         uint8_t cmd_buf[3];
01234         cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
01235         cmd_buf[1] = 0x13; // Output report 13
01236         cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2
01237         HID_Command(cmd_buf, 3);
01238 }
01239 
01240 void WII::enableIRCamera2() {
01241         uint8_t cmd_buf[3];
01242         cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
01243         cmd_buf[1] = 0x1A; // Output report 1A
01244         cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2
01245         HID_Command(cmd_buf, 3);
01246 }
01247 
01248 void WII::writeSensitivityBlock1() {
01249         uint8_t buf[9];
01250         buf[0] = 0x00;
01251         buf[1] = 0x00;
01252         buf[2] = 0x00;
01253         buf[3] = 0x00;
01254         buf[4] = 0x00;
01255         buf[5] = 0x00;
01256         buf[6] = 0x90;
01257         buf[7] = 0x00;
01258         buf[8] = 0x41;
01259 
01260         writeData(0xB00000, 9, buf);
01261 }
01262 
01263 void WII::writeSensitivityBlock2() {
01264         uint8_t buf[2];
01265         buf[0] = 0x40;
01266         buf[1] = 0x00;
01267 
01268         writeData(0xB0001A, 2, buf);
01269 }
01270 
01271 void WII::write0x08Value() {
01272         uint8_t cmd = 0x08;
01273         writeData(0xb00030, 1, &cmd);
01274 }
01275 
01276 void WII::setWiiModeNumber(uint8_t mode_number) { // mode_number in hex i.e. 0x03 for extended mode
01277         writeData(0xb00033, 1, &mode_number);
01278 }
01279 #endif