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