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