Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: UsbHostMAX3421E_Hello
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
Generated on Tue Jul 12 2022 18:12:05 by
1.7.2