Merge pull request #146 from felis/WiiBalanceBoard

Added support for Wii balance board
This commit is contained in:
Kristian Sloth Lauszus 2015-04-25 01:27:16 +02:00
commit 7095b58896
7 changed files with 230 additions and 49 deletions

55
BTD.cpp
View file

@ -445,11 +445,17 @@ void BTD::HCI_event_task() {
for(uint8_t j = 0; j < 3; j++) for(uint8_t j = 0; j < 3; j++)
classOfDevice[j] = hcibuf[j + 4 + offset]; classOfDevice[j] = hcibuf[j + 4 + offset];
#ifdef EXTRADEBUG
Notify(PSTR("\r\nClass of device: "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
Notify(PSTR(" "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
Notify(PSTR(" "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
#endif
if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information
if(classOfDevice[0] & 0x08) // Check if it's the new Wiimote with motion plus inside that was detected checkRemoteName = true; // Check remote name to distinguish between the different controllers
motionPlusInside = true;
else
motionPlusInside = false;
for(uint8_t j = 0; j < 6; j++) for(uint8_t j = 0; j < 6; j++)
disc_bdaddr[j] = hcibuf[j + 3 + 6 * i]; disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
@ -472,16 +478,6 @@ void BTD::HCI_event_task() {
hci_set_flag(HCI_FLAG_DEVICE_FOUND); hci_set_flag(HCI_FLAG_DEVICE_FOUND);
break; break;
} }
#ifdef EXTRADEBUG
else {
Notify(PSTR("\r\nClass of device: "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
Notify(PSTR(" "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
Notify(PSTR(" "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
}
#endif
} }
} }
break; break;
@ -555,7 +551,7 @@ void BTD::HCI_event_task() {
case EV_PIN_CODE_REQUEST: case EV_PIN_CODE_REQUEST:
if(pairWithWii) { if(pairWithWii) {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nPairing with wiimote"), 0x80); Notify(PSTR("\r\nPairing with Wiimote"), 0x80);
#endif #endif
hci_pin_code_request_reply(); hci_pin_code_request_reply();
} else if(btdPin != NULL) { } else if(btdPin != NULL) {
@ -705,7 +701,7 @@ void BTD::HCI_task() {
if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
if(pairWithWii) if(pairWithWii)
Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press sync if you are using a Wii U Pro Controller"), 0x80); Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press the SYNC button if you are using a Wii U Pro Controller or a Wii Balance Board"), 0x80);
else else
Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80); Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80);
#endif #endif
@ -736,8 +732,8 @@ void BTD::HCI_task() {
else else
Notify(PSTR("device"), 0x80); Notify(PSTR("device"), 0x80);
#endif #endif
if(motionPlusInside) { if(checkRemoteName) {
hci_remote_name(); // We need to know the name to distinguish between a Wiimote and a Wii U Pro Controller hci_remote_name(); // We need to know the name to distinguish between the Wiimote, the new Wiimote with Motion Plus inside, a Wii U Pro Controller and a Wii Balance Board
hci_state = HCI_REMOTE_NAME_STATE; hci_state = HCI_REMOTE_NAME_STATE;
} else } else
hci_state = HCI_CONNECT_DEVICE_STATE; hci_state = HCI_CONNECT_DEVICE_STATE;
@ -752,6 +748,7 @@ void BTD::HCI_task() {
else else
Notify(PSTR("\r\nConnecting to HID device"), 0x80); Notify(PSTR("\r\nConnecting to HID device"), 0x80);
#endif #endif
checkRemoteName = false;
hci_connect(); hci_connect();
hci_state = HCI_CONNECTED_DEVICE_STATE; hci_state = HCI_CONNECTED_DEVICE_STATE;
} }
@ -809,6 +806,9 @@ void BTD::HCI_task() {
#endif #endif
if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) { if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
incomingWii = true; incomingWii = true;
motionPlusInside = false;
wiiUProController = false;
pairWiiUsingSync = false;
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWiimote is connecting"), 0x80); Notify(PSTR("\r\nWiimote is connecting"), 0x80);
#endif #endif
@ -821,11 +821,12 @@ void BTD::HCI_task() {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR(" - Wii U Pro Controller"), 0x80); Notify(PSTR(" - Wii U Pro Controller"), 0x80);
#endif #endif
motionPlusInside = true; wiiUProController = motionPlusInside = pairWiiUsingSync = true;
wiiUProController = true; } else if(strncmp((const char*)remote_name, "Nintendo RVL-WBC-01", 19) == 0) {
} else { #ifdef DEBUG_USB_HOST
motionPlusInside = false; Notify(PSTR(" - Wii Balance Board"), 0x80);
wiiUProController = false; #endif
pairWiiUsingSync = true;
} }
} }
if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) { if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {
@ -834,7 +835,7 @@ void BTD::HCI_task() {
#endif #endif
incomingPS4 = true; incomingPS4 = true;
} }
if(pairWithWii && motionPlusInside) if(pairWithWii && checkRemoteName)
hci_state = HCI_CONNECT_DEVICE_STATE; hci_state = HCI_CONNECT_DEVICE_STATE;
else { else {
hci_accept_connection(); hci_accept_connection();
@ -886,7 +887,7 @@ void BTD::HCI_task() {
memset(l2capinbuf, 0, BULK_MAXPKTSIZE); memset(l2capinbuf, 0, BULK_MAXPKTSIZE);
connectToWii = incomingWii = pairWithWii = false; connectToWii = incomingWii = pairWithWii = false;
connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = false; connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = checkRemoteName = false;
incomingPS4 = false; incomingPS4 = false;
hci_state = HCI_SCANNING_STATE; hci_state = HCI_SCANNING_STATE;
@ -1085,9 +1086,9 @@ void BTD::hci_pin_code_request_reply() {
hcibuf[8] = disc_bdaddr[5]; hcibuf[8] = disc_bdaddr[5];
if(pairWithWii) { if(pairWithWii) {
hcibuf[9] = 6; // Pin length is the length of the Bluetooth address hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
if(wiiUProController) { if(pairWiiUsingSync) {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nParing with Wii U Pro Controller"), 0x80); Notify(PSTR("\r\nParing with Wii controller via SYNC"), 0x80);
#endif #endif
for(uint8_t i = 0; i < 6; i++) for(uint8_t i = 0; i < 6; i++)
hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards

2
BTD.h
View file

@ -535,6 +535,8 @@ private:
uint8_t pollInterval; uint8_t pollInterval;
bool bPollEnable; bool bPollEnable;
bool pairWiiUsingSync; // True if paring was done using the Wii SYNC button.
bool checkRemoteName; // Used to check remote device's name before connecting.
bool incomingPS4; // True if a PS4 controller is connecting bool incomingPS4; // True if a PS4 controller is connecting
uint8_t classOfDevice[3]; // Class of device of last device uint8_t classOfDevice[3]; // Class of device of last device

View file

@ -37,6 +37,8 @@ Help yourself by helping us support you! Many thousands of hours have been spent
# Table of Contents # Table of Contents
* [How to include the library](#how-to-include-the-library) * [How to include the library](#how-to-include-the-library)
* [Arduino Library Manager](#arduino-library-manager)
* [Manual installation](#manual-installation)
* [How to use the library](#how-to-use-the-library) * [How to use the library](#how-to-use-the-library)
* [Documentation](#documentation) * [Documentation](#documentation)
* [Enable debugging](#enable-debugging) * [Enable debugging](#enable-debugging)
@ -57,6 +59,14 @@ Help yourself by helping us support you! Many thousands of hours have been spent
# How to include the library # How to include the library
### Arduino Library Manager
First install Arduino IDE version 1.6.2 or newer, then simply use the Arduino Library Manager to install the library.
Please see the following page for instructions: <http://www.arduino.cc/en/Guide/Libraries#toc3>.
### Manual installation
First download the library by clicking on the following link: <https://github.com/felis/USB_Host_Shield_2.0/archive/master.zip>. First download the library by clicking on the following link: <https://github.com/felis/USB_Host_Shield_2.0/archive/master.zip>.
Then uncompress the zip folder and rename the directory to "USB\_Host\_Shield\_20", as any special characters are not supported by the Arduino IDE. Then uncompress the zip folder and rename the directory to "USB\_Host\_Shield\_20", as any special characters are not supported by the Arduino IDE.
@ -243,7 +253,7 @@ An Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class.
### [Wii library](Wii.cpp) ### [Wii library](Wii.cpp)
The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth. The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller and Wii Balance Board are also supported via Bluetooth.
First you have to pair with the controller, this is done automatically by the library if you create the instance like so: First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
@ -251,7 +261,7 @@ First you have to pair with the controller, this is done automatically by the li
WII Wii(&Btd, PAIR); WII Wii(&Btd, PAIR);
``` ```
And then press 1 & 2 at once on the Wiimote or press sync if you are using a Wii U Pro Controller. And then press 1 & 2 at once on the Wiimote or the SYNC buttons if you are using a Wii U Pro Controller or a Wii Balance Board.
After that you can simply create the instance like so: After that you can simply create the instance like so:
@ -271,13 +281,13 @@ The Wii IR camera can also be used, but you will have to activate the code for i
The [WiiIRCamera.ino](examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino) example shows how it can be used. The [WiiIRCamera.ino](examples/Bluetooth/WiiIRCamera/WiiIRCamera.ino) example shows how it can be used.
All the information about the Wii controllers are from these sites: All the information about the Wii controllers are from these sites:
* <http://wiibrew.org/wiki/Wiimote> * <http://wiibrew.org/wiki/Wiimote>
* <http://wiibrew.org/wiki/Wiimote/Extension_Controllers> * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers>
* <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck> * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck>
* <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Wii_Motion_Plus> * <http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Wii_Motion_Plus>
* <http://wiibrew.org/wiki/Wii_Balance_Board>
* The old library created by _Tomoyuki Tanaka_: <https://github.com/moyuchin/WiiRemote_on_Arduino> also helped a lot. * The old library created by _Tomoyuki Tanaka_: <https://github.com/moyuchin/WiiRemote_on_Arduino> also helped a lot.
### [PS Buzz Library](PSBuzz.cpp) ### [PS Buzz Library](PSBuzz.cpp)
@ -338,4 +348,4 @@ LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0
> When compiling I am getting the following error: "fatal error: SPI.h: No such file or directory". > When compiling I am getting the following error: "fatal error: SPI.h: No such file or directory".
* Please make sure to include the SPI library like so: ```#include <SPI.h>``` in your .ino file. * Please make sure to include the SPI library like so: ```#include <SPI.h>``` in your .ino file.

99
Wii.cpp
View file

@ -108,6 +108,7 @@ void WII::Reset() {
motionPlusInside = false; motionPlusInside = false;
pBtd->wiiUProController = false; pBtd->wiiUProController = false;
wiiUProControllerConnected = false; wiiUProControllerConnected = false;
wiiBalanceBoardConnected = false;
l2cap_event_flag = 0; // Reset flags l2cap_event_flag = 0; // Reset flags
l2cap_state = L2CAP_WAIT; l2cap_state = L2CAP_WAIT;
} }
@ -263,7 +264,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
else if(wiiUProControllerConnected) else if(wiiUProControllerConnected)
ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16)); ButtonState = (uint32_t)(((~l2capinbuf[23]) & 0xFE) | ((uint16_t)(~l2capinbuf[24]) << 8) | ((uint32_t)((~l2capinbuf[25]) & 0x03) << 16));
else if(motionPlusConnected) { else if(motionPlusConnected) {
if(l2capinbuf[20] & 0x02) // Only update the wiimote buttons, since the extension bytes are from the Motion Plus if(l2capinbuf[20] & 0x02) // Only update the Wiimote buttons, since the extension bytes are from the Motion Plus
ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000))); ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(ButtonState & 0xFFFF0000)));
else if(nunchuckConnected) // Update if it's a report from the Nunchuck else if(nunchuckConnected) // Update if it's a report from the Nunchuck
ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14)); ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)((~l2capinbuf[20]) & 0x0C) << 14));
@ -295,11 +296,8 @@ void WII::ACLData(uint8_t* l2capinbuf) {
#endif #endif
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) 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)
batteryLevel = l2capinbuf[15]; // Update battery level batteryLevel = l2capinbuf[15]; // Update battery level
#ifdef DEBUG_USB_HOST
if(l2capinbuf[12] & 0x01) if(!checkBatteryLevel) { // If this is true it means that the user must have called getBatteryLevel()
Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80);
#endif
if(checkExtension) { // If this is false it means that the user must have called getBatteryLevel()
if(l2capinbuf[12] & 0x02) { // Check if a extension is connected if(l2capinbuf[12] & 0x02) { // Check if a extension is connected
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
if(!unknownExtensionConnected) if(!unknownExtensionConnected)
@ -333,11 +331,22 @@ void WII::ACLData(uint8_t* l2capinbuf) {
} else } else
setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
} }
} else }
checkExtension = true; // Check for extensions by default else {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nChecking battery level"), 0x80);
#endif
checkBatteryLevel = false; // Check for extensions by default
}
#ifdef DEBUG_USB_HOST
if(l2capinbuf[12] & 0x01)
Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80);
#endif
break; break;
case 0x21: // Read Memory Data case 0x21: // Read Memory Data
if((l2capinbuf[12] & 0x0F) == 0) { // No error if((l2capinbuf[12] & 0x0F) == 0) { // No error
uint8_t reportLength = (l2capinbuf[12] >> 4) + 1; // // Bit 4-7 is the length - 1
// See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers // See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
@ -380,6 +389,27 @@ void WII::ACLData(uint8_t* l2capinbuf) {
Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80); Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80);
#endif #endif
wiiUProControllerConnected = true; wiiUProControllerConnected = true;
} else if(l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x02) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWii Balance Board connected"), 0x80);
#endif
setReportMode(false, 0x32); // Read the Wii Balance Board extension
wii_set_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD);
}
// Wii Balance Board calibration reports (24 bits in total)
else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x24 && reportLength == 16) { // First 16-bit
for(uint8_t i = 0; i < 2; i++) {
for(uint8_t j = 0; j < 4; j++)
wiiBalanceBoardCal[i][j] = l2capinbuf[16 + 8 * i + 2 * j] | l2capinbuf[15 + 8 * i + 2 * j] << 8;
}
} else if(l2capinbuf[13] == 0x00 && l2capinbuf[14] == 0x34 && reportLength == 8) { // Last 8-bit
for(uint8_t j = 0; j < 4; j++)
wiiBalanceBoardCal[2][j] = l2capinbuf[16 + 2 * j] | l2capinbuf[15 + 2 * j] << 8;
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nWii Balance Board calibration values read successfully"), 0x80);
#endif
wii_clear_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD);
wiiBalanceBoardConnected = true;
} }
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
else { else {
@ -387,7 +417,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
Notify(PSTR("\r\nData: "), 0x80); Notify(PSTR("\r\nData: "), 0x80);
for(uint8_t i = 0; i < ((l2capinbuf[12] >> 4) + 1); i++) { // bit 4-7 is the length-1 for(uint8_t i = 0; i < reportLength; i++) {
D_PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80); D_PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80);
Notify(PSTR(" "), 0x80); Notify(PSTR(" "), 0x80);
} }
@ -415,13 +445,18 @@ void WII::ACLData(uint8_t* l2capinbuf) {
case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA case 0x31: // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA
break; break;
case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE case 0x32: // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE
// See: http://wiibrew.org/wiki/Wii_Balance_Board#Data_Format
wiiBalanceBoardRaw[TopRight] = l2capinbuf[13] | l2capinbuf[12] << 8; // Top right
wiiBalanceBoardRaw[BotRight] = l2capinbuf[15] | l2capinbuf[14] << 8; // Bottom right
wiiBalanceBoardRaw[TopLeft] = l2capinbuf[17] | l2capinbuf[16] << 8; // Top left
wiiBalanceBoardRaw[BotLeft] = l2capinbuf[19] | l2capinbuf[18] << 8; // Bottom left
break; break;
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 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
#ifdef WIICAMERA #ifdef WIICAMERA
// Read the IR data // Read the IR data
IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position IR_object_x1 = (l2capinbuf[15] | ((uint16_t)(l2capinbuf[17] & 0x30) << 4)); // x position
IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position IR_object_y1 = (l2capinbuf[16] | ((uint16_t)(l2capinbuf[17] & 0xC0) << 2)); // y position
IR_object_s1 = (l2capinbuf[17] & 0x0F); // size value, 0-15 IR_object_s1 = (l2capinbuf[17] & 0x0F); // Size value, 0-15
IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4)); IR_object_x2 = (l2capinbuf[18] | ((uint16_t)(l2capinbuf[20] & 0x30) << 4));
IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2)); IR_object_y2 = (l2capinbuf[19] | ((uint16_t)(l2capinbuf[20] & 0xC0) << 2));
@ -460,6 +495,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
break; break;
case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes case 0x35: // Core Buttons and Accelerometer with 16 Extension Bytes
// (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE // (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
#if 1 // Set this to 0 if you don't want to use an extension, this reduceds the size of the library a lot!
if(motionPlusConnected) { if(motionPlusConnected) {
if(l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension if(l2capinbuf[20] & 0x02) { // Check if it's a report from the Motion controller or the extension
if(motionValuesReset) { // We will only use the values when the gyro value has been set if(motionValuesReset) { // We will only use the values when the gyro value has been set
@ -563,6 +599,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8); hatValues[LeftHatY] = (l2capinbuf[19] | l2capinbuf[20] << 8);
hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8); hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8);
} }
#endif
break; break;
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
default: default:
@ -751,13 +788,21 @@ void WII::Run() {
if(unknownExtensionConnected) // Check if there is a extension is connected to the port if(unknownExtensionConnected) // Check if there is a extension is connected to the port
initExtension1(); initExtension1();
else else
stateCounter = 399; stateCounter = 499;
} else if(stateCounter == 200) } else if(stateCounter == 200)
initExtension2(); initExtension2();
else if(stateCounter == 300) { else if(stateCounter == 300) {
readExtensionType(); readExtensionType();
unknownExtensionConnected = false; unknownExtensionConnected = false;
} else if(stateCounter == 400) { } else if(stateCounter == 400) {
if(wii_check_flag(WII_FLAG_CALIBRATE_BALANCE_BOARD)) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReading Wii Balance Board calibration values"), 0x80);
#endif
readWiiBalanceBoardCalibration();
} else
stateCounter = 499;
} else if(stateCounter == 500) {
stateCounter = 0; stateCounter = 0;
l2cap_state = TURN_ON_LED; l2cap_state = TURN_ON_LED;
} }
@ -839,8 +884,8 @@ void WII::Run() {
/************************************************************/ /************************************************************/
/* HID Commands */ /* HID Commands */
/************************************************************/ /************************************************************/
void WII::HID_Command(uint8_t* data, uint8_t nbytes) { void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
if(motionPlusInside) if(motionPlusInside)
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 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
@ -914,7 +959,7 @@ void WII::setLedStatus() {
} }
uint8_t WII::getBatteryLevel() { uint8_t WII::getBatteryLevel() {
checkExtension = false; // This is needed so the library knows that the status response is a response to this function checkBatteryLevel = true; // This is needed so the library knows that the status response is a response to this function
statusRequest(); // This will update the battery level statusRequest(); // This will update the battery level
return batteryLevel; return batteryLevel;
}; };
@ -941,8 +986,8 @@ void WII::statusRequest() {
/************************************************************/ /************************************************************/
/* Memmory Commands */ /* Memmory Commands */
/************************************************************/ /************************************************************/
void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) { void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) {
uint8_t cmd_buf[23]; uint8_t cmd_buf[23];
cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
@ -1030,9 +1075,12 @@ void WII::checkMotionPresent() {
readData(0xA600FA, 6, false); readData(0xA600FA, 6, false);
} }
void WII::readWiiBalanceBoardCalibration() {
readData(0xA40024, 24, false);
}
/************************************************************/ /************************************************************/
/* WII Commands */ /* WII Commands */
/************************************************************/ /************************************************************/
bool WII::getButtonPress(ButtonEnum b) { // Return true when a button is pressed bool WII::getButtonPress(ButtonEnum b) { // Return true when a button is pressed
@ -1084,6 +1132,27 @@ void WII::onInit() {
setLedStatus(); setLedStatus();
} }
/************************************************************/
/* Wii Balance Board Commands */
/************************************************************/
float WII::getWeight(BalanceBoardEnum pos) {
// Use interpolating between two points - based on: https://github.com/skorokithakis/gr8w8upd8m8/blob/master/gr8w8upd8m8.py
// wiiBalanceBoardCal[pos][0] is calibration values for 0 kg
// wiiBalanceBoardCal[pos][1] is calibration values for 17 kg
// wiiBalanceBoardCal[pos][2] is calibration values for 34 kg
if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[0][pos])
return 0.0f; // Below 0 kg
else if(wiiBalanceBoardRaw[pos] < wiiBalanceBoardCal[1][pos]) // Between 0 and 17 kg
return 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[0][pos]) / (float)(wiiBalanceBoardCal[1][pos] - wiiBalanceBoardCal[0][pos]);
else // More than 17 kg
return 17.0f + 17.0f * (float)(wiiBalanceBoardRaw[pos] - wiiBalanceBoardCal[1][pos]) / (float)(wiiBalanceBoardCal[2][pos] - wiiBalanceBoardCal[1][pos]);
};
float WII::getTotalWeight() {
return getWeight(TopRight) + getWeight(BotRight) + getWeight(TopLeft) + getWeight(BotLeft);
};
/************************************************************/ /************************************************************/
/* The following functions are for the IR camera */ /* The following functions are for the IR camera */
/************************************************************/ /************************************************************/

46
Wii.h
View file

@ -24,8 +24,9 @@
#include "controllerEnums.h" #include "controllerEnums.h"
/* Wii event flags */ /* Wii event flags */
#define WII_FLAG_MOTION_PLUS_CONNECTED 0x01 #define WII_FLAG_MOTION_PLUS_CONNECTED (1 << 0)
#define WII_FLAG_NUNCHUCK_CONNECTED 0x02 #define WII_FLAG_NUNCHUCK_CONNECTED (1 << 1)
#define WII_FLAG_CALIBRATE_BALANCE_BOARD (1 << 2)
#define wii_check_flag(flag) (wii_event_flag & (flag)) #define wii_check_flag(flag) (wii_event_flag & (flag))
#define wii_set_flag(flag) (wii_event_flag |= (flag)) #define wii_set_flag(flag) (wii_event_flag |= (flag))
@ -39,6 +40,14 @@ enum HatEnum {
HatY = 1, HatY = 1,
}; };
/** Enum used to read the weight on Wii Balance Board. */
enum BalanceBoardEnum {
TopRight = 0,
BotRight = 1,
TopLeft = 2,
BotLeft = 3,
};
/** /**
* This BluetoothService class implements support for the Wiimote including the Nunchuck and Motion Plus extension. * This BluetoothService class implements support for the Wiimote including the Nunchuck and Motion Plus extension.
* *
@ -191,6 +200,8 @@ public:
bool motionPlusConnected; bool motionPlusConnected;
/** Variable used to indicate if a Wii U Pro controller is connected. */ /** Variable used to indicate if a Wii U Pro controller is connected. */
bool wiiUProControllerConnected; bool wiiUProControllerConnected;
/** Variable used to indicate if a Wii Balance Board is connected. */
bool wiiBalanceBoardConnected;
/**@}*/ /**@}*/
/* IMU Data, might be usefull if you need to do something more advanced than just calculating the angle */ /* IMU Data, might be usefull if you need to do something more advanced than just calculating the angle */
@ -261,6 +272,31 @@ public:
int16_t gyroPitchZero; int16_t gyroPitchZero;
/**@}*/ /**@}*/
/** @name Wii Balance Board functions */
/**
* Used to get the weight at the specific position on the Wii Balance Board.
* @param ::BalanceBoardEnum to read from.
* @return Returns the weight in kg.
*/
float getWeight(BalanceBoardEnum pos);
/**
* Used to get total weight on the Wii Balance Board.
* @returnReturns the weight in kg.
*/
float getTotalWeight();
/**
* Used to get the raw reading at the specific position on the Wii Balance Board.
* @param ::BalanceBoardEnum to read from.
* @return Returns the raw reading.
*/
uint16_t getWeightRaw(BalanceBoardEnum pos) {
return wiiBalanceBoardRaw[pos];
};
/**@}*/
#ifdef WIICAMERA #ifdef WIICAMERA
/** @name Wiimote IR camera functions /** @name Wiimote IR camera functions
* You will have to set ::ENABLE_WII_IR_CAMERA in settings.h to 1 in order use the IR camera. * You will have to set ::ENABLE_WII_IR_CAMERA in settings.h to 1 in order use the IR camera.
@ -415,7 +451,7 @@ private:
uint16_t stateCounter; uint16_t stateCounter;
bool unknownExtensionConnected; bool unknownExtensionConnected;
bool extensionConnected; bool extensionConnected;
bool checkExtension; // Set to false when getBatteryLevel() is called otherwise if should be true bool checkBatteryLevel; // Set to true when getBatteryLevel() is called otherwise if should be false
bool motionPlusInside; // True if it's a new Wiimote with the Motion Plus extension build into it bool motionPlusInside; // True if it's a new Wiimote with the Motion Plus extension build into it
/* L2CAP Channels */ /* L2CAP Channels */
@ -437,11 +473,15 @@ private:
void readData(uint32_t offset, uint16_t size, bool EEPROM); void readData(uint32_t offset, uint16_t size, bool EEPROM);
void readExtensionType(); void readExtensionType();
void readCalData(); void readCalData();
void readWiiBalanceBoardCalibration(); // Used by the library to read the Wii Balance Board calibration values
void checkMotionPresent(); // Used to see if a Motion Plus is connected to the Wiimote void checkMotionPresent(); // Used to see if a Motion Plus is connected to the Wiimote
void initMotionPlus(); void initMotionPlus();
void activateMotionPlus(); void activateMotionPlus();
uint16_t wiiBalanceBoardRaw[4]; // Wii Balance Board raw values
uint16_t wiiBalanceBoardCal[3][4]; // Wii Balance Board calibration values
double compPitch; // Fusioned angle using a complimentary filter if the Motion Plus is connected double compPitch; // Fusioned angle using a complimentary filter if the Motion Plus is connected
double compRoll; // Fusioned angle using a complimentary filter if the Motion Plus is connected double compRoll; // Fusioned angle using a complimentary filter if the Motion Plus is connected

View file

@ -0,0 +1,51 @@
/*
Example sketch for the Wii Balance Board Bluetooth library - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <Wii.h>
#include <usbhub.h>
// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#include <SPI.h>
#endif
USB Usb;
//USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the class in two ways */
WII Wii(&Btd, PAIR); // This will start an inquiry and then pair with your Wii Balance Board - you only have to do this once
//WII Wii(&Btd); // After that you can simply create the instance like so and then press the power button on the Wii Balance Board
void setup() {
Serial.begin(115200);
#if !defined(__MIPSEL__)
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while (1); //halt
}
Serial.print(F("\r\nWii Balance Board Bluetooth Library Started"));
}
void loop() {
Usb.Task();
if (Wii.wiiBalanceBoardConnected) {
Serial.print(F("\r\nWeight: "));
for (uint8_t i = 0; i < 4; i++) {
Serial.print(Wii.getWeight((BalanceBoardEnum)i));
Serial.print(F("\t"));
}
Serial.print(F("Total Weight: "));
Serial.print(Wii.getTotalWeight());
if (Wii.getButtonClick(A)) {
Serial.print(F("\r\nA"));
//Wii.setLedToggle(LED1); // The Wii Balance Board has one LED as well
Wii.disconnect();
}
}
}

View file

@ -269,6 +269,7 @@ wiimoteConnected KEYWORD2
nunchuckConnected KEYWORD2 nunchuckConnected KEYWORD2
motionPlusConnected KEYWORD2 motionPlusConnected KEYWORD2
wiiUProControllerConnected KEYWORD2 wiiUProControllerConnected KEYWORD2
wiiBalanceBoardConnected KEYWORD2
setRumbleToggle KEYWORD2 setRumbleToggle KEYWORD2
getPitch KEYWORD2 getPitch KEYWORD2
getRoll KEYWORD2 getRoll KEYWORD2
@ -281,6 +282,9 @@ PAIR KEYWORD2
statusRequest KEYWORD2 statusRequest KEYWORD2
getBatteryLevel KEYWORD2 getBatteryLevel KEYWORD2
getWiiState KEYWORD2 getWiiState KEYWORD2
getWeight KEYWORD2
getTotalWeight KEYWORD2
getWeightRaw KEYWORD2
#################################################### ####################################################
# Constants and enums (LITERAL1) # Constants and enums (LITERAL1)
@ -299,6 +303,10 @@ ZL LITERAL1
ZR LITERAL1 ZR LITERAL1
HatX LITERAL1 HatX LITERAL1
HatY LITERAL1 HatY LITERAL1
TopRight LITERAL1
BotRight LITERAL1
TopLeft LITERAL1
BotLeft LITERAL1
#################################################### ####################################################
# Methods and Functions for the IR Camera # Methods and Functions for the IR Camera