MAX3421E-based USB Host Shield Library
Dependents: UsbHostMAX3421E_Hello
Wii.cpp@1:2263e77400e9, 2020-07-13 (annotated)
- Committer:
- hudakz
- Date:
- Mon Jul 13 07:03:06 2020 +0000
- Revision:
- 1:2263e77400e9
- Parent:
- 0:84353c479782
MAX3421E-based USB Host Shield Library
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:84353c479782 | 1 | /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved. |
hudakz | 0:84353c479782 | 2 | |
hudakz | 0:84353c479782 | 3 | This software may be distributed and modified under the terms of the GNU |
hudakz | 0:84353c479782 | 4 | General Public License version 2 (GPL2) as published by the Free Software |
hudakz | 0:84353c479782 | 5 | Foundation and appearing in the file GPL2.TXT included in the packaging of |
hudakz | 0:84353c479782 | 6 | this file. Please note that GPL2 Section 2[b] requires that all works based |
hudakz | 0:84353c479782 | 7 | on this software must also be made publicly available under the terms of |
hudakz | 0:84353c479782 | 8 | the GPL2 ("Copyleft"). |
hudakz | 0:84353c479782 | 9 | |
hudakz | 0:84353c479782 | 10 | Contact information |
hudakz | 0:84353c479782 | 11 | ------------------- |
hudakz | 0:84353c479782 | 12 | |
hudakz | 0:84353c479782 | 13 | Kristian Lauszus, TKJ Electronics |
hudakz | 0:84353c479782 | 14 | Web : http://www.tkjelectronics.com |
hudakz | 0:84353c479782 | 15 | e-mail : kristianl@tkjelectronics.com |
hudakz | 0:84353c479782 | 16 | |
hudakz | 0:84353c479782 | 17 | IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus |
hudakz | 0:84353c479782 | 18 | */ |
hudakz | 0:84353c479782 | 19 | |
hudakz | 0:84353c479782 | 20 | #include "Wii.h" |
hudakz | 0:84353c479782 | 21 | // To enable serial debugging see "settings.h" |
hudakz | 0:84353c479782 | 22 | //#define EXTRADEBUG // Uncomment to get even more debugging data |
hudakz | 0:84353c479782 | 23 | //#define PRINTREPORT // Uncomment to print the report send by the Wii controllers |
hudakz | 0:84353c479782 | 24 | |
hudakz | 0:84353c479782 | 25 | const uint8_t WII_LEDS[] PROGMEM = { |
hudakz | 0:84353c479782 | 26 | 0x00, // OFF |
hudakz | 0:84353c479782 | 27 | 0x10, // LED1 |
hudakz | 0:84353c479782 | 28 | 0x20, // LED2 |
hudakz | 0:84353c479782 | 29 | 0x40, // LED3 |
hudakz | 0:84353c479782 | 30 | 0x80, // LED4 |
hudakz | 0:84353c479782 | 31 | |
hudakz | 0:84353c479782 | 32 | 0x90, // LED5 |
hudakz | 0:84353c479782 | 33 | 0xA0, // LED6 |
hudakz | 0:84353c479782 | 34 | 0xC0, // LED7 |
hudakz | 0:84353c479782 | 35 | 0xD0, // LED8 |
hudakz | 0:84353c479782 | 36 | 0xE0, // LED9 |
hudakz | 0:84353c479782 | 37 | 0xF0, // LED10 |
hudakz | 0:84353c479782 | 38 | }; |
hudakz | 0:84353c479782 | 39 | |
hudakz | 0:84353c479782 | 40 | const uint32_t WII_BUTTONS[] PROGMEM = { |
hudakz | 0:84353c479782 | 41 | 0x00008, // UP |
hudakz | 0:84353c479782 | 42 | 0x00002, // RIGHT |
hudakz | 0:84353c479782 | 43 | 0x00004, // DOWN |
hudakz | 0:84353c479782 | 44 | 0x00001, // LEFT |
hudakz | 0:84353c479782 | 45 | |
hudakz | 0:84353c479782 | 46 | 0, // Skip |
hudakz | 0:84353c479782 | 47 | 0x00010, // PLUS |
hudakz | 0:84353c479782 | 48 | 0x00100, // TWO |
hudakz | 0:84353c479782 | 49 | 0x00200, // ONE |
hudakz | 0:84353c479782 | 50 | |
hudakz | 0:84353c479782 | 51 | 0x01000, // MINUS |
hudakz | 0:84353c479782 | 52 | 0x08000, // HOME |
hudakz | 0:84353c479782 | 53 | 0x10000, // Z |
hudakz | 0:84353c479782 | 54 | 0x20000, // C |
hudakz | 0:84353c479782 | 55 | |
hudakz | 0:84353c479782 | 56 | 0x00400, // B |
hudakz | 0:84353c479782 | 57 | 0x00800, // A |
hudakz | 0:84353c479782 | 58 | }; |
hudakz | 0:84353c479782 | 59 | const uint32_t WII_PROCONTROLLER_BUTTONS[] PROGMEM = { |
hudakz | 0:84353c479782 | 60 | 0x00100, // UP |
hudakz | 0:84353c479782 | 61 | 0x00080, // RIGHT |
hudakz | 0:84353c479782 | 62 | 0x00040, // DOWN |
hudakz | 0:84353c479782 | 63 | 0x00200, // LEFT |
hudakz | 0:84353c479782 | 64 | |
hudakz | 0:84353c479782 | 65 | 0, // Skip |
hudakz | 0:84353c479782 | 66 | 0x00004, // PLUS |
hudakz | 0:84353c479782 | 67 | 0x20000, // L3 |
hudakz | 0:84353c479782 | 68 | 0x10000, // R3 |
hudakz | 0:84353c479782 | 69 | |
hudakz | 0:84353c479782 | 70 | 0x00010, // MINUS |
hudakz | 0:84353c479782 | 71 | 0x00008, // HOME |
hudakz | 0:84353c479782 | 72 | 0, 0, // Skip |
hudakz | 0:84353c479782 | 73 | |
hudakz | 0:84353c479782 | 74 | 0x04000, // B |
hudakz | 0:84353c479782 | 75 | 0x01000, // A |
hudakz | 0:84353c479782 | 76 | 0x00800, // X |
hudakz | 0:84353c479782 | 77 | 0x02000, // Y |
hudakz | 0:84353c479782 | 78 | |
hudakz | 0:84353c479782 | 79 | 0x00020, // L |
hudakz | 0:84353c479782 | 80 | 0x00002, // R |
hudakz | 0:84353c479782 | 81 | 0x08000, // ZL |
hudakz | 0:84353c479782 | 82 | 0x00400, // ZR |
hudakz | 0:84353c479782 | 83 | }; |
hudakz | 0:84353c479782 | 84 | |
hudakz | 0:84353c479782 | 85 | WII::WII(BTD *p, bool pair) : |
hudakz | 0:84353c479782 | 86 | BluetoothService(p) // Pointer to USB class instance - mandatory |
hudakz | 0:84353c479782 | 87 | { |
hudakz | 0:84353c479782 | 88 | pBtd->pairWithWii = pair; |
hudakz | 0:84353c479782 | 89 | |
hudakz | 0:84353c479782 | 90 | HIDBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 91 | |
hudakz | 0:84353c479782 | 92 | /* Set device cid for the control and intterrupt channelse - LSB */ |
hudakz | 0:84353c479782 | 93 | control_dcid[0] = 0x60; // 0x0060 |
hudakz | 0:84353c479782 | 94 | control_dcid[1] = 0x00; |
hudakz | 0:84353c479782 | 95 | interrupt_dcid[0] = 0x61; // 0x0061 |
hudakz | 0:84353c479782 | 96 | interrupt_dcid[1] = 0x00; |
hudakz | 0:84353c479782 | 97 | |
hudakz | 0:84353c479782 | 98 | Reset(); |
hudakz | 0:84353c479782 | 99 | } |
hudakz | 0:84353c479782 | 100 | |
hudakz | 0:84353c479782 | 101 | void WII::Reset() { |
hudakz | 0:84353c479782 | 102 | wiimoteConnected = false; |
hudakz | 0:84353c479782 | 103 | nunchuckConnected = false; |
hudakz | 0:84353c479782 | 104 | motionPlusConnected = false; |
hudakz | 0:84353c479782 | 105 | activateNunchuck = false; |
hudakz | 0:84353c479782 | 106 | motionValuesReset = false; |
hudakz | 0:84353c479782 | 107 | activeConnection = false; |
hudakz | 0:84353c479782 | 108 | motionPlusInside = false; |
hudakz | 0:84353c479782 | 109 | pBtd->wiiUProController = false; |
hudakz | 0:84353c479782 | 110 | wiiUProControllerConnected = false; |
hudakz | 0:84353c479782 | 111 | wiiBalanceBoardConnected = false; |
hudakz | 0:84353c479782 | 112 | l2cap_event_flag = 0; // Reset flags |
hudakz | 0:84353c479782 | 113 | l2cap_state = L2CAP_WAIT; |
hudakz | 0:84353c479782 | 114 | } |
hudakz | 0:84353c479782 | 115 | |
hudakz | 0:84353c479782 | 116 | void WII::disconnect() { // Use this void to disconnect any of the controllers |
hudakz | 0:84353c479782 | 117 | if(!motionPlusInside) { // The old Wiimote needs a delay after the first command or it will automatically reconnect |
hudakz | 0:84353c479782 | 118 | if(motionPlusConnected) { |
hudakz | 0:84353c479782 | 119 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 120 | Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80); |
hudakz | 0:84353c479782 | 121 | #endif |
hudakz | 0:84353c479782 | 122 | initExtension1(); // This will disable the Motion Plus extension |
hudakz | 0:84353c479782 | 123 | } |
hudakz | 0:84353c479782 | 124 | timer = (uint32_t)millis() + 1000; // We have to wait for the message before the rest of the channels can be deactivated |
hudakz | 0:84353c479782 | 125 | } else |
hudakz | 0:84353c479782 | 126 | timer = (uint32_t)millis(); // Don't wait |
hudakz | 0:84353c479782 | 127 | // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection |
hudakz | 0:84353c479782 | 128 | pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid); |
hudakz | 0:84353c479782 | 129 | Reset(); |
hudakz | 0:84353c479782 | 130 | l2cap_state = L2CAP_INTERRUPT_DISCONNECT; |
hudakz | 0:84353c479782 | 131 | } |
hudakz | 0:84353c479782 | 132 | |
hudakz | 0:84353c479782 | 133 | void WII::ACLData(uint8_t* l2capinbuf) { |
hudakz | 0:84353c479782 | 134 | if(!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) { |
hudakz | 0:84353c479782 | 135 | if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { |
hudakz | 0:84353c479782 | 136 | if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { |
hudakz | 0:84353c479782 | 137 | motionPlusInside = pBtd->motionPlusInside; |
hudakz | 0:84353c479782 | 138 | pBtd->incomingWii = false; |
hudakz | 0:84353c479782 | 139 | pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service |
hudakz | 0:84353c479782 | 140 | activeConnection = true; |
hudakz | 0:84353c479782 | 141 | hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection |
hudakz | 0:84353c479782 | 142 | l2cap_state = L2CAP_WAIT; |
hudakz | 0:84353c479782 | 143 | } |
hudakz | 0:84353c479782 | 144 | } |
hudakz | 0:84353c479782 | 145 | } |
hudakz | 0:84353c479782 | 146 | |
hudakz | 0:84353c479782 | 147 | if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok |
hudakz | 0:84353c479782 | 148 | if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U |
hudakz | 0:84353c479782 | 149 | if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { |
hudakz | 0:84353c479782 | 150 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 151 | Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80); |
hudakz | 0:84353c479782 | 152 | D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); |
hudakz | 0:84353c479782 | 153 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 154 | D_PrintHex<uint8_t > (l2capinbuf[12], 0x80); |
hudakz | 0:84353c479782 | 155 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 156 | D_PrintHex<uint8_t > (l2capinbuf[17], 0x80); |
hudakz | 0:84353c479782 | 157 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 158 | D_PrintHex<uint8_t > (l2capinbuf[16], 0x80); |
hudakz | 0:84353c479782 | 159 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 160 | D_PrintHex<uint8_t > (l2capinbuf[15], 0x80); |
hudakz | 0:84353c479782 | 161 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 162 | D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); |
hudakz | 0:84353c479782 | 163 | #endif |
hudakz | 0:84353c479782 | 164 | } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) { |
hudakz | 0:84353c479782 | 165 | if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success |
hudakz | 0:84353c479782 | 166 | if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { |
hudakz | 0:84353c479782 | 167 | //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80); |
hudakz | 0:84353c479782 | 168 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 169 | control_scid[0] = l2capinbuf[12]; |
hudakz | 0:84353c479782 | 170 | control_scid[1] = l2capinbuf[13]; |
hudakz | 0:84353c479782 | 171 | l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED); |
hudakz | 0:84353c479782 | 172 | } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) { |
hudakz | 0:84353c479782 | 173 | //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80); |
hudakz | 0:84353c479782 | 174 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 175 | interrupt_scid[0] = l2capinbuf[12]; |
hudakz | 0:84353c479782 | 176 | interrupt_scid[1] = l2capinbuf[13]; |
hudakz | 0:84353c479782 | 177 | l2cap_set_flag(L2CAP_FLAG_INTERRUPT_CONNECTED); |
hudakz | 0:84353c479782 | 178 | } |
hudakz | 0:84353c479782 | 179 | } |
hudakz | 0:84353c479782 | 180 | } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { |
hudakz | 0:84353c479782 | 181 | #ifdef EXTRADEBUG |
hudakz | 0:84353c479782 | 182 | Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80); |
hudakz | 0:84353c479782 | 183 | D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); |
hudakz | 0:84353c479782 | 184 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 185 | D_PrintHex<uint8_t > (l2capinbuf[12], 0x80); |
hudakz | 0:84353c479782 | 186 | Notify(PSTR(" SCID: "), 0x80); |
hudakz | 0:84353c479782 | 187 | D_PrintHex<uint8_t > (l2capinbuf[15], 0x80); |
hudakz | 0:84353c479782 | 188 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 189 | D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); |
hudakz | 0:84353c479782 | 190 | Notify(PSTR(" Identifier: "), 0x80); |
hudakz | 0:84353c479782 | 191 | D_PrintHex<uint8_t > (l2capinbuf[9], 0x80); |
hudakz | 0:84353c479782 | 192 | #endif |
hudakz | 0:84353c479782 | 193 | if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { |
hudakz | 0:84353c479782 | 194 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 195 | control_scid[0] = l2capinbuf[14]; |
hudakz | 0:84353c479782 | 196 | control_scid[1] = l2capinbuf[15]; |
hudakz | 0:84353c479782 | 197 | l2cap_set_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST); |
hudakz | 0:84353c479782 | 198 | } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) { |
hudakz | 0:84353c479782 | 199 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 200 | interrupt_scid[0] = l2capinbuf[14]; |
hudakz | 0:84353c479782 | 201 | interrupt_scid[1] = l2capinbuf[15]; |
hudakz | 0:84353c479782 | 202 | l2cap_set_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST); |
hudakz | 0:84353c479782 | 203 | } |
hudakz | 0:84353c479782 | 204 | } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { |
hudakz | 0:84353c479782 | 205 | if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success |
hudakz | 0:84353c479782 | 206 | if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { |
hudakz | 0:84353c479782 | 207 | //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); |
hudakz | 0:84353c479782 | 208 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 209 | l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS); |
hudakz | 0:84353c479782 | 210 | } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { |
hudakz | 0:84353c479782 | 211 | //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80); |
hudakz | 0:84353c479782 | 212 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 213 | l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS); |
hudakz | 0:84353c479782 | 214 | } |
hudakz | 0:84353c479782 | 215 | } |
hudakz | 0:84353c479782 | 216 | } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { |
hudakz | 0:84353c479782 | 217 | if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { |
hudakz | 0:84353c479782 | 218 | //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80); |
hudakz | 0:84353c479782 | 219 | pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid); |
hudakz | 0:84353c479782 | 220 | } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { |
hudakz | 0:84353c479782 | 221 | //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80); |
hudakz | 0:84353c479782 | 222 | pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid); |
hudakz | 0:84353c479782 | 223 | } |
hudakz | 0:84353c479782 | 224 | } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { |
hudakz | 0:84353c479782 | 225 | if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { |
hudakz | 0:84353c479782 | 226 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 227 | Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80); |
hudakz | 0:84353c479782 | 228 | #endif |
hudakz | 0:84353c479782 | 229 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 230 | pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid); |
hudakz | 0:84353c479782 | 231 | Reset(); |
hudakz | 0:84353c479782 | 232 | } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { |
hudakz | 0:84353c479782 | 233 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 234 | Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80); |
hudakz | 0:84353c479782 | 235 | #endif |
hudakz | 0:84353c479782 | 236 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 237 | pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid); |
hudakz | 0:84353c479782 | 238 | Reset(); |
hudakz | 0:84353c479782 | 239 | } |
hudakz | 0:84353c479782 | 240 | } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { |
hudakz | 0:84353c479782 | 241 | if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { |
hudakz | 0:84353c479782 | 242 | //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80); |
hudakz | 0:84353c479782 | 243 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 244 | l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE); |
hudakz | 0:84353c479782 | 245 | } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { |
hudakz | 0:84353c479782 | 246 | //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80); |
hudakz | 0:84353c479782 | 247 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 248 | l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE); |
hudakz | 0:84353c479782 | 249 | } |
hudakz | 0:84353c479782 | 250 | } |
hudakz | 0:84353c479782 | 251 | #ifdef EXTRADEBUG |
hudakz | 0:84353c479782 | 252 | else { |
hudakz | 0:84353c479782 | 253 | identifier = l2capinbuf[9]; |
hudakz | 0:84353c479782 | 254 | Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); |
hudakz | 0:84353c479782 | 255 | D_PrintHex<uint8_t > (l2capinbuf[8], 0x80); |
hudakz | 0:84353c479782 | 256 | } |
hudakz | 0:84353c479782 | 257 | #endif |
hudakz | 0:84353c479782 | 258 | } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt |
hudakz | 0:84353c479782 | 259 | //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80); |
hudakz | 0:84353c479782 | 260 | if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT |
hudakz | 0:84353c479782 | 261 | if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons |
hudakz | 0:84353c479782 | 262 | if((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes |
hudakz | 0:84353c479782 | 263 | ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); |
hudakz | 0:84353c479782 | 264 | else if(wiiUProControllerConnected) |
hudakz | 0:84353c479782 | 265 | ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16)); |
hudakz | 0:84353c479782 | 266 | else if(motionPlusConnected) { |
hudakz | 0:84353c479782 | 267 | if(l2capinbuf[20] & 0x02) // Only update the Wiimote buttons, since the extension bytes are from the Motion Plus |
hudakz | 0:84353c479782 | 268 | ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000))); |
hudakz | 0:84353c479782 | 269 | else if(nunchuckConnected) // Update if it's a report from the Nunchuck |
hudakz | 0:84353c479782 | 270 | ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14)); |
hudakz | 0:84353c479782 | 271 | //else if(classicControllerConnected) // Update if it's a report from the Classic Controller |
hudakz | 0:84353c479782 | 272 | } else if(nunchuckConnected) // The Nunchuck is directly connected |
hudakz | 0:84353c479782 | 273 | ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x03) << 16)); |
hudakz | 0:84353c479782 | 274 | //else if(classicControllerConnected) // The Classic Controller is directly connected |
hudakz | 0:84353c479782 | 275 | else if(!unknownExtensionConnected) |
hudakz | 0:84353c479782 | 276 | ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8)); |
hudakz | 0:84353c479782 | 277 | #ifdef PRINTREPORT |
hudakz | 0:84353c479782 | 278 | Notify(PSTR("ButtonState: "), 0x80); |
hudakz | 0:84353c479782 | 279 | D_PrintHex<uint32_t > (ButtonState, 0x80); |
hudakz | 0:84353c479782 | 280 | Notify(PSTR("\r\n"), 0x80); |
hudakz | 0:84353c479782 | 281 | #endif |
hudakz | 0:84353c479782 | 282 | if(ButtonState != OldButtonState) { |
hudakz | 0:84353c479782 | 283 | ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable |
hudakz | 0:84353c479782 | 284 | OldButtonState = ButtonState; |
hudakz | 0:84353c479782 | 285 | } |
hudakz | 0:84353c479782 | 286 | } |
hudakz | 0:84353c479782 | 287 | if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33 || l2capinbuf[9] == 0x35 || l2capinbuf[9] == 0x37) { // Read the accelerometer |
hudakz | 0:84353c479782 | 288 | accXwiimote = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5)) - 500; |
hudakz | 0:84353c479782 | 289 | accYwiimote = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4)) - 500; |
hudakz | 0:84353c479782 | 290 | accZwiimote = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5)) - 500; |
hudakz | 0:84353c479782 | 291 | } |
hudakz | 0:84353c479782 | 292 | switch(l2capinbuf[9]) { |
hudakz | 0:84353c479782 | 293 | case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV |
hudakz | 0:84353c479782 | 294 | #ifdef EXTRADEBUG |
hudakz | 0:84353c479782 | 295 | Notify(PSTR("\r\nStatus report was received"), 0x80); |
hudakz | 0:84353c479782 | 296 | #endif |
hudakz | 0:84353c479782 | 297 | 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) |
hudakz | 0:84353c479782 | 298 | batteryLevel = l2capinbuf[15]; // Update battery level |
hudakz | 0:84353c479782 | 299 | |
hudakz | 0:84353c479782 | 300 | if(!checkBatteryLevel) { // If this is true it means that the user must have called getBatteryLevel() |
hudakz | 0:84353c479782 | 301 | if(l2capinbuf[12] & 0x02) { // Check if a extension is connected |
hudakz | 0:84353c479782 | 302 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 303 | if(!unknownExtensionConnected) |
hudakz | 0:84353c479782 | 304 | Notify(PSTR("\r\nExtension connected"), 0x80); |
hudakz | 0:84353c479782 | 305 | #endif |
hudakz | 0:84353c479782 | 306 | unknownExtensionConnected = true; |
hudakz | 0:84353c479782 | 307 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 308 | if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera |
hudakz | 0:84353c479782 | 309 | #endif |
hudakz | 0:84353c479782 | 310 | setReportMode(false, 0x35); // Also read the extension |
hudakz | 0:84353c479782 | 311 | } else { |
hudakz | 0:84353c479782 | 312 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 313 | Notify(PSTR("\r\nExtension disconnected"), 0x80); |
hudakz | 0:84353c479782 | 314 | #endif |
hudakz | 0:84353c479782 | 315 | if(motionPlusConnected) { |
hudakz | 0:84353c479782 | 316 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 317 | Notify(PSTR(" - from Motion Plus"), 0x80); |
hudakz | 0:84353c479782 | 318 | #endif |
hudakz | 0:84353c479782 | 319 | wii_clear_flag(WII_FLAG_NUNCHUCK_CONNECTED); |
hudakz | 0:84353c479782 | 320 | if(!activateNunchuck) // If it's already trying to initialize the Nunchuck don't set it to false |
hudakz | 0:84353c479782 | 321 | nunchuckConnected = false; |
hudakz | 0:84353c479782 | 322 | //else if(classicControllerConnected) |
hudakz | 0:84353c479782 | 323 | } else if(nunchuckConnected) { |
hudakz | 0:84353c479782 | 324 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 325 | Notify(PSTR(" - Nunchuck"), 0x80); |
hudakz | 0:84353c479782 | 326 | #endif |
hudakz | 0:84353c479782 | 327 | nunchuckConnected = false; // It must be the Nunchuck controller then |
hudakz | 0:84353c479782 | 328 | wii_clear_flag(WII_FLAG_NUNCHUCK_CONNECTED); |
hudakz | 0:84353c479782 | 329 | onInit(); |
hudakz | 0:84353c479782 | 330 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 331 | if(!isIRCameraEnabled()) // We still want to read from the IR camera, so do not change the report mode |
hudakz | 0:84353c479782 | 332 | #endif |
hudakz | 0:84353c479782 | 333 | setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer |
hudakz | 0:84353c479782 | 334 | } else { |
hudakz | 0:84353c479782 | 335 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 336 | if(!isIRCameraEnabled()) // We still want to read from the IR camera, so do not change the report mode |
hudakz | 0:84353c479782 | 337 | #endif |
hudakz | 0:84353c479782 | 338 | setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer |
hudakz | 0:84353c479782 | 339 | } |
hudakz | 0:84353c479782 | 340 | } |
hudakz | 0:84353c479782 | 341 | } |
hudakz | 0:84353c479782 | 342 | else { |
hudakz | 0:84353c479782 | 343 | #ifdef EXTRADEBUG |
hudakz | 0:84353c479782 | 344 | Notify(PSTR("\r\nChecking battery level"), 0x80); |
hudakz | 0:84353c479782 | 345 | #endif |
hudakz | 0:84353c479782 | 346 | checkBatteryLevel = false; // Check for extensions by default |
hudakz | 0:84353c479782 | 347 | } |
hudakz | 0:84353c479782 | 348 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 349 | if(l2capinbuf[12] & 0x01) |
hudakz | 0:84353c479782 | 350 | Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80); |
hudakz | 0:84353c479782 | 351 | #endif |
hudakz | 0:84353c479782 | 352 | |
hudakz | 0:84353c479782 | 353 | break; |
hudakz | 0:84353c479782 | 354 | case 0x21: // Read Memory Data |
hudakz | 0:84353c479782 | 355 | if((l2capinbuf[12] & 0x0F) == 0) { // No error |
hudakz | 0:84353c479782 | 356 | uint8_t reportLength = (l2capinbuf[12] >> 4) + 1; // // Bit 4-7 is the length - 1 |
hudakz | 0:84353c479782 | 357 | // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers |
hudakz | 0:84353c479782 | 358 | if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { |
hudakz | 0:84353c479782 | 359 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 360 | Notify(PSTR("\r\nNunchuck connected"), 0x80); |
hudakz | 0:84353c479782 | 361 | #endif |
hudakz | 0:84353c479782 | 362 | wii_set_flag(WII_FLAG_NUNCHUCK_CONNECTED); |
hudakz | 0:84353c479782 | 363 | } else if(l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) { |
hudakz | 0:84353c479782 | 364 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 365 | Notify(PSTR("\r\nMotion Plus connected"), 0x80); |
hudakz | 0:84353c479782 | 366 | #endif |
hudakz | 0:84353c479782 | 367 | wii_set_flag(WII_FLAG_MOTION_PLUS_CONNECTED); |
hudakz | 0:84353c479782 | 368 | } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) { |
hudakz | 0:84353c479782 | 369 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 370 | Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80); |
hudakz | 0:84353c479782 | 371 | #endif |
hudakz | 0:84353c479782 | 372 | motionPlusConnected = true; |
hudakz | 0:84353c479782 | 373 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 374 | if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera |
hudakz | 0:84353c479782 | 375 | #endif |
hudakz | 0:84353c479782 | 376 | setReportMode(false, 0x35); // Also read the extension |
hudakz | 0:84353c479782 | 377 | } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) { |
hudakz | 0:84353c479782 | 378 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 379 | Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80); |
hudakz | 0:84353c479782 | 380 | #endif |
hudakz | 0:84353c479782 | 381 | activateNunchuck = false; |
hudakz | 0:84353c479782 | 382 | motionPlusConnected = true; |
hudakz | 0:84353c479782 | 383 | nunchuckConnected = true; |
hudakz | 0:84353c479782 | 384 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 385 | if(!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera |
hudakz | 0:84353c479782 | 386 | #endif |
hudakz | 0:84353c479782 | 387 | setReportMode(false, 0x35); // Also read the extension |
hudakz | 0:84353c479782 | 388 | } 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) { |
hudakz | 0:84353c479782 | 389 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 390 | Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80); |
hudakz | 0:84353c479782 | 391 | Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80); |
hudakz | 0:84353c479782 | 392 | #endif |
hudakz | 0:84353c479782 | 393 | stateCounter = 300; // Skip the rest in "WII_CHECK_MOTION_PLUS_STATE" |
hudakz | 0:84353c479782 | 394 | } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) { |
hudakz | 0:84353c479782 | 395 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 396 | Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80); |
hudakz | 0:84353c479782 | 397 | #endif |
hudakz | 0:84353c479782 | 398 | wiiUProControllerConnected = true; |
hudakz | 0:84353c479782 | 399 | } else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x02) { |
hudakz | 0:84353c479782 | 400 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 401 | Notify(PSTR("\r\nWii Balance Board connected"), 0x80); |
hudakz | 0:84353c479782 | 402 | #endif |
hudakz | 0:84353c479782 | 403 | setReportMode(false, 0x32); // Read the Wii Balance Board extension |
hudakz | 0:84353c479782 | 404 | wii_set_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD); |
hudakz | 0:84353c479782 | 405 | } |
hudakz | 0:84353c479782 | 406 | // Wii Balance Board calibration reports (24 bits in total) |
hudakz | 0:84353c479782 | 407 | else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x24 && reportLength == 16) { // First 16-bit |
hudakz | 0:84353c479782 | 408 | for(uint8_t i = 0; i < 2; i++) { |
hudakz | 0:84353c479782 | 409 | for(uint8_t j = 0; j < 4; j++) |
hudakz | 0:84353c479782 | 410 | wiiBalanceBoardCal[i][j] = l2capinbuf[16 + 8 * i + 2 * j] | l2capinbuf[15 + 8 * i + 2 * j] << 8; |
hudakz | 0:84353c479782 | 411 | } |
hudakz | 0:84353c479782 | 412 | } else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x34 && reportLength == 8) { // Last 8-bit |
hudakz | 0:84353c479782 | 413 | for(uint8_t j = 0; j < 4; j++) |
hudakz | 0:84353c479782 | 414 | wiiBalanceBoardCal[2][j] = l2capinbuf[16 + 2 * j] | l2capinbuf[15 + 2 * j] << 8; |
hudakz | 0:84353c479782 | 415 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 416 | Notify(PSTR("\r\nWii Balance Board calibration values read successfully"), 0x80); |
hudakz | 0:84353c479782 | 417 | #endif |
hudakz | 0:84353c479782 | 418 | wii_clear_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD); |
hudakz | 0:84353c479782 | 419 | wiiBalanceBoardConnected = true; |
hudakz | 0:84353c479782 | 420 | } |
hudakz | 0:84353c479782 | 421 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 422 | else { |
hudakz | 0:84353c479782 | 423 | Notify(PSTR("\r\nUnknown Device: "), 0x80); |
hudakz | 0:84353c479782 | 424 | D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); |
hudakz | 0:84353c479782 | 425 | D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); |
hudakz | 0:84353c479782 | 426 | Notify(PSTR("\r\nData: "), 0x80); |
hudakz | 0:84353c479782 | 427 | for(uint8_t i = 0; i < reportLength; i++) { |
hudakz | 0:84353c479782 | 428 | D_PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80); |
hudakz | 0:84353c479782 | 429 | Notify(PSTR(" "), 0x80); |
hudakz | 0:84353c479782 | 430 | } |
hudakz | 0:84353c479782 | 431 | } |
hudakz | 0:84353c479782 | 432 | #endif |
hudakz | 0:84353c479782 | 433 | } |
hudakz | 0:84353c479782 | 434 | #ifdef EXTRADEBUG |
hudakz | 0:84353c479782 | 435 | else { |
hudakz | 0:84353c479782 | 436 | Notify(PSTR("\r\nReport Error: "), 0x80); |
hudakz | 0:84353c479782 | 437 | D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); |
hudakz | 0:84353c479782 | 438 | D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); |
hudakz | 0:84353c479782 | 439 | } |
hudakz | 0:84353c479782 | 440 | #endif |
hudakz | 0:84353c479782 | 441 | break; |
hudakz | 0:84353c479782 | 442 | case 0x22: // Acknowledge output report, return function result |
hudakz | 0:84353c479782 | 443 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 444 | if(l2capinbuf[13] != 0x00) { // Check if there is an error |
hudakz | 0:84353c479782 | 445 | Notify(PSTR("\r\nCommand failed: "), 0x80); |
hudakz | 0:84353c479782 | 446 | D_PrintHex<uint8_t > (l2capinbuf[12], 0x80); |
hudakz | 0:84353c479782 | 447 | } |
hudakz | 0:84353c479782 | 448 | #endif |
hudakz | 0:84353c479782 | 449 | break; |
hudakz | 0:84353c479782 | 450 | case 0x30: // Core buttons - (a1) 30 BB BB |
hudakz | 0:84353c479782 | 451 | break; |
hudakz | 0:84353c479782 | 452 | case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA |
hudakz | 0:84353c479782 | 453 | break; |
hudakz | 0:84353c479782 | 454 | case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE |
hudakz | 0:84353c479782 | 455 | // See: http://wiibrew.org/wiki/Wii_Balance_Board#Data_Format |
hudakz | 0:84353c479782 | 456 | wiiBalanceBoardRaw[TopRight] = l2capinbuf[13] | l2capinbuf[12] << 8; // Top right |
hudakz | 0:84353c479782 | 457 | wiiBalanceBoardRaw[BotRight] = l2capinbuf[15] | l2capinbuf[14] << 8; // Bottom right |
hudakz | 0:84353c479782 | 458 | wiiBalanceBoardRaw[TopLeft] = l2capinbuf[17] | l2capinbuf[16] << 8; // Top left |
hudakz | 0:84353c479782 | 459 | wiiBalanceBoardRaw[BotLeft] = l2capinbuf[19] | l2capinbuf[18] << 8; // Bottom left |
hudakz | 0:84353c479782 | 460 | break; |
hudakz | 0:84353c479782 | 461 | 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 |
hudakz | 0:84353c479782 | 462 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 463 | // Read the IR data |
hudakz | 0:84353c479782 | 464 | IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position |
hudakz | 0:84353c479782 | 465 | IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position |
hudakz | 0:84353c479782 | 466 | IR_object_s1 = (l2capinbuf[17] & 0x0F); // Size value, 0-15 |
hudakz | 0:84353c479782 | 467 | |
hudakz | 0:84353c479782 | 468 | IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4)); |
hudakz | 0:84353c479782 | 469 | IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2)); |
hudakz | 0:84353c479782 | 470 | IR_object_s2 = (l2capinbuf[20] & 0x0F); |
hudakz | 0:84353c479782 | 471 | |
hudakz | 0:84353c479782 | 472 | IR_object_x3 = (l2capinbuf[21] | ((uint16_t)(l2capinbuf[23] & 0x30) << 4)); |
hudakz | 0:84353c479782 | 473 | IR_object_y3 = (l2capinbuf[22] | ((uint16_t)(l2capinbuf[23] & 0xC0) << 2)); |
hudakz | 0:84353c479782 | 474 | IR_object_s3 = (l2capinbuf[23] & 0x0F); |
hudakz | 0:84353c479782 | 475 | |
hudakz | 0:84353c479782 | 476 | IR_object_x4 = (l2capinbuf[24] | ((uint16_t)(l2capinbuf[26] & 0x30) << 4)); |
hudakz | 0:84353c479782 | 477 | IR_object_y4 = (l2capinbuf[25] | ((uint16_t)(l2capinbuf[26] & 0xC0) << 2)); |
hudakz | 0:84353c479782 | 478 | IR_object_s4 = (l2capinbuf[26] & 0x0F); |
hudakz | 0:84353c479782 | 479 | #endif |
hudakz | 0:84353c479782 | 480 | break; |
hudakz | 0:84353c479782 | 481 | 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 |
hudakz | 0:84353c479782 | 482 | break; |
hudakz | 0:84353c479782 | 483 | /* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */ |
hudakz | 0:84353c479782 | 484 | case 0x3E: // Core Buttons with Accelerometer and 32 IR bytes |
hudakz | 0:84353c479782 | 485 | // (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 |
hudakz | 0:84353c479782 | 486 | // corresponds to output report mode 0x3e |
hudakz | 0:84353c479782 | 487 | |
hudakz | 0:84353c479782 | 488 | /**** for reading in full mode: DOES NOT WORK YET ****/ |
hudakz | 0:84353c479782 | 489 | /* When it works it will also have intensity and bounding box data */ |
hudakz | 0:84353c479782 | 490 | /* |
hudakz | 0:84353c479782 | 491 | IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); |
hudakz | 0:84353c479782 | 492 | IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); |
hudakz | 0:84353c479782 | 493 | IR_object_s1 = (l2capinbuf[15] & 0x0F); |
hudakz | 0:84353c479782 | 494 | */ |
hudakz | 0:84353c479782 | 495 | break; |
hudakz | 0:84353c479782 | 496 | case 0x3F: |
hudakz | 0:84353c479782 | 497 | /* |
hudakz | 0:84353c479782 | 498 | IR_object_x1 = (l2capinbuf[13] | ((uint16_t)(l2capinbuf[15] & 0x30) << 4)); |
hudakz | 0:84353c479782 | 499 | IR_object_y1 = (l2capinbuf[14] | ((uint16_t)(l2capinbuf[15] & 0xC0) << 2)); |
hudakz | 0:84353c479782 | 500 | IR_object_s1 = (l2capinbuf[15] & 0x0F); |
hudakz | 0:84353c479782 | 501 | */ |
hudakz | 0:84353c479782 | 502 | break; |
hudakz | 0:84353c479782 | 503 | case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes |
hudakz | 0:84353c479782 | 504 | // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE |
hudakz | 0:84353c479782 | 505 | #if 1 // Set this to 0 if you don't want to use an extension, this reduceds the size of the library a lot! |
hudakz | 0:84353c479782 | 506 | if(motionPlusConnected) { |
hudakz | 0:84353c479782 | 507 | if(l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension |
hudakz | 0:84353c479782 | 508 | if(motionValuesReset) { // We will only use the values when the gyro value has been set |
hudakz | 0:84353c479782 | 509 | gyroYawRaw = ((l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)) - gyroYawZero); |
hudakz | 0:84353c479782 | 510 | gyroRollRaw = ((l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)) - gyroRollZero); |
hudakz | 0:84353c479782 | 511 | gyroPitchRaw = ((l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)) - gyroPitchZero); |
hudakz | 0:84353c479782 | 512 | |
hudakz | 0:84353c479782 | 513 | yawGyroSpeed = (float)gyroYawRaw / ((float)gyroYawZero / yawGyroScale); |
hudakz | 0:84353c479782 | 514 | rollGyroSpeed = -(float)gyroRollRaw / ((float)gyroRollZero / rollGyroScale); // We invert these values so they will fit the acc values |
hudakz | 0:84353c479782 | 515 | pitchGyroSpeed = (float)gyroPitchRaw / ((float)gyroPitchZero / pitchGyroScale); |
hudakz | 0:84353c479782 | 516 | |
hudakz | 0:84353c479782 | 517 | /* The onboard gyro has two ranges for slow and fast mode */ |
hudakz | 0:84353c479782 | 518 | if(!(l2capinbuf[18] & 0x02)) // Check if fast mode is used |
hudakz | 0:84353c479782 | 519 | yawGyroSpeed *= 4.545; |
hudakz | 0:84353c479782 | 520 | if(!(l2capinbuf[18] & 0x01)) // Check if fast mode is used |
hudakz | 0:84353c479782 | 521 | pitchGyroSpeed *= 4.545; |
hudakz | 0:84353c479782 | 522 | if(!(l2capinbuf[19] & 0x02)) // Check if fast mode is used |
hudakz | 0:84353c479782 | 523 | rollGyroSpeed *= 4.545; |
hudakz | 0:84353c479782 | 524 | |
hudakz | 0:84353c479782 | 525 | compPitch = (0.93f * (compPitch + (pitchGyroSpeed * (float)((uint32_t)micros() - timer) / 1000000.0f)))+(0.07f * getWiimotePitch()); // Use a complimentary filter to calculate the angle |
hudakz | 0:84353c479782 | 526 | compRoll = (0.93f * (compRoll + (rollGyroSpeed * (float)((uint32_t)micros() - timer) / 1000000.0f)))+(0.07f * getWiimoteRoll()); |
hudakz | 0:84353c479782 | 527 | |
hudakz | 0:84353c479782 | 528 | gyroYaw += (yawGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f)); |
hudakz | 0:84353c479782 | 529 | gyroRoll += (rollGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f)); |
hudakz | 0:84353c479782 | 530 | gyroPitch += (pitchGyroSpeed * ((float)((uint32_t)micros() - timer) / 1000000.0f)); |
hudakz | 0:84353c479782 | 531 | timer = (uint32_t)micros(); |
hudakz | 0:84353c479782 | 532 | /* |
hudakz | 0:84353c479782 | 533 | // Uncomment these lines to tune the gyro scale variabels |
hudakz | 0:84353c479782 | 534 | Notify(PSTR("\r\ngyroYaw: "), 0x80); |
hudakz | 0:84353c479782 | 535 | Notify(gyroYaw, 0x80); |
hudakz | 0:84353c479782 | 536 | Notify(PSTR("\tgyroRoll: "), 0x80); |
hudakz | 0:84353c479782 | 537 | Notify(gyroRoll, 0x80); |
hudakz | 0:84353c479782 | 538 | Notify(PSTR("\tgyroPitch: "), 0x80); |
hudakz | 0:84353c479782 | 539 | Notify(gyroPitch, 0x80); |
hudakz | 0:84353c479782 | 540 | */ |
hudakz | 0:84353c479782 | 541 | /* |
hudakz | 0:84353c479782 | 542 | Notify(PSTR("\twiimoteRoll: "), 0x80); |
hudakz | 0:84353c479782 | 543 | Notify(wiimoteRoll, 0x80); |
hudakz | 0:84353c479782 | 544 | Notify(PSTR("\twiimotePitch: "), 0x80); |
hudakz | 0:84353c479782 | 545 | Notify(wiimotePitch, 0x80); |
hudakz | 0:84353c479782 | 546 | */ |
hudakz | 0:84353c479782 | 547 | } else { |
hudakz | 0:84353c479782 | 548 | if((int32_t)((uint32_t)micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values |
hudakz | 0:84353c479782 | 549 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 550 | Notify(PSTR("\r\nThe gyro values has been reset"), 0x80); |
hudakz | 0:84353c479782 | 551 | #endif |
hudakz | 0:84353c479782 | 552 | gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6)); |
hudakz | 0:84353c479782 | 553 | gyroRollZero = (l2capinbuf[16] | ((l2capinbuf[19] & 0xFC) << 6)); |
hudakz | 0:84353c479782 | 554 | gyroPitchZero = (l2capinbuf[17] | ((l2capinbuf[20] & 0xFC) << 6)); |
hudakz | 0:84353c479782 | 555 | |
hudakz | 0:84353c479782 | 556 | rollGyroScale = 500; // You might need to adjust these |
hudakz | 0:84353c479782 | 557 | pitchGyroScale = 400; |
hudakz | 0:84353c479782 | 558 | yawGyroScale = 415; |
hudakz | 0:84353c479782 | 559 | |
hudakz | 0:84353c479782 | 560 | gyroYaw = 0; |
hudakz | 0:84353c479782 | 561 | gyroRoll = 0; |
hudakz | 0:84353c479782 | 562 | gyroPitch = 0; |
hudakz | 0:84353c479782 | 563 | |
hudakz | 0:84353c479782 | 564 | motionValuesReset = true; |
hudakz | 0:84353c479782 | 565 | timer = (uint32_t)micros(); |
hudakz | 0:84353c479782 | 566 | } |
hudakz | 0:84353c479782 | 567 | } |
hudakz | 0:84353c479782 | 568 | } else { |
hudakz | 0:84353c479782 | 569 | if(nunchuckConnected) { |
hudakz | 0:84353c479782 | 570 | hatValues[HatX] = l2capinbuf[15]; |
hudakz | 0:84353c479782 | 571 | hatValues[HatY] = l2capinbuf[16]; |
hudakz | 0:84353c479782 | 572 | accXnunchuck = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x10 >> 3)) - 416; |
hudakz | 0:84353c479782 | 573 | accYnunchuck = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x20 >> 4)) - 416; |
hudakz | 0:84353c479782 | 574 | accZnunchuck = (((l2capinbuf[19] & 0xFE) << 2) | (l2capinbuf[20] & 0xC0 >> 5)) - 416; |
hudakz | 0:84353c479782 | 575 | } |
hudakz | 0:84353c479782 | 576 | //else if(classicControllerConnected) { } |
hudakz | 0:84353c479782 | 577 | } |
hudakz | 0:84353c479782 | 578 | if(l2capinbuf[19] & 0x01) { |
hudakz | 0:84353c479782 | 579 | if(!extensionConnected) { |
hudakz | 0:84353c479782 | 580 | extensionConnected = true; |
hudakz | 0:84353c479782 | 581 | unknownExtensionConnected = true; |
hudakz | 0:84353c479782 | 582 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 583 | Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80); |
hudakz | 0:84353c479782 | 584 | #endif |
hudakz | 0:84353c479782 | 585 | } |
hudakz | 0:84353c479782 | 586 | } else { |
hudakz | 0:84353c479782 | 587 | if(extensionConnected && !unknownExtensionConnected) { |
hudakz | 0:84353c479782 | 588 | extensionConnected = false; |
hudakz | 0:84353c479782 | 589 | unknownExtensionConnected = true; |
hudakz | 0:84353c479782 | 590 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 591 | Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80); |
hudakz | 0:84353c479782 | 592 | #endif |
hudakz | 0:84353c479782 | 593 | nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent |
hudakz | 0:84353c479782 | 594 | } |
hudakz | 0:84353c479782 | 595 | } |
hudakz | 0:84353c479782 | 596 | |
hudakz | 0:84353c479782 | 597 | } else if(nunchuckConnected) { |
hudakz | 0:84353c479782 | 598 | hatValues[HatX] = l2capinbuf[15]; |
hudakz | 0:84353c479782 | 599 | hatValues[HatY] = l2capinbuf[16]; |
hudakz | 0:84353c479782 | 600 | accXnunchuck = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2)) - 416; |
hudakz | 0:84353c479782 | 601 | accYnunchuck = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4)) - 416; |
hudakz | 0:84353c479782 | 602 | accZnunchuck = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6)) - 416; |
hudakz | 0:84353c479782 | 603 | } else if(wiiUProControllerConnected) { |
hudakz | 0:84353c479782 | 604 | hatValues[LeftHatX] = (l2capinbuf[15] | l2capinbuf[16] << 8); |
hudakz | 0:84353c479782 | 605 | hatValues[RightHatX] = (l2capinbuf[17] | l2capinbuf[18] << 8); |
hudakz | 0:84353c479782 | 606 | hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8); |
hudakz | 0:84353c479782 | 607 | hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8); |
hudakz | 0:84353c479782 | 608 | } |
hudakz | 0:84353c479782 | 609 | #endif |
hudakz | 0:84353c479782 | 610 | break; |
hudakz | 0:84353c479782 | 611 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 612 | default: |
hudakz | 0:84353c479782 | 613 | Notify(PSTR("\r\nUnknown Report type: "), 0x80); |
hudakz | 0:84353c479782 | 614 | D_PrintHex<uint8_t > (l2capinbuf[9], 0x80); |
hudakz | 0:84353c479782 | 615 | break; |
hudakz | 0:84353c479782 | 616 | #endif |
hudakz | 0:84353c479782 | 617 | } |
hudakz | 0:84353c479782 | 618 | } |
hudakz | 0:84353c479782 | 619 | } |
hudakz | 0:84353c479782 | 620 | L2CAP_task(); |
hudakz | 0:84353c479782 | 621 | } |
hudakz | 0:84353c479782 | 622 | } |
hudakz | 0:84353c479782 | 623 | |
hudakz | 0:84353c479782 | 624 | void WII::L2CAP_task() { |
hudakz | 0:84353c479782 | 625 | switch(l2cap_state) { |
hudakz | 0:84353c479782 | 626 | /* These states are used if the Wiimote is the host */ |
hudakz | 0:84353c479782 | 627 | case L2CAP_CONTROL_SUCCESS: |
hudakz | 0:84353c479782 | 628 | if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) { |
hudakz | 0:84353c479782 | 629 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 630 | Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); |
hudakz | 0:84353c479782 | 631 | #endif |
hudakz | 0:84353c479782 | 632 | l2cap_state = L2CAP_INTERRUPT_SETUP; |
hudakz | 0:84353c479782 | 633 | } |
hudakz | 0:84353c479782 | 634 | break; |
hudakz | 0:84353c479782 | 635 | |
hudakz | 0:84353c479782 | 636 | case L2CAP_INTERRUPT_SETUP: |
hudakz | 0:84353c479782 | 637 | if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)) { |
hudakz | 0:84353c479782 | 638 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 639 | Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80); |
hudakz | 0:84353c479782 | 640 | #endif |
hudakz | 0:84353c479782 | 641 | pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING); |
hudakz | 0:84353c479782 | 642 | wait_ms(1); |
hudakz | 0:84353c479782 | 643 | pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); |
hudakz | 0:84353c479782 | 644 | identifier++; |
hudakz | 0:84353c479782 | 645 | wait_ms(1); |
hudakz | 0:84353c479782 | 646 | pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); |
hudakz | 0:84353c479782 | 647 | |
hudakz | 0:84353c479782 | 648 | l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; |
hudakz | 0:84353c479782 | 649 | } |
hudakz | 0:84353c479782 | 650 | break; |
hudakz | 0:84353c479782 | 651 | |
hudakz | 0:84353c479782 | 652 | /* These states are used if the Arduino is the host */ |
hudakz | 0:84353c479782 | 653 | case L2CAP_CONTROL_CONNECT_REQUEST: |
hudakz | 0:84353c479782 | 654 | if(l2cap_check_flag(L2CAP_FLAG_CONTROL_CONNECTED)) { |
hudakz | 0:84353c479782 | 655 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 656 | Notify(PSTR("\r\nSend HID Control Config Request"), 0x80); |
hudakz | 0:84353c479782 | 657 | #endif |
hudakz | 0:84353c479782 | 658 | identifier++; |
hudakz | 0:84353c479782 | 659 | pBtd->l2cap_config_request(hci_handle, identifier, control_scid); |
hudakz | 0:84353c479782 | 660 | l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST; |
hudakz | 0:84353c479782 | 661 | } |
hudakz | 0:84353c479782 | 662 | break; |
hudakz | 0:84353c479782 | 663 | |
hudakz | 0:84353c479782 | 664 | case L2CAP_CONTROL_CONFIG_REQUEST: |
hudakz | 0:84353c479782 | 665 | if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) { |
hudakz | 0:84353c479782 | 666 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 667 | Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); |
hudakz | 0:84353c479782 | 668 | #endif |
hudakz | 0:84353c479782 | 669 | identifier++; |
hudakz | 0:84353c479782 | 670 | pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM); |
hudakz | 0:84353c479782 | 671 | l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST; |
hudakz | 0:84353c479782 | 672 | } |
hudakz | 0:84353c479782 | 673 | break; |
hudakz | 0:84353c479782 | 674 | |
hudakz | 0:84353c479782 | 675 | case L2CAP_INTERRUPT_CONNECT_REQUEST: |
hudakz | 0:84353c479782 | 676 | if(l2cap_check_flag(L2CAP_FLAG_INTERRUPT_CONNECTED)) { |
hudakz | 0:84353c479782 | 677 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 678 | Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80); |
hudakz | 0:84353c479782 | 679 | #endif |
hudakz | 0:84353c479782 | 680 | identifier++; |
hudakz | 0:84353c479782 | 681 | pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); |
hudakz | 0:84353c479782 | 682 | l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; |
hudakz | 0:84353c479782 | 683 | } |
hudakz | 0:84353c479782 | 684 | break; |
hudakz | 0:84353c479782 | 685 | |
hudakz | 0:84353c479782 | 686 | case L2CAP_INTERRUPT_CONFIG_REQUEST: |
hudakz | 0:84353c479782 | 687 | if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established |
hudakz | 0:84353c479782 | 688 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 689 | Notify(PSTR("\r\nHID Channels Established"), 0x80); |
hudakz | 0:84353c479782 | 690 | #endif |
hudakz | 0:84353c479782 | 691 | pBtd->connectToWii = false; |
hudakz | 0:84353c479782 | 692 | pBtd->pairWithWii = false; |
hudakz | 0:84353c479782 | 693 | stateCounter = 0; |
hudakz | 0:84353c479782 | 694 | l2cap_state = WII_CHECK_MOTION_PLUS_STATE; |
hudakz | 0:84353c479782 | 695 | } |
hudakz | 0:84353c479782 | 696 | break; |
hudakz | 0:84353c479782 | 697 | |
hudakz | 0:84353c479782 | 698 | /* The next states are in run() */ |
hudakz | 0:84353c479782 | 699 | |
hudakz | 0:84353c479782 | 700 | case L2CAP_INTERRUPT_DISCONNECT: |
hudakz | 0:84353c479782 | 701 | if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE) && ((int32_t)((uint32_t)millis() - timer) >= 0L)) { |
hudakz | 0:84353c479782 | 702 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 703 | Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80); |
hudakz | 0:84353c479782 | 704 | #endif |
hudakz | 0:84353c479782 | 705 | identifier++; |
hudakz | 0:84353c479782 | 706 | pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid); |
hudakz | 0:84353c479782 | 707 | l2cap_state = L2CAP_CONTROL_DISCONNECT; |
hudakz | 0:84353c479782 | 708 | } |
hudakz | 0:84353c479782 | 709 | break; |
hudakz | 0:84353c479782 | 710 | |
hudakz | 0:84353c479782 | 711 | case L2CAP_CONTROL_DISCONNECT: |
hudakz | 0:84353c479782 | 712 | if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)) { |
hudakz | 0:84353c479782 | 713 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 714 | Notify(PSTR("\r\nDisconnected Control Channel"), 0x80); |
hudakz | 0:84353c479782 | 715 | #endif |
hudakz | 0:84353c479782 | 716 | pBtd->hci_disconnect(hci_handle); |
hudakz | 0:84353c479782 | 717 | hci_handle = -1; // Reset handle |
hudakz | 0:84353c479782 | 718 | l2cap_event_flag = 0; // Reset flags |
hudakz | 0:84353c479782 | 719 | l2cap_state = L2CAP_WAIT; |
hudakz | 0:84353c479782 | 720 | } |
hudakz | 0:84353c479782 | 721 | break; |
hudakz | 0:84353c479782 | 722 | } |
hudakz | 0:84353c479782 | 723 | } |
hudakz | 0:84353c479782 | 724 | |
hudakz | 0:84353c479782 | 725 | void WII::Run() { |
hudakz | 0:84353c479782 | 726 | if(l2cap_state == L2CAP_INTERRUPT_DISCONNECT && ((int32_t)((uint32_t)millis() - timer) >= 0L)) |
hudakz | 0:84353c479782 | 727 | L2CAP_task(); // Call the rest of the disconnection routine after we have waited long enough |
hudakz | 0:84353c479782 | 728 | |
hudakz | 0:84353c479782 | 729 | switch(l2cap_state) { |
hudakz | 0:84353c479782 | 730 | case L2CAP_WAIT: |
hudakz | 0:84353c479782 | 731 | if(pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) { |
hudakz | 0:84353c479782 | 732 | pBtd->l2capConnectionClaimed = true; |
hudakz | 0:84353c479782 | 733 | activeConnection = true; |
hudakz | 0:84353c479782 | 734 | motionPlusInside = pBtd->motionPlusInside; |
hudakz | 0:84353c479782 | 735 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 736 | Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80); |
hudakz | 0:84353c479782 | 737 | #endif |
hudakz | 0:84353c479782 | 738 | hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection |
hudakz | 0:84353c479782 | 739 | l2cap_event_flag = 0; // Reset flags |
hudakz | 0:84353c479782 | 740 | identifier = 0; |
hudakz | 0:84353c479782 | 741 | pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM); |
hudakz | 0:84353c479782 | 742 | l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST; |
hudakz | 0:84353c479782 | 743 | } else if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)) { |
hudakz | 0:84353c479782 | 744 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 745 | Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80); |
hudakz | 0:84353c479782 | 746 | #endif |
hudakz | 0:84353c479782 | 747 | pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING); |
hudakz | 0:84353c479782 | 748 | wait_ms(1); |
hudakz | 0:84353c479782 | 749 | pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL); |
hudakz | 0:84353c479782 | 750 | identifier++; |
hudakz | 0:84353c479782 | 751 | wait_ms(1); |
hudakz | 0:84353c479782 | 752 | pBtd->l2cap_config_request(hci_handle, identifier, control_scid); |
hudakz | 0:84353c479782 | 753 | l2cap_state = L2CAP_CONTROL_SUCCESS; |
hudakz | 0:84353c479782 | 754 | } |
hudakz | 0:84353c479782 | 755 | break; |
hudakz | 0:84353c479782 | 756 | |
hudakz | 0:84353c479782 | 757 | case WII_CHECK_MOTION_PLUS_STATE: |
hudakz | 0:84353c479782 | 758 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 759 | if(stateCounter == 0) // Only print onnce |
hudakz | 0:84353c479782 | 760 | Notify(PSTR("\r\nChecking if a Motion Plus is connected"), 0x80); |
hudakz | 0:84353c479782 | 761 | #endif |
hudakz | 0:84353c479782 | 762 | stateCounter++; |
hudakz | 0:84353c479782 | 763 | if(stateCounter % 200 == 0) |
hudakz | 0:84353c479782 | 764 | checkMotionPresent(); // Check if there is a motion plus connected |
hudakz | 0:84353c479782 | 765 | if(wii_check_flag(WII_FLAG_MOTION_PLUS_CONNECTED)) { |
hudakz | 0:84353c479782 | 766 | stateCounter = 0; |
hudakz | 0:84353c479782 | 767 | l2cap_state = WII_INIT_MOTION_PLUS_STATE; |
hudakz | 0:84353c479782 | 768 | timer = (uint32_t)micros(); |
hudakz | 0:84353c479782 | 769 | |
hudakz | 0:84353c479782 | 770 | if(unknownExtensionConnected) { |
hudakz | 0:84353c479782 | 771 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 772 | Notify(PSTR("\r\nA extension is also connected"), 0x80); |
hudakz | 0:84353c479782 | 773 | #endif |
hudakz | 0:84353c479782 | 774 | activateNunchuck = true; // For we will just set this to true as this the only extension supported so far |
hudakz | 0:84353c479782 | 775 | } |
hudakz | 0:84353c479782 | 776 | |
hudakz | 0:84353c479782 | 777 | } else if(stateCounter == 601) { // We will try three times to check for the motion plus |
hudakz | 0:84353c479782 | 778 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 779 | Notify(PSTR("\r\nNo Motion Plus was detected"), 0x80); |
hudakz | 0:84353c479782 | 780 | #endif |
hudakz | 0:84353c479782 | 781 | stateCounter = 0; |
hudakz | 0:84353c479782 | 782 | l2cap_state = WII_CHECK_EXTENSION_STATE; |
hudakz | 0:84353c479782 | 783 | } |
hudakz | 0:84353c479782 | 784 | break; |
hudakz | 0:84353c479782 | 785 | |
hudakz | 0:84353c479782 | 786 | case WII_CHECK_EXTENSION_STATE: // This is used to check if there is anything plugged in to the extension port |
hudakz | 0:84353c479782 | 787 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 788 | if(stateCounter == 0) // Only print onnce |
hudakz | 0:84353c479782 | 789 | Notify(PSTR("\r\nChecking if there is any extension connected"), 0x80); |
hudakz | 0:84353c479782 | 790 | #endif |
hudakz | 0:84353c479782 | 791 | stateCounter++; // We use this counter as there has to be a short delay between the commands |
hudakz | 0:84353c479782 | 792 | if(stateCounter == 1) |
hudakz | 0:84353c479782 | 793 | statusRequest(); // See if a new device has connected |
hudakz | 0:84353c479782 | 794 | if(stateCounter == 100) { |
hudakz | 0:84353c479782 | 795 | if(unknownExtensionConnected) // Check if there is a extension is connected to the port |
hudakz | 0:84353c479782 | 796 | initExtension1(); |
hudakz | 0:84353c479782 | 797 | else |
hudakz | 0:84353c479782 | 798 | stateCounter = 499; |
hudakz | 0:84353c479782 | 799 | } else if(stateCounter == 200) |
hudakz | 0:84353c479782 | 800 | initExtension2(); |
hudakz | 0:84353c479782 | 801 | else if(stateCounter == 300) { |
hudakz | 0:84353c479782 | 802 | readExtensionType(); |
hudakz | 0:84353c479782 | 803 | unknownExtensionConnected = false; |
hudakz | 0:84353c479782 | 804 | } else if(stateCounter == 400) { |
hudakz | 0:84353c479782 | 805 | if(wii_check_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD)) { |
hudakz | 0:84353c479782 | 806 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 807 | Notify(PSTR("\r\nReading Wii Balance Board calibration values"), 0x80); |
hudakz | 0:84353c479782 | 808 | #endif |
hudakz | 0:84353c479782 | 809 | readWiiBalanceBoardCalibration(); |
hudakz | 0:84353c479782 | 810 | } else |
hudakz | 0:84353c479782 | 811 | stateCounter = 499; |
hudakz | 0:84353c479782 | 812 | } else if(stateCounter == 500) { |
hudakz | 0:84353c479782 | 813 | stateCounter = 0; |
hudakz | 0:84353c479782 | 814 | l2cap_state = TURN_ON_LED; |
hudakz | 0:84353c479782 | 815 | } |
hudakz | 0:84353c479782 | 816 | break; |
hudakz | 0:84353c479782 | 817 | |
hudakz | 0:84353c479782 | 818 | case WII_INIT_MOTION_PLUS_STATE: |
hudakz | 0:84353c479782 | 819 | stateCounter++; |
hudakz | 0:84353c479782 | 820 | if(stateCounter == 1) |
hudakz | 0:84353c479782 | 821 | initMotionPlus(); |
hudakz | 0:84353c479782 | 822 | else if(stateCounter == 100) |
hudakz | 0:84353c479782 | 823 | activateMotionPlus(); |
hudakz | 0:84353c479782 | 824 | else if(stateCounter == 200) |
hudakz | 0:84353c479782 | 825 | readExtensionType(); // Check if it has been activated |
hudakz | 0:84353c479782 | 826 | else if(stateCounter == 300) { |
hudakz | 0:84353c479782 | 827 | stateCounter = 0; |
hudakz | 0:84353c479782 | 828 | 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 |
hudakz | 0:84353c479782 | 829 | l2cap_state = TURN_ON_LED; |
hudakz | 0:84353c479782 | 830 | } |
hudakz | 0:84353c479782 | 831 | break; |
hudakz | 0:84353c479782 | 832 | |
hudakz | 0:84353c479782 | 833 | case TURN_ON_LED: |
hudakz | 0:84353c479782 | 834 | if(wii_check_flag(WII_FLAG_NUNCHUCK_CONNECTED)) |
hudakz | 0:84353c479782 | 835 | nunchuckConnected = true; |
hudakz | 0:84353c479782 | 836 | wiimoteConnected = true; |
hudakz | 0:84353c479782 | 837 | onInit(); |
hudakz | 0:84353c479782 | 838 | l2cap_state = L2CAP_DONE; |
hudakz | 0:84353c479782 | 839 | break; |
hudakz | 0:84353c479782 | 840 | |
hudakz | 0:84353c479782 | 841 | case L2CAP_DONE: |
hudakz | 0:84353c479782 | 842 | if(unknownExtensionConnected) { |
hudakz | 0:84353c479782 | 843 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 844 | if(stateCounter == 0) // Only print once |
hudakz | 0:84353c479782 | 845 | Notify(PSTR("\r\nChecking extension port"), 0x80); |
hudakz | 0:84353c479782 | 846 | #endif |
hudakz | 0:84353c479782 | 847 | stateCounter++; // We will use this counter as there has to be a short delay between the commands |
hudakz | 0:84353c479782 | 848 | if(stateCounter == 50) |
hudakz | 0:84353c479782 | 849 | statusRequest(); |
hudakz | 0:84353c479782 | 850 | else if(stateCounter == 100) |
hudakz | 0:84353c479782 | 851 | initExtension1(); |
hudakz | 0:84353c479782 | 852 | else if(stateCounter == 150) |
hudakz | 0:84353c479782 | 853 | if((extensionConnected && motionPlusConnected) || (unknownExtensionConnected && !motionPlusConnected)) |
hudakz | 0:84353c479782 | 854 | initExtension2(); |
hudakz | 0:84353c479782 | 855 | else |
hudakz | 0:84353c479782 | 856 | stateCounter = 299; // There is no extension connected |
hudakz | 0:84353c479782 | 857 | else if(stateCounter == 200) |
hudakz | 0:84353c479782 | 858 | readExtensionType(); |
hudakz | 0:84353c479782 | 859 | else if(stateCounter == 250) { |
hudakz | 0:84353c479782 | 860 | if(wii_check_flag(WII_FLAG_NUNCHUCK_CONNECTED)) { |
hudakz | 0:84353c479782 | 861 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 862 | Notify(PSTR("\r\nNunchuck was reconnected"), 0x80); |
hudakz | 0:84353c479782 | 863 | #endif |
hudakz | 0:84353c479782 | 864 | activateNunchuck = true; |
hudakz | 0:84353c479782 | 865 | nunchuckConnected = true; |
hudakz | 0:84353c479782 | 866 | } |
hudakz | 0:84353c479782 | 867 | if(!motionPlusConnected) |
hudakz | 0:84353c479782 | 868 | stateCounter = 449; |
hudakz | 0:84353c479782 | 869 | } else if(stateCounter == 300) { |
hudakz | 0:84353c479782 | 870 | if(motionPlusConnected) { |
hudakz | 0:84353c479782 | 871 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 872 | Notify(PSTR("\r\nReactivating the Motion Plus"), 0x80); |
hudakz | 0:84353c479782 | 873 | #endif |
hudakz | 0:84353c479782 | 874 | initMotionPlus(); |
hudakz | 0:84353c479782 | 875 | } else |
hudakz | 0:84353c479782 | 876 | stateCounter = 449; |
hudakz | 0:84353c479782 | 877 | } else if(stateCounter == 350) |
hudakz | 0:84353c479782 | 878 | activateMotionPlus(); |
hudakz | 0:84353c479782 | 879 | else if(stateCounter == 400) |
hudakz | 0:84353c479782 | 880 | readExtensionType(); // Check if it has been activated |
hudakz | 0:84353c479782 | 881 | else if(stateCounter == 450) { |
hudakz | 0:84353c479782 | 882 | onInit(); |
hudakz | 0:84353c479782 | 883 | stateCounter = 0; |
hudakz | 0:84353c479782 | 884 | unknownExtensionConnected = false; |
hudakz | 0:84353c479782 | 885 | } |
hudakz | 0:84353c479782 | 886 | } else |
hudakz | 0:84353c479782 | 887 | stateCounter = 0; |
hudakz | 0:84353c479782 | 888 | break; |
hudakz | 0:84353c479782 | 889 | } |
hudakz | 0:84353c479782 | 890 | } |
hudakz | 0:84353c479782 | 891 | |
hudakz | 0:84353c479782 | 892 | /************************************************************/ |
hudakz | 0:84353c479782 | 893 | /* HID Commands */ |
hudakz | 0:84353c479782 | 894 | /************************************************************/ |
hudakz | 0:84353c479782 | 895 | |
hudakz | 0:84353c479782 | 896 | void WII::HID_Command(uint8_t* data, uint8_t nbytes) { |
hudakz | 0:84353c479782 | 897 | if(motionPlusInside) |
hudakz | 0:84353c479782 | 898 | 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 |
hudakz | 0:84353c479782 | 899 | else |
hudakz | 0:84353c479782 | 900 | pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); |
hudakz | 0:84353c479782 | 901 | } |
hudakz | 0:84353c479782 | 902 | |
hudakz | 0:84353c479782 | 903 | void WII::setAllOff() { |
hudakz | 0:84353c479782 | 904 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 905 | HIDBuffer[2] = 0x00; |
hudakz | 0:84353c479782 | 906 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 907 | } |
hudakz | 0:84353c479782 | 908 | |
hudakz | 0:84353c479782 | 909 | void WII::setRumbleOff() { |
hudakz | 0:84353c479782 | 910 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 911 | HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble |
hudakz | 0:84353c479782 | 912 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 913 | } |
hudakz | 0:84353c479782 | 914 | |
hudakz | 0:84353c479782 | 915 | void WII::setRumbleOn() { |
hudakz | 0:84353c479782 | 916 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 917 | HIDBuffer[2] |= 0x01; // Bit 0 control the rumble |
hudakz | 0:84353c479782 | 918 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 919 | } |
hudakz | 0:84353c479782 | 920 | |
hudakz | 0:84353c479782 | 921 | void WII::setRumbleToggle() { |
hudakz | 0:84353c479782 | 922 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 923 | HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble |
hudakz | 0:84353c479782 | 924 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 925 | } |
hudakz | 0:84353c479782 | 926 | |
hudakz | 0:84353c479782 | 927 | void WII::setLedRaw(uint8_t value) { |
hudakz | 0:84353c479782 | 928 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 929 | HIDBuffer[2] = value | (HIDBuffer[2] & 0x01); // Keep the rumble bit |
hudakz | 0:84353c479782 | 930 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 931 | } |
hudakz | 0:84353c479782 | 932 | |
hudakz | 0:84353c479782 | 933 | void WII::setLedOff(LEDEnum a) { |
hudakz | 0:84353c479782 | 934 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 935 | HIDBuffer[2] &= ~(pgm_read_byte(&WII_LEDS[(uint8_t)a])); |
hudakz | 0:84353c479782 | 936 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 937 | } |
hudakz | 0:84353c479782 | 938 | |
hudakz | 0:84353c479782 | 939 | void WII::setLedOn(LEDEnum a) { |
hudakz | 0:84353c479782 | 940 | if(a == OFF) |
hudakz | 0:84353c479782 | 941 | setLedRaw(0); |
hudakz | 0:84353c479782 | 942 | else { |
hudakz | 0:84353c479782 | 943 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 944 | HIDBuffer[2] |= pgm_read_byte(&WII_LEDS[(uint8_t)a]); |
hudakz | 0:84353c479782 | 945 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 946 | } |
hudakz | 0:84353c479782 | 947 | } |
hudakz | 0:84353c479782 | 948 | |
hudakz | 0:84353c479782 | 949 | void WII::setLedToggle(LEDEnum a) { |
hudakz | 0:84353c479782 | 950 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 951 | HIDBuffer[2] ^= pgm_read_byte(&WII_LEDS[(uint8_t)a]); |
hudakz | 0:84353c479782 | 952 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 953 | } |
hudakz | 0:84353c479782 | 954 | |
hudakz | 0:84353c479782 | 955 | void WII::setLedStatus() { |
hudakz | 0:84353c479782 | 956 | HIDBuffer[1] = 0x11; |
hudakz | 0:84353c479782 | 957 | HIDBuffer[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit |
hudakz | 0:84353c479782 | 958 | if(wiimoteConnected) |
hudakz | 0:84353c479782 | 959 | HIDBuffer[2] |= 0x10; // If it's connected LED1 will light up |
hudakz | 0:84353c479782 | 960 | if(motionPlusConnected) |
hudakz | 0:84353c479782 | 961 | HIDBuffer[2] |= 0x20; // If it's connected LED2 will light up |
hudakz | 0:84353c479782 | 962 | if(nunchuckConnected) |
hudakz | 0:84353c479782 | 963 | HIDBuffer[2] |= 0x40; // If it's connected LED3 will light up |
hudakz | 0:84353c479782 | 964 | |
hudakz | 0:84353c479782 | 965 | HID_Command(HIDBuffer, 3); |
hudakz | 0:84353c479782 | 966 | } |
hudakz | 0:84353c479782 | 967 | |
hudakz | 0:84353c479782 | 968 | uint8_t WII::getBatteryLevel() { |
hudakz | 0:84353c479782 | 969 | checkBatteryLevel = true; // This is needed so the library knows that the status response is a response to this function |
hudakz | 0:84353c479782 | 970 | statusRequest(); // This will update the battery level |
hudakz | 0:84353c479782 | 971 | return batteryLevel; |
hudakz | 0:84353c479782 | 972 | }; |
hudakz | 0:84353c479782 | 973 | |
hudakz | 0:84353c479782 | 974 | void WII::setReportMode(bool continuous, uint8_t mode) { |
hudakz | 0:84353c479782 | 975 | #ifdef EXTRADEBUG |
hudakz | 0:84353c479782 | 976 | Notify(PSTR("\r\nReport mode was changed to: "), 0x80); |
hudakz | 0:84353c479782 | 977 | D_PrintHex<uint8_t > (mode, 0x80); |
hudakz | 0:84353c479782 | 978 | #endif |
hudakz | 0:84353c479782 | 979 | uint8_t cmd_buf[4]; |
hudakz | 0:84353c479782 | 980 | cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 981 | cmd_buf[1] = 0x12; |
hudakz | 0:84353c479782 | 982 | if(continuous) |
hudakz | 0:84353c479782 | 983 | cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit |
hudakz | 0:84353c479782 | 984 | else |
hudakz | 0:84353c479782 | 985 | cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Keep the rumble bit |
hudakz | 0:84353c479782 | 986 | cmd_buf[3] = mode; |
hudakz | 0:84353c479782 | 987 | HID_Command(cmd_buf, 4); |
hudakz | 0:84353c479782 | 988 | } |
hudakz | 0:84353c479782 | 989 | |
hudakz | 0:84353c479782 | 990 | void WII::statusRequest() { |
hudakz | 0:84353c479782 | 991 | uint8_t cmd_buf[3]; |
hudakz | 0:84353c479782 | 992 | cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 993 | cmd_buf[1] = 0x15; |
hudakz | 0:84353c479782 | 994 | cmd_buf[2] = (HIDBuffer[2] & 0x01); // Keep the rumble bit |
hudakz | 0:84353c479782 | 995 | HID_Command(cmd_buf, 3); |
hudakz | 0:84353c479782 | 996 | } |
hudakz | 0:84353c479782 | 997 | |
hudakz | 0:84353c479782 | 998 | /************************************************************/ |
hudakz | 0:84353c479782 | 999 | /* Memmory Commands */ |
hudakz | 0:84353c479782 | 1000 | /************************************************************/ |
hudakz | 0:84353c479782 | 1001 | |
hudakz | 0:84353c479782 | 1002 | void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) { |
hudakz | 0:84353c479782 | 1003 | uint8_t cmd_buf[23]; |
hudakz | 0:84353c479782 | 1004 | cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 1005 | cmd_buf[1] = 0x16; // Write data |
hudakz | 0:84353c479782 | 1006 | cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Write to memory, clear bit 2 to write to EEPROM |
hudakz | 0:84353c479782 | 1007 | cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16); |
hudakz | 0:84353c479782 | 1008 | cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8); |
hudakz | 0:84353c479782 | 1009 | cmd_buf[5] = (uint8_t)(offset & 0xFF); |
hudakz | 0:84353c479782 | 1010 | cmd_buf[6] = size; |
hudakz | 0:84353c479782 | 1011 | uint8_t i = 0; |
hudakz | 0:84353c479782 | 1012 | for(; i < size; i++) |
hudakz | 0:84353c479782 | 1013 | cmd_buf[7 + i] = data[i]; |
hudakz | 0:84353c479782 | 1014 | for(; i < 16; i++) // Set the rest to zero |
hudakz | 0:84353c479782 | 1015 | cmd_buf[7 + i] = 0x00; |
hudakz | 0:84353c479782 | 1016 | HID_Command(cmd_buf, 23); |
hudakz | 0:84353c479782 | 1017 | } |
hudakz | 0:84353c479782 | 1018 | |
hudakz | 0:84353c479782 | 1019 | void WII::initExtension1() { |
hudakz | 0:84353c479782 | 1020 | uint8_t buf[1]; |
hudakz | 0:84353c479782 | 1021 | buf[0] = 0x55; |
hudakz | 0:84353c479782 | 1022 | writeData(0xA400F0, 1, buf); |
hudakz | 0:84353c479782 | 1023 | } |
hudakz | 0:84353c479782 | 1024 | |
hudakz | 0:84353c479782 | 1025 | void WII::initExtension2() { |
hudakz | 0:84353c479782 | 1026 | uint8_t buf[1]; |
hudakz | 0:84353c479782 | 1027 | buf[0] = 0x00; |
hudakz | 0:84353c479782 | 1028 | writeData(0xA400FB, 1, buf); |
hudakz | 0:84353c479782 | 1029 | } |
hudakz | 0:84353c479782 | 1030 | |
hudakz | 0:84353c479782 | 1031 | void WII::initMotionPlus() { |
hudakz | 0:84353c479782 | 1032 | uint8_t buf[1]; |
hudakz | 0:84353c479782 | 1033 | buf[0] = 0x55; |
hudakz | 0:84353c479782 | 1034 | writeData(0xA600F0, 1, buf); |
hudakz | 0:84353c479782 | 1035 | } |
hudakz | 0:84353c479782 | 1036 | |
hudakz | 0:84353c479782 | 1037 | void WII::activateMotionPlus() { |
hudakz | 0:84353c479782 | 1038 | uint8_t buf[1]; |
hudakz | 0:84353c479782 | 1039 | if(pBtd->wiiUProController) { |
hudakz | 0:84353c479782 | 1040 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1041 | Notify(PSTR("\r\nActivating Wii U Pro Controller"), 0x80); |
hudakz | 0:84353c479782 | 1042 | #endif |
hudakz | 0:84353c479782 | 1043 | buf[0] = 0x00; // It seems like you can send anything but 0x04, 0x05, and 0x07 |
hudakz | 0:84353c479782 | 1044 | } else if(activateNunchuck) { |
hudakz | 0:84353c479782 | 1045 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1046 | Notify(PSTR("\r\nActivating Motion Plus in pass-through mode"), 0x80); |
hudakz | 0:84353c479782 | 1047 | #endif |
hudakz | 0:84353c479782 | 1048 | buf[0] = 0x05; // Activate nunchuck pass-through mode |
hudakz | 0:84353c479782 | 1049 | }//else if(classicControllerConnected && extensionConnected) |
hudakz | 0:84353c479782 | 1050 | //buf[0] = 0x07; |
hudakz | 0:84353c479782 | 1051 | else { |
hudakz | 0:84353c479782 | 1052 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1053 | Notify(PSTR("\r\nActivating Motion Plus in normal mode"), 0x80); |
hudakz | 0:84353c479782 | 1054 | #endif |
hudakz | 0:84353c479782 | 1055 | buf[0] = 0x04; // Don't use any extension |
hudakz | 0:84353c479782 | 1056 | } |
hudakz | 0:84353c479782 | 1057 | writeData(0xA600FE, 1, buf); |
hudakz | 0:84353c479782 | 1058 | } |
hudakz | 0:84353c479782 | 1059 | |
hudakz | 0:84353c479782 | 1060 | void WII::readData(uint32_t offset, uint16_t size, bool EEPROM) { |
hudakz | 0:84353c479782 | 1061 | uint8_t cmd_buf[8]; |
hudakz | 0:84353c479782 | 1062 | cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 1063 | cmd_buf[1] = 0x17; // Read data |
hudakz | 0:84353c479782 | 1064 | if(EEPROM) |
hudakz | 0:84353c479782 | 1065 | cmd_buf[2] = 0x00 | (HIDBuffer[2] & 0x01); // Read from EEPROM |
hudakz | 0:84353c479782 | 1066 | else |
hudakz | 0:84353c479782 | 1067 | cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Read from memory |
hudakz | 0:84353c479782 | 1068 | cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16); |
hudakz | 0:84353c479782 | 1069 | cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8); |
hudakz | 0:84353c479782 | 1070 | cmd_buf[5] = (uint8_t)(offset & 0xFF); |
hudakz | 0:84353c479782 | 1071 | cmd_buf[6] = (uint8_t)((size & 0xFF00) >> 8); |
hudakz | 0:84353c479782 | 1072 | cmd_buf[7] = (uint8_t)(size & 0xFF); |
hudakz | 0:84353c479782 | 1073 | |
hudakz | 0:84353c479782 | 1074 | HID_Command(cmd_buf, 8); |
hudakz | 0:84353c479782 | 1075 | } |
hudakz | 0:84353c479782 | 1076 | |
hudakz | 0:84353c479782 | 1077 | void WII::readExtensionType() { |
hudakz | 0:84353c479782 | 1078 | readData(0xA400FA, 6, false); |
hudakz | 0:84353c479782 | 1079 | } |
hudakz | 0:84353c479782 | 1080 | |
hudakz | 0:84353c479782 | 1081 | void WII::readCalData() { |
hudakz | 0:84353c479782 | 1082 | readData(0x0016, 8, true); |
hudakz | 0:84353c479782 | 1083 | } |
hudakz | 0:84353c479782 | 1084 | |
hudakz | 0:84353c479782 | 1085 | void WII::checkMotionPresent() { |
hudakz | 0:84353c479782 | 1086 | readData(0xA600FA, 6, false); |
hudakz | 0:84353c479782 | 1087 | } |
hudakz | 0:84353c479782 | 1088 | |
hudakz | 0:84353c479782 | 1089 | void WII::readWiiBalanceBoardCalibration() { |
hudakz | 0:84353c479782 | 1090 | readData(0xA40024, 24, false); |
hudakz | 0:84353c479782 | 1091 | } |
hudakz | 0:84353c479782 | 1092 | |
hudakz | 0:84353c479782 | 1093 | /************************************************************/ |
hudakz | 0:84353c479782 | 1094 | /* WII Commands */ |
hudakz | 0:84353c479782 | 1095 | /************************************************************/ |
hudakz | 0:84353c479782 | 1096 | |
hudakz | 0:84353c479782 | 1097 | bool WII::getButtonPress(ButtonEnum b) { // Return true when a button is pressed |
hudakz | 0:84353c479782 | 1098 | if(wiiUProControllerConnected) |
hudakz | 0:84353c479782 | 1099 | return (ButtonState & pgm_read_dword(&WII_PROCONTROLLER_BUTTONS[(uint8_t)b])); |
hudakz | 0:84353c479782 | 1100 | else |
hudakz | 0:84353c479782 | 1101 | return (ButtonState & pgm_read_dword(&WII_BUTTONS[(uint8_t)b])); |
hudakz | 0:84353c479782 | 1102 | } |
hudakz | 0:84353c479782 | 1103 | |
hudakz | 0:84353c479782 | 1104 | bool WII::getButtonClick(ButtonEnum b) { // Only return true when a button is clicked |
hudakz | 0:84353c479782 | 1105 | uint32_t button; |
hudakz | 0:84353c479782 | 1106 | if(wiiUProControllerConnected) |
hudakz | 0:84353c479782 | 1107 | button = pgm_read_dword(&WII_PROCONTROLLER_BUTTONS[(uint8_t)b]); |
hudakz | 0:84353c479782 | 1108 | else |
hudakz | 0:84353c479782 | 1109 | button = pgm_read_dword(&WII_BUTTONS[(uint8_t)b]); |
hudakz | 0:84353c479782 | 1110 | bool click = (ButtonClickState & button); |
hudakz | 0:84353c479782 | 1111 | ButtonClickState &= ~button; // clear "click" event |
hudakz | 0:84353c479782 | 1112 | return click; |
hudakz | 0:84353c479782 | 1113 | } |
hudakz | 0:84353c479782 | 1114 | |
hudakz | 0:84353c479782 | 1115 | uint8_t WII::getAnalogHat(HatEnum a) { |
hudakz | 0:84353c479782 | 1116 | if(!nunchuckConnected) |
hudakz | 0:84353c479782 | 1117 | return 127; // Return center position |
hudakz | 0:84353c479782 | 1118 | else { |
hudakz | 0:84353c479782 | 1119 | uint8_t output = hatValues[(uint8_t)a]; |
hudakz | 0:84353c479782 | 1120 | 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 |
hudakz | 0:84353c479782 | 1121 | return 127; |
hudakz | 0:84353c479782 | 1122 | else |
hudakz | 0:84353c479782 | 1123 | return output; |
hudakz | 0:84353c479782 | 1124 | } |
hudakz | 0:84353c479782 | 1125 | } |
hudakz | 0:84353c479782 | 1126 | |
hudakz | 0:84353c479782 | 1127 | uint16_t WII::getAnalogHat(AnalogHatEnum a) { |
hudakz | 0:84353c479782 | 1128 | if(!wiiUProControllerConnected) |
hudakz | 0:84353c479782 | 1129 | return 2000; |
hudakz | 0:84353c479782 | 1130 | else { |
hudakz | 0:84353c479782 | 1131 | uint16_t output = hatValues[(uint8_t)a]; |
hudakz | 0:84353c479782 | 1132 | if(output == 0x00) // The joystick will only read 0 when it is first initializing, so we will just return the center position |
hudakz | 0:84353c479782 | 1133 | return 2000; |
hudakz | 0:84353c479782 | 1134 | else |
hudakz | 0:84353c479782 | 1135 | return output; |
hudakz | 0:84353c479782 | 1136 | } |
hudakz | 0:84353c479782 | 1137 | } |
hudakz | 0:84353c479782 | 1138 | |
hudakz | 0:84353c479782 | 1139 | void WII::onInit() { |
hudakz | 0:84353c479782 | 1140 | if(pFuncOnInit) |
hudakz | 0:84353c479782 | 1141 | pFuncOnInit(); // Call the user function |
hudakz | 0:84353c479782 | 1142 | else |
hudakz | 0:84353c479782 | 1143 | setLedStatus(); |
hudakz | 0:84353c479782 | 1144 | } |
hudakz | 0:84353c479782 | 1145 | |
hudakz | 0:84353c479782 | 1146 | /************************************************************/ |
hudakz | 0:84353c479782 | 1147 | /* Wii Balance Board Commands */ |
hudakz | 0:84353c479782 | 1148 | /************************************************************/ |
hudakz | 0:84353c479782 | 1149 | |
hudakz | 0:84353c479782 | 1150 | float WII::getWeight(BalanceBoardEnum pos) { |
hudakz | 0:84353c479782 | 1151 | // Use interpolating between two points - based on: https://github.com/skorokithakis/gr8w8upd8m8/blob/master/gr8w8upd8m8.py |
hudakz | 0:84353c479782 | 1152 | // wiiBalanceBoardCal[pos][0] is calibration values for 0 kg |
hudakz | 0:84353c479782 | 1153 | // wiiBalanceBoardCal[pos][1] is calibration values for 17 kg |
hudakz | 0:84353c479782 | 1154 | // wiiBalanceBoardCal[pos][2] is calibration values for 34 kg |
hudakz | 0:84353c479782 | 1155 | if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[0][pos]) |
hudakz | 0:84353c479782 | 1156 | return 0.0f; // Below 0 kg |
hudakz | 0:84353c479782 | 1157 | else if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[1][pos]) // Between 0 and 17 kg |
hudakz | 0:84353c479782 | 1158 | return 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[0][pos]) / (float)(wiiBalanceBoardCal[1][pos] - wiiBalanceBoardCal[0][pos]); |
hudakz | 0:84353c479782 | 1159 | else // More than 17 kg |
hudakz | 0:84353c479782 | 1160 | return 17.0f + 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[1][pos]) / (float)(wiiBalanceBoardCal[2][pos] - wiiBalanceBoardCal[1][pos]); |
hudakz | 0:84353c479782 | 1161 | }; |
hudakz | 0:84353c479782 | 1162 | |
hudakz | 0:84353c479782 | 1163 | float WII::getTotalWeight() { |
hudakz | 0:84353c479782 | 1164 | return getWeight(TopRight) + getWeight(BotRight) + getWeight(TopLeft) + getWeight(BotLeft); |
hudakz | 0:84353c479782 | 1165 | }; |
hudakz | 0:84353c479782 | 1166 | |
hudakz | 0:84353c479782 | 1167 | /************************************************************/ |
hudakz | 0:84353c479782 | 1168 | /* The following functions are for the IR camera */ |
hudakz | 0:84353c479782 | 1169 | /************************************************************/ |
hudakz | 0:84353c479782 | 1170 | |
hudakz | 0:84353c479782 | 1171 | #ifdef WIICAMERA |
hudakz | 0:84353c479782 | 1172 | |
hudakz | 0:84353c479782 | 1173 | void WII::IRinitialize() { // Turns on and initialises the IR camera |
hudakz | 0:84353c479782 | 1174 | |
hudakz | 0:84353c479782 | 1175 | enableIRCamera1(); |
hudakz | 0:84353c479782 | 1176 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1177 | Notify(PSTR("\r\nEnable IR Camera1 Complete"), 0x80); |
hudakz | 0:84353c479782 | 1178 | #endif |
hudakz | 0:84353c479782 | 1179 | wait_ms(80); |
hudakz | 0:84353c479782 | 1180 | |
hudakz | 0:84353c479782 | 1181 | enableIRCamera2(); |
hudakz | 0:84353c479782 | 1182 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1183 | Notify(PSTR("\r\nEnable IR Camera2 Complete"), 0x80); |
hudakz | 0:84353c479782 | 1184 | #endif |
hudakz | 0:84353c479782 | 1185 | wait_ms(80); |
hudakz | 0:84353c479782 | 1186 | |
hudakz | 0:84353c479782 | 1187 | write0x08Value(); |
hudakz | 0:84353c479782 | 1188 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1189 | Notify(PSTR("\r\nWrote hex number 0x08"), 0x80); |
hudakz | 0:84353c479782 | 1190 | #endif |
hudakz | 0:84353c479782 | 1191 | wait_ms(80); |
hudakz | 0:84353c479782 | 1192 | |
hudakz | 0:84353c479782 | 1193 | writeSensitivityBlock1(); |
hudakz | 0:84353c479782 | 1194 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1195 | Notify(PSTR("\r\nWrote Sensitivity Block 1"), 0x80); |
hudakz | 0:84353c479782 | 1196 | #endif |
hudakz | 0:84353c479782 | 1197 | wait_ms(80); |
hudakz | 0:84353c479782 | 1198 | |
hudakz | 0:84353c479782 | 1199 | writeSensitivityBlock2(); |
hudakz | 0:84353c479782 | 1200 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1201 | Notify(PSTR("\r\nWrote Sensitivity Block 2"), 0x80); |
hudakz | 0:84353c479782 | 1202 | #endif |
hudakz | 0:84353c479782 | 1203 | wait_ms(80); |
hudakz | 0:84353c479782 | 1204 | |
hudakz | 0:84353c479782 | 1205 | uint8_t mode_num = 0x03; |
hudakz | 0:84353c479782 | 1206 | setWiiModeNumber(mode_num); // Change input for whatever mode you want i.e. 0x01, 0x03, or 0x05 |
hudakz | 0:84353c479782 | 1207 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1208 | Notify(PSTR("\r\nSet Wii Mode Number To 0x"), 0x80); |
hudakz | 0:84353c479782 | 1209 | D_PrintHex<uint8_t > (mode_num, 0x80); |
hudakz | 0:84353c479782 | 1210 | #endif |
hudakz | 0:84353c479782 | 1211 | wait_ms(80); |
hudakz | 0:84353c479782 | 1212 | |
hudakz | 0:84353c479782 | 1213 | write0x08Value(); |
hudakz | 0:84353c479782 | 1214 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1215 | Notify(PSTR("\r\nWrote Hex Number 0x08"), 0x80); |
hudakz | 0:84353c479782 | 1216 | #endif |
hudakz | 0:84353c479782 | 1217 | wait_ms(80); |
hudakz | 0:84353c479782 | 1218 | |
hudakz | 0:84353c479782 | 1219 | setReportMode(false, 0x33); |
hudakz | 0:84353c479782 | 1220 | //setReportMode(false, 0x3f); // For full reporting mode, doesn't work yet |
hudakz | 0:84353c479782 | 1221 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1222 | Notify(PSTR("\r\nSet Report Mode to 0x33"), 0x80); |
hudakz | 0:84353c479782 | 1223 | #endif |
hudakz | 0:84353c479782 | 1224 | wait_ms(80); |
hudakz | 0:84353c479782 | 1225 | |
hudakz | 0:84353c479782 | 1226 | statusRequest(); // Used to update wiiState - call isIRCameraEnabled() afterwards to check if it actually worked |
hudakz | 0:84353c479782 | 1227 | #ifdef DEBUG_USB_HOST |
hudakz | 0:84353c479782 | 1228 | Notify(PSTR("\r\nIR Initialized"), 0x80); |
hudakz | 0:84353c479782 | 1229 | #endif |
hudakz | 0:84353c479782 | 1230 | } |
hudakz | 0:84353c479782 | 1231 | |
hudakz | 0:84353c479782 | 1232 | void WII::enableIRCamera1() { |
hudakz | 0:84353c479782 | 1233 | uint8_t cmd_buf[3]; |
hudakz | 0:84353c479782 | 1234 | cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 1235 | cmd_buf[1] = 0x13; // Output report 13 |
hudakz | 0:84353c479782 | 1236 | cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2 |
hudakz | 0:84353c479782 | 1237 | HID_Command(cmd_buf, 3); |
hudakz | 0:84353c479782 | 1238 | } |
hudakz | 0:84353c479782 | 1239 | |
hudakz | 0:84353c479782 | 1240 | void WII::enableIRCamera2() { |
hudakz | 0:84353c479782 | 1241 | uint8_t cmd_buf[3]; |
hudakz | 0:84353c479782 | 1242 | cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
hudakz | 0:84353c479782 | 1243 | cmd_buf[1] = 0x1A; // Output report 1A |
hudakz | 0:84353c479782 | 1244 | cmd_buf[2] = 0x04 | (HIDBuffer[2] & 0x01); // Keep the rumble bit and sets bit 2 |
hudakz | 0:84353c479782 | 1245 | HID_Command(cmd_buf, 3); |
hudakz | 0:84353c479782 | 1246 | } |
hudakz | 0:84353c479782 | 1247 | |
hudakz | 0:84353c479782 | 1248 | void WII::writeSensitivityBlock1() { |
hudakz | 0:84353c479782 | 1249 | uint8_t buf[9]; |
hudakz | 0:84353c479782 | 1250 | buf[0] = 0x00; |
hudakz | 0:84353c479782 | 1251 | buf[1] = 0x00; |
hudakz | 0:84353c479782 | 1252 | buf[2] = 0x00; |
hudakz | 0:84353c479782 | 1253 | buf[3] = 0x00; |
hudakz | 0:84353c479782 | 1254 | buf[4] = 0x00; |
hudakz | 0:84353c479782 | 1255 | buf[5] = 0x00; |
hudakz | 0:84353c479782 | 1256 | buf[6] = 0x90; |
hudakz | 0:84353c479782 | 1257 | buf[7] = 0x00; |
hudakz | 0:84353c479782 | 1258 | buf[8] = 0x41; |
hudakz | 0:84353c479782 | 1259 | |
hudakz | 0:84353c479782 | 1260 | writeData(0xB00000, 9, buf); |
hudakz | 0:84353c479782 | 1261 | } |
hudakz | 0:84353c479782 | 1262 | |
hudakz | 0:84353c479782 | 1263 | void WII::writeSensitivityBlock2() { |
hudakz | 0:84353c479782 | 1264 | uint8_t buf[2]; |
hudakz | 0:84353c479782 | 1265 | buf[0] = 0x40; |
hudakz | 0:84353c479782 | 1266 | buf[1] = 0x00; |
hudakz | 0:84353c479782 | 1267 | |
hudakz | 0:84353c479782 | 1268 | writeData(0xB0001A, 2, buf); |
hudakz | 0:84353c479782 | 1269 | } |
hudakz | 0:84353c479782 | 1270 | |
hudakz | 0:84353c479782 | 1271 | void WII::write0x08Value() { |
hudakz | 0:84353c479782 | 1272 | uint8_t cmd = 0x08; |
hudakz | 0:84353c479782 | 1273 | writeData(0xb00030, 1, &cmd); |
hudakz | 0:84353c479782 | 1274 | } |
hudakz | 0:84353c479782 | 1275 | |
hudakz | 0:84353c479782 | 1276 | void WII::setWiiModeNumber(uint8_t mode_number) { // mode_number in hex i.e. 0x03 for extended mode |
hudakz | 0:84353c479782 | 1277 | writeData(0xb00033, 1, &mode_number); |
hudakz | 0:84353c479782 | 1278 | } |
hudakz | 0:84353c479782 | 1279 | #endif |