mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Added support for the Nunchuck controller
This commit is contained in:
parent
d4d196b65a
commit
c138bf0492
5 changed files with 337 additions and 182 deletions
252
Wii.cpp
252
Wii.cpp
|
@ -18,7 +18,7 @@
|
||||||
#include "Wii.h"
|
#include "Wii.h"
|
||||||
#define DEBUG // Uncomment to print data for debugging
|
#define DEBUG // Uncomment to print data for debugging
|
||||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||||
//#define PRINTREPORT // Uncomment to print the report send by the Wiimote
|
//#define PRINTREPORT // Uncomment to print the report send by the Wii controllers
|
||||||
|
|
||||||
WII::WII(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
|
WII::WII(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
|
||||||
pBtd(p) // pointer to USB class instance - mandatory
|
pBtd(p) // pointer to USB class instance - mandatory
|
||||||
|
@ -44,7 +44,8 @@ pBtd(p) // pointer to USB class instance - mandatory
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
void WII::Reset() {
|
void WII::Reset() {
|
||||||
connected = false;
|
wiimoteConnected = false;
|
||||||
|
nunchuckConnected = false;
|
||||||
l2cap_event_flag = 0; // Reset flags
|
l2cap_event_flag = 0; // Reset flags
|
||||||
l2cap_state = L2CAP_WAIT;
|
l2cap_state = L2CAP_WAIT;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,8 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Notify(PSTR("\r\nDisconnect Request: Control Channel"));
|
Notify(PSTR("\r\nDisconnect Request: Control Channel"));
|
||||||
#endif
|
#endif
|
||||||
connected = false;
|
wiimoteConnected = false;
|
||||||
|
nunchuckConnected = false;
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
pBtd->l2cap_disconnection_response(hci_handle,identifier,control_dcid,control_scid);
|
pBtd->l2cap_disconnection_response(hci_handle,identifier,control_dcid,control_scid);
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -131,7 +133,8 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"));
|
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"));
|
||||||
#endif
|
#endif
|
||||||
connected = false;
|
wiimoteConnected = false;
|
||||||
|
nunchuckConnected = false;
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
pBtd->l2cap_disconnection_response(hci_handle,identifier,interrupt_dcid,interrupt_scid);
|
pBtd->l2cap_disconnection_response(hci_handle,identifier,interrupt_dcid,interrupt_scid);
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -158,38 +161,26 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
||||||
#endif
|
#endif
|
||||||
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
|
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
|
||||||
//Serial.print("\r\nL2CAP Interrupt");
|
//Serial.print("\r\nL2CAP Interrupt");
|
||||||
if(connected) {
|
if(wiimoteConnected) {
|
||||||
/* Read Report */
|
|
||||||
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
||||||
if(l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) { // These reports include the buttons
|
if(l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) { // These reports include the buttons
|
||||||
ButtonState = (uint16_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
|
if(nunchuckConnected)
|
||||||
ButtonClickState = ButtonState; // Update click state variable
|
ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8) | ((uint32_t)(l2capinbuf[20] & 0x03) << 16));
|
||||||
|
else
|
||||||
|
ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
|
||||||
#ifdef PRINTREPORT
|
#ifdef PRINTREPORT
|
||||||
Notify(PSTR("ButtonState: "));
|
Notify(PSTR("ButtonState: "));
|
||||||
PrintHex<uint16_t>(ButtonState);
|
PrintHex<uint32_t>(ButtonState);
|
||||||
Notify(PSTR("\r\n"));
|
Notify(PSTR("\r\n"));
|
||||||
#endif
|
#endif
|
||||||
if(ButtonState != OldButtonState) {
|
if(ButtonState != OldButtonState)
|
||||||
buttonChanged = true;
|
ButtonClickState = ButtonState; // Update click state variable
|
||||||
if(ButtonState != 0x0000) {
|
|
||||||
buttonPressed = true;
|
|
||||||
buttonReleased = false;
|
|
||||||
} else {
|
|
||||||
buttonPressed = false;
|
|
||||||
buttonReleased = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buttonChanged = false;
|
|
||||||
buttonPressed = false;
|
|
||||||
buttonReleased = false;
|
|
||||||
}
|
|
||||||
OldButtonState = ButtonState;
|
OldButtonState = ButtonState;
|
||||||
}
|
}
|
||||||
if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x35) { // Read the accelerometer
|
if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x35) { // Read the accelerometer
|
||||||
int16_t accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5))-500;
|
accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5))-500;
|
||||||
int16_t accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4))-500;
|
accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4))-500;
|
||||||
int16_t accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5))-500;
|
accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5))-500;
|
||||||
/*
|
/*
|
||||||
Notify(PSTR("\r\naccX: "));
|
Notify(PSTR("\r\naccX: "));
|
||||||
Serial.print(accX);
|
Serial.print(accX);
|
||||||
|
@ -200,20 +191,60 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
||||||
*/
|
*/
|
||||||
pitch = (atan2(accY,accZ)+PI)*RAD_TO_DEG;
|
pitch = (atan2(accY,accZ)+PI)*RAD_TO_DEG;
|
||||||
roll = (atan2(accX,accZ)+PI)*RAD_TO_DEG;
|
roll = (atan2(accX,accZ)+PI)*RAD_TO_DEG;
|
||||||
/*
|
|
||||||
Notify(PSTR("\r\nPitch: "));
|
|
||||||
Serial.print(pitch);
|
|
||||||
Notify(PSTR("\tRoll: "));
|
|
||||||
Serial.print(roll);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
switch (l2capinbuf[9]) {
|
switch (l2capinbuf[9]) {
|
||||||
case 0x20: // Status Information
|
case 0x20: // Status Information
|
||||||
// (a1) 20 BB BB LF 00 00 VV
|
// (a1) 20 BB BB LF 00 00 VV
|
||||||
if(l2capinbuf[12] & 0x02) // Check if a extension is connected
|
if(l2capinbuf[12] & 0x02) { // Check if a extension is connected
|
||||||
setReportMode(false,0x35); // Also read the extension
|
#ifdef DEBUG
|
||||||
else
|
Notify(PSTR("\r\nExtension connected"));
|
||||||
|
#endif
|
||||||
|
setReportMode(false,0x35); // Also read the extension
|
||||||
|
activateState = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef DEBUG
|
||||||
|
Notify(PSTR("\r\nExtension disconnected"));
|
||||||
|
#endif
|
||||||
|
nunchuckConnected = false;
|
||||||
setReportMode(false,0x31); // If there is no extension connected we will read the button and accelerometer
|
setReportMode(false,0x31); // If there is no extension connected we will read the button and accelerometer
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x21: // Read Memory Data
|
||||||
|
if((l2capinbuf[12] & 0x0F) == 0) { // No error
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
|
Notify(PSTR("\r\nGot report: "));
|
||||||
|
PrintHex<uint8_t>(l2capinbuf[13]);
|
||||||
|
PrintHex<uint8_t>(l2capinbuf[14]);
|
||||||
|
Notify(PSTR("\r\nData: "));
|
||||||
|
for(uint8_t i = 0; i < ((l2capinbuf[12] >> 4)+1); i++) // bit 4-7 is the length-1
|
||||||
|
PrintHex<uint8_t>(l2capinbuf[15+i]);
|
||||||
|
#endif
|
||||||
|
if(l2capinbuf[15] == 0x00 && l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) { // See // http://wiibrew.org/wiki/Wiimote/Extension_Controllers
|
||||||
|
#ifdef DEBUG
|
||||||
|
Notify(PSTR("\r\nNunchuck connected"));
|
||||||
|
#endif
|
||||||
|
nunchuckConnected = true;
|
||||||
|
ButtonState |= (Z | C); // Since the Nunchuck button are cleared when pressed we set the buttonstates like so
|
||||||
|
ButtonClickState |= (Z | C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
else {
|
||||||
|
Notify(PSTR("\r\nReport Error: "));
|
||||||
|
PrintHex<uint8_t>(l2capinbuf[13]);
|
||||||
|
PrintHex<uint8_t>(l2capinbuf[14]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 0x22: // Acknowledge output report, return function result
|
||||||
|
#ifdef DEBUG
|
||||||
|
if(l2capinbuf[13] != 0x00) { // Check if there is an error
|
||||||
|
Notify(PSTR("\r\nCommand failed: "));
|
||||||
|
PrintHex<uint8_t>(l2capinbuf[12]);
|
||||||
|
} else if(l2capinbuf[12] == 0x16 && activateState > 20)
|
||||||
|
Notify(PSTR("\r\nExtension activated"));
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case 0x30: // Core buttons
|
case 0x30: // Core buttons
|
||||||
// (a1) 30 BB BB
|
// (a1) 30 BB BB
|
||||||
|
@ -222,34 +253,41 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
||||||
// (a1) 31 BB BB AA AA AA
|
// (a1) 31 BB BB AA AA AA
|
||||||
break;
|
break;
|
||||||
case 0x32: // Core Buttons with 8 Extension bytes
|
case 0x32: // Core Buttons with 8 Extension bytes
|
||||||
// (a1) 32 BB BB EE EE EE EE EE EE EE EE
|
// (a1) 32 BB BB EE EE EE EE EE EE EE EE
|
||||||
/*
|
|
||||||
Notify(PSTR("\r\n"));
|
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
|
||||||
Serial.print(l2capinbuf[12+i]);
|
|
||||||
Notify(PSTR(" "));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
case 0x34: // Core Buttons with 19 Extension bytes
|
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
|
// (a1) 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
|
||||||
/*
|
|
||||||
Notify(PSTR("\r\n"));
|
|
||||||
for (uint8_t i = 0; i < 19; i++) {
|
|
||||||
Serial.print(l2capinbuf[12+i]);
|
|
||||||
Notify(PSTR(" "));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
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(activateState == 10) {
|
||||||
|
activateExtension1();
|
||||||
|
activateState = 11;
|
||||||
|
} else if(activateState == 20) {
|
||||||
|
activateExtension2();
|
||||||
|
activateState = 21;
|
||||||
|
} else if(activateState == 30) {
|
||||||
|
readExtensionType();
|
||||||
|
activateState = 31;
|
||||||
|
} else if(activateState < 31)
|
||||||
|
activateState++; // We make this counter as there has to be a short delay between the commands
|
||||||
|
|
||||||
|
hatValues[0] = l2capinbuf[15];
|
||||||
|
hatValues[1] = l2capinbuf[16];
|
||||||
|
|
||||||
|
accX = ((l2capinbuf[17] << 2) | (l2capinbuf[20] & 0x0C >> 2))-416;
|
||||||
|
accY = ((l2capinbuf[18] << 2) | (l2capinbuf[20] & 0x30 >> 4))-416;
|
||||||
|
accZ = ((l2capinbuf[19] << 2) | (l2capinbuf[20] & 0xC0 >> 6))-416;
|
||||||
/*
|
/*
|
||||||
Notify(PSTR("\r\n"));
|
Notify(PSTR("\r\naccX: "));
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
Serial.print(accX);
|
||||||
Serial.print(l2capinbuf[15+i]);
|
Notify(PSTR("\taccY: "));
|
||||||
Notify(PSTR(" "));
|
Serial.print(accY);
|
||||||
}
|
Notify(PSTR("\taccZ: "));
|
||||||
*/
|
Serial.print(accZ);
|
||||||
|
*/
|
||||||
|
nunchuckPitch = (atan2(accY,accZ)+PI)*RAD_TO_DEG;
|
||||||
|
nunchuckRoll = (atan2(accX,accZ)+PI)*RAD_TO_DEG;
|
||||||
break;
|
break;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
default:
|
default:
|
||||||
|
@ -311,7 +349,7 @@ void WII::L2CAP_task() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_WII_STATUS_STATE:
|
case L2CAP_WII_STATUS_STATE:
|
||||||
connected = true;
|
wiimoteConnected = true;
|
||||||
pBtd->connectToWii = false;
|
pBtd->connectToWii = false;
|
||||||
ButtonState = 0;
|
ButtonState = 0;
|
||||||
OldButtonState = 0;
|
OldButtonState = 0;
|
||||||
|
@ -376,27 +414,31 @@ void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
|
||||||
void WII::setAllOff() {
|
void WII::setAllOff() {
|
||||||
HIDBuffer[1] = 0x11;
|
HIDBuffer[1] = 0x11;
|
||||||
HIDBuffer[2] = 0x00;
|
HIDBuffer[2] = 0x00;
|
||||||
|
rumbleBit = 0x00;
|
||||||
HID_Command(HIDBuffer, 3);
|
HID_Command(HIDBuffer, 3);
|
||||||
}
|
}
|
||||||
void WII::setRumbleOff() {
|
void WII::setRumbleOff() {
|
||||||
HIDBuffer[1] = 0x11;
|
HIDBuffer[1] = 0x11;
|
||||||
HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble
|
HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble
|
||||||
|
rumbleBit = 0x00;
|
||||||
HID_Command(HIDBuffer, 3);
|
HID_Command(HIDBuffer, 3);
|
||||||
}
|
}
|
||||||
void WII::setRumbleOn() {
|
void WII::setRumbleOn() {
|
||||||
HIDBuffer[1] = 0x11;
|
HIDBuffer[1] = 0x11;
|
||||||
HIDBuffer[2] |= 0x01; // Bit 0 control the rumble
|
HIDBuffer[2] |= 0x01; // Bit 0 control the rumble
|
||||||
|
rumbleBit = 0x01;
|
||||||
HID_Command(HIDBuffer, 3);
|
HID_Command(HIDBuffer, 3);
|
||||||
}
|
}
|
||||||
void WII::setRumbleToggle() {
|
void WII::setRumbleToggle() {
|
||||||
HIDBuffer[1] = 0x11;
|
HIDBuffer[1] = 0x11;
|
||||||
HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble
|
HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble
|
||||||
|
rumbleBit ^= rumbleBit;
|
||||||
HID_Command(HIDBuffer, 3);
|
HID_Command(HIDBuffer, 3);
|
||||||
}
|
}
|
||||||
void WII::setLedOff(LED a) {
|
void WII::setLedOff(LED a) {
|
||||||
HIDBuffer[1] = 0x11;
|
HIDBuffer[1] = 0x11;
|
||||||
HIDBuffer[2] &= ~((uint8_t)a);
|
HIDBuffer[2] &= ~((uint8_t)a);
|
||||||
HID_Command(HIDBuffer, 3);
|
HID_Command(HIDBuffer, 3);
|
||||||
}
|
}
|
||||||
void WII::setLedOn(LED a) {
|
void WII::setLedOn(LED a) {
|
||||||
HIDBuffer[1] = 0x11;
|
HIDBuffer[1] = 0x11;
|
||||||
|
@ -413,9 +455,9 @@ void WII::setReportMode(bool continuous, uint8_t mode) {
|
||||||
cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
||||||
cmd_buf[1] = 0x12;
|
cmd_buf[1] = 0x12;
|
||||||
if(continuous)
|
if(continuous)
|
||||||
cmd_buf[2] = 0x04;
|
cmd_buf[2] = 0x04 | rumbleBit;
|
||||||
else
|
else
|
||||||
cmd_buf[2] = 0x00;
|
cmd_buf[2] = 0x00 | rumbleBit;
|
||||||
cmd_buf[3] = mode;
|
cmd_buf[3] = mode;
|
||||||
HID_Command(cmd_buf, 4);
|
HID_Command(cmd_buf, 4);
|
||||||
}
|
}
|
||||||
|
@ -423,22 +465,90 @@ void WII::statusRequest() {
|
||||||
uint8_t cmd_buf[3];
|
uint8_t cmd_buf[3];
|
||||||
cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
||||||
cmd_buf[1] = 0x15;
|
cmd_buf[1] = 0x15;
|
||||||
cmd_buf[2] = 0x00;
|
cmd_buf[2] = rumbleBit;
|
||||||
HID_Command(cmd_buf, 3);
|
HID_Command(cmd_buf, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************/
|
||||||
|
/* Memmory Commands */
|
||||||
|
/************************************************************/
|
||||||
|
void WII::writeData(uint32_t offset, uint8_t size, uint8_t* data) {
|
||||||
|
uint8_t cmd_buf[23];
|
||||||
|
cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
||||||
|
cmd_buf[1] = 0x16; // Write data
|
||||||
|
cmd_buf[2] = 0x04 | rumbleBit; // Write to memory, clear bit 2 to write to EEPROM
|
||||||
|
cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16);
|
||||||
|
cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8);
|
||||||
|
cmd_buf[5] = (uint8_t)(offset & 0xFF);
|
||||||
|
cmd_buf[6] = size;
|
||||||
|
uint8_t i = 0;
|
||||||
|
for(; i < size; i++)
|
||||||
|
cmd_buf[7+i] = data[i];
|
||||||
|
for(; i < 16; i++) // Set the rest to zero
|
||||||
|
cmd_buf[7+i] = 0x00;
|
||||||
|
HID_Command(cmd_buf,23);
|
||||||
|
}
|
||||||
|
void WII::activateExtension1() {
|
||||||
|
uint8_t buf[1];
|
||||||
|
buf[0] = 0x55;
|
||||||
|
writeData(0xA400F0,1,buf);
|
||||||
|
}
|
||||||
|
void WII::activateExtension2() {
|
||||||
|
uint8_t buf[1];
|
||||||
|
buf[0] = 0x00;
|
||||||
|
writeData(0xA400FB,1,buf);
|
||||||
|
}
|
||||||
|
void WII::readData(uint32_t offset, uint16_t size, bool EEPROM) {
|
||||||
|
uint8_t cmd_buf[8];
|
||||||
|
cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
||||||
|
cmd_buf[1] = 0x17; // Read data
|
||||||
|
if(EEPROM)
|
||||||
|
cmd_buf[2] = 0x00 | rumbleBit; // Read from EEPROM
|
||||||
|
else
|
||||||
|
cmd_buf[2] = 0x04 | rumbleBit; // Read from memory
|
||||||
|
cmd_buf[3] = (uint8_t)((offset & 0xFF0000) >> 16);
|
||||||
|
cmd_buf[4] = (uint8_t)((offset & 0xFF00) >> 8);
|
||||||
|
cmd_buf[5] = (uint8_t)(offset & 0xFF);
|
||||||
|
cmd_buf[6] = (uint8_t)((size & 0xFF00) >> 8);
|
||||||
|
cmd_buf[7] = (uint8_t)(size & 0xFF);
|
||||||
|
|
||||||
|
HID_Command(cmd_buf,8);
|
||||||
|
}
|
||||||
|
void WII::readExtensionType() {
|
||||||
|
readData(0xA400FA,6,false);
|
||||||
|
}
|
||||||
|
void WII::readCalData() {
|
||||||
|
readData(0x0016,8,true);
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************/
|
/************************************************************/
|
||||||
/* WII Commands */
|
/* WII Commands */
|
||||||
/************************************************************/
|
/************************************************************/
|
||||||
|
|
||||||
bool WII::getButtonPress(Button b) {
|
bool WII::getButtonPress(Button b) { // Return true when a button is pressed
|
||||||
if(ButtonState & (uint16_t)b)
|
bool press = (ButtonState & (uint32_t)b);
|
||||||
return true;
|
if(b == Z || b == C)
|
||||||
|
return !press; // The nunchuck buttons are cleared when pressed
|
||||||
else
|
else
|
||||||
return false;
|
return press;
|
||||||
}
|
}
|
||||||
bool WII::getButtonClick(Button b) {
|
bool WII::getButtonClick(Button b) { // Only return true when a button is clicked
|
||||||
bool click = ((ButtonClickState & (uint16_t)b) != 0);
|
bool click = (ButtonClickState & (uint32_t)b);
|
||||||
ButtonClickState &= ~((uint16_t)b); // clear "click" event
|
if(b == Z || b == C) {
|
||||||
|
click = !click; // The nunchuck buttons are cleared when pressed
|
||||||
|
ButtonClickState |= (uint32_t)b; // clear "click" event
|
||||||
|
} else
|
||||||
|
ButtonClickState &= ~((uint32_t)b); // clear "click" event
|
||||||
return click;
|
return click;
|
||||||
}
|
}
|
||||||
|
uint8_t WII::getAnalogHat(AnalogHat a) {
|
||||||
|
if(!nunchuckConnected)
|
||||||
|
return 127; // Center position
|
||||||
|
else {
|
||||||
|
uint8_t output = hatValues[(uint8_t)a];
|
||||||
|
if(output == 0xFF) // The joystick will only read 255 when the cable is unplugged, so we will just return the center position
|
||||||
|
return 127;
|
||||||
|
else
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
76
Wii.h
76
Wii.h
|
@ -63,18 +63,25 @@ enum LED {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Button {
|
enum Button {
|
||||||
LEFT = 0x0001,
|
LEFT = 0x00001,
|
||||||
RIGHT = 0x0002,
|
RIGHT = 0x00002,
|
||||||
DOWN = 0x0004,
|
DOWN = 0x00004,
|
||||||
UP = 0x0008,
|
UP = 0x00008,
|
||||||
PLUS = 0x0010,
|
PLUS = 0x00010,
|
||||||
|
|
||||||
TWO = 0x0100,
|
TWO = 0x00100,
|
||||||
ONE = 0x0200,
|
ONE = 0x00200,
|
||||||
B = 0x0400,
|
B = 0x00400,
|
||||||
A = 0x0800,
|
A = 0x00800,
|
||||||
MINUS = 0x1000,
|
MINUS = 0x01000,
|
||||||
HOME = 0x8000,
|
HOME = 0x08000,
|
||||||
|
|
||||||
|
Z = 0x10000,
|
||||||
|
C = 0x20000,
|
||||||
|
};
|
||||||
|
enum AnalogHat {
|
||||||
|
HatX = 0,
|
||||||
|
HatY = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
class WII : public BluetoothService {
|
class WII : public BluetoothService {
|
||||||
|
@ -89,6 +96,7 @@ public:
|
||||||
|
|
||||||
bool getButtonPress(Button b); // This will read true as long as the button is held down
|
bool getButtonPress(Button b); // This will read true as long as the button is held down
|
||||||
bool getButtonClick(Button b); // This will only be true when the button is clicked the first time
|
bool getButtonClick(Button b); // This will only be true when the button is clicked the first time
|
||||||
|
uint8_t getAnalogHat(AnalogHat a); // Used to read the joystick of the Nunchuck
|
||||||
/*
|
/*
|
||||||
TODO: Enable support for Motion Plus
|
TODO: Enable support for Motion Plus
|
||||||
int16_t getSensor(Sensor a);
|
int16_t getSensor(Sensor a);
|
||||||
|
@ -96,6 +104,8 @@ public:
|
||||||
*/
|
*/
|
||||||
double getPitch() { return pitch; };
|
double getPitch() { return pitch; };
|
||||||
double getRoll() { return roll; };
|
double getRoll() { return roll; };
|
||||||
|
double getNunchuckPitch() { return nunchuckPitch; };
|
||||||
|
double getNunchuckRoll() { return nunchuckRoll; };
|
||||||
|
|
||||||
void setAllOff(); // Turn both rumble and all LEDs off
|
void setAllOff(); // Turn both rumble and all LEDs off
|
||||||
void setRumbleOff();
|
void setRumbleOff();
|
||||||
|
@ -104,13 +114,9 @@ public:
|
||||||
void setLedOff(LED a);
|
void setLedOff(LED a);
|
||||||
void setLedOn(LED a);
|
void setLedOn(LED a);
|
||||||
void setLedToggle(LED a);
|
void setLedToggle(LED a);
|
||||||
void setReportMode(bool continuous, uint8_t mode);
|
|
||||||
void statusRequest();
|
|
||||||
|
|
||||||
bool connected;// Variable used to indicate if a Wiimote is connected
|
bool wiimoteConnected; // Variable used to indicate if a Wiimote is connected
|
||||||
bool buttonChanged;//Indicate if a button has been changed
|
bool nunchuckConnected; // Variable used to indicate if a Nunchuck controller is connected
|
||||||
bool buttonPressed;//Indicate if a button has been pressed
|
|
||||||
bool buttonReleased;//Indicate if a button has been released
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Mandatory members */
|
/* Mandatory members */
|
||||||
|
@ -125,23 +131,43 @@ private:
|
||||||
uint8_t l2cap_state;
|
uint8_t l2cap_state;
|
||||||
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
|
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
|
||||||
|
|
||||||
uint16_t ButtonState;
|
uint32_t ButtonState;
|
||||||
uint16_t OldButtonState;
|
uint32_t OldButtonState;
|
||||||
uint16_t ButtonClickState;
|
uint32_t ButtonClickState;
|
||||||
|
uint8_t hatValues[2];
|
||||||
|
|
||||||
uint8_t HIDBuffer[3];// Used to store HID commands
|
uint8_t HIDBuffer[3];// Used to store HID commands
|
||||||
|
|
||||||
/* L2CAP Channels */
|
/* L2CAP Channels */
|
||||||
uint8_t control_scid[2];// L2CAP source CID for HID_Control
|
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
||||||
uint8_t control_dcid[2];//0x0060
|
uint8_t control_dcid[2]; //0x0060
|
||||||
uint8_t interrupt_scid[2];// L2CAP source CID for HID_Interrupt
|
uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt
|
||||||
uint8_t interrupt_dcid[2];//0x0061
|
uint8_t interrupt_dcid[2]; //0x0061
|
||||||
uint8_t identifier;//Identifier for connection
|
uint8_t identifier; //Identifier for connection
|
||||||
|
|
||||||
/* HID Commands */
|
/* HID Commands */
|
||||||
void HID_Command(uint8_t* data, uint8_t nbytes);
|
void HID_Command(uint8_t* data, uint8_t nbytes);
|
||||||
|
void setReportMode(bool continuous, uint8_t mode);
|
||||||
|
void statusRequest();
|
||||||
|
|
||||||
|
void writeData(uint32_t offset, uint8_t size, uint8_t* data);
|
||||||
|
void activateExtension1();
|
||||||
|
void activateExtension2();
|
||||||
|
|
||||||
|
void readData(uint32_t offset, uint16_t size, bool EEPROM);
|
||||||
|
void readExtensionType();
|
||||||
|
void readCalData();
|
||||||
|
|
||||||
|
uint8_t activateState;
|
||||||
|
uint8_t rumbleBit;
|
||||||
|
|
||||||
double pitch;
|
double pitch;
|
||||||
double roll;
|
double roll;
|
||||||
|
double nunchuckPitch;
|
||||||
|
double nunchuckRoll;
|
||||||
|
|
||||||
|
int16_t accX; // Accelerometer values used to calculate pitch and roll
|
||||||
|
int16_t accY;
|
||||||
|
int16_t accZ;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
101
examples/Bluetooth/Wii/Wii.ino
Normal file
101
examples/Bluetooth/Wii/Wii.ino
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
Example sketch for the Wiimote 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>
|
||||||
|
USB Usb;
|
||||||
|
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); // This will start inquiry which will connect to any Wiimote
|
||||||
|
//WII Wii(&Btd,0x00,0x26,0x59,0x48,0xFF,0xFB); // This will connect to the Wiimote with that specific Bluetooth Address
|
||||||
|
|
||||||
|
bool printAngle;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
if (Usb.Init() == -1) {
|
||||||
|
Serial.print(F("\r\nOSC did not start"));
|
||||||
|
while(1); //halt
|
||||||
|
}
|
||||||
|
Serial.print(F("\r\nWiimote Bluetooth Library Started"));
|
||||||
|
}
|
||||||
|
void loop() {
|
||||||
|
Usb.Task();
|
||||||
|
if(Wii.wiimoteConnected) {
|
||||||
|
if(Wii.getButtonClick(HOME)) { // You can use getButtonPress to see if the button is held down
|
||||||
|
Serial.print(F("\r\nHOME"));
|
||||||
|
Wii.disconnect(); // If you disconnect you have to reset the Arduino to establish the connection again
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(Wii.getButtonClick(LEFT)) {
|
||||||
|
Wii.setAllOff();
|
||||||
|
Wii.setLedOn(LED1);
|
||||||
|
Serial.print(F("\r\nLeft"));
|
||||||
|
}
|
||||||
|
if(Wii.getButtonClick(RIGHT)) {
|
||||||
|
Wii.setAllOff();
|
||||||
|
Wii.setLedOn(LED3);
|
||||||
|
Serial.print(F("\r\nRight"));
|
||||||
|
}
|
||||||
|
if(Wii.getButtonClick(DOWN)) {
|
||||||
|
Wii.setAllOff();
|
||||||
|
Wii.setLedOn(LED4);
|
||||||
|
Serial.print(F("\r\nDown"));
|
||||||
|
}
|
||||||
|
if(Wii.getButtonClick(UP)) {
|
||||||
|
Wii.setAllOff();
|
||||||
|
Wii.setLedOn(LED2);
|
||||||
|
Serial.print(F("\r\nUp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Wii.getButtonClick(PLUS)) {
|
||||||
|
Serial.print(F("\r\nPlus"));
|
||||||
|
}
|
||||||
|
if(Wii.getButtonClick(MINUS)) {
|
||||||
|
Serial.print(F("\r\nMinus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Wii.getButtonClick(ONE)) {
|
||||||
|
Serial.print(F("\r\nOne"));
|
||||||
|
}
|
||||||
|
if(Wii.getButtonClick(TWO)) {
|
||||||
|
Serial.print(F("\r\nTwo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Wii.getButtonClick(A)) {
|
||||||
|
printAngle = !printAngle;
|
||||||
|
Serial.print(F("\r\nA"));
|
||||||
|
}
|
||||||
|
if(Wii.getButtonClick(B)) {
|
||||||
|
Wii.setRumbleToggle();
|
||||||
|
Serial.print(F("\r\nB"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(printAngle) {
|
||||||
|
Serial.print(F("\r\nPitch: "));
|
||||||
|
Serial.print(Wii.getPitch());
|
||||||
|
Serial.print(F("\tRoll: "));
|
||||||
|
Serial.print(Wii.getRoll());
|
||||||
|
if(Wii.nunchuckConnected) {
|
||||||
|
Serial.print(F("\tNunchuck Pitch: "));
|
||||||
|
Serial.print(Wii.getNunchuckPitch());
|
||||||
|
Serial.print(F("\tNunchuck Roll: "));
|
||||||
|
Serial.print(Wii.getNunchuckRoll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(Wii.nunchuckConnected) {
|
||||||
|
if(Wii.getButtonClick(Z))
|
||||||
|
Serial.print(F("\r\nZ"));
|
||||||
|
if(Wii.getButtonClick(C))
|
||||||
|
Serial.print(F("\r\nC"));
|
||||||
|
if(Wii.getAnalogHat(HatX) > 137 || Wii.getAnalogHat(HatX) < 117 || Wii.getAnalogHat(HatY) > 137 || Wii.getAnalogHat(HatY) < 117) {
|
||||||
|
Serial.print(F("\r\nHatX: "));
|
||||||
|
Serial.print(Wii.getAnalogHat(HatX));
|
||||||
|
Serial.print(F("\tHatY: "));
|
||||||
|
Serial.print(Wii.getAnalogHat(HatY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
Example sketch for the Wiimote 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>
|
|
||||||
USB Usb;
|
|
||||||
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); // This will start inquiry which will connect to any Wiimote
|
|
||||||
//WII Wii(&Btd,0x00,0x26,0x59,0x48,0xFF,0xFB); // This will connect to the Wiimote with that specific Bluetooth Address
|
|
||||||
|
|
||||||
bool printAngle;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
if (Usb.Init() == -1) {
|
|
||||||
Serial.print(F("\r\nOSC did not start"));
|
|
||||||
while(1); //halt
|
|
||||||
}
|
|
||||||
Serial.print(F("\r\nWiimote Bluetooth Library Started"));
|
|
||||||
}
|
|
||||||
void loop() {
|
|
||||||
Usb.Task();
|
|
||||||
if(Wii.connected) {
|
|
||||||
if(Wii.buttonPressed) {
|
|
||||||
if(Wii.getButtonClick(HOME)) { // You can use getButtonPress to see if the button is held down
|
|
||||||
Serial.print(F("\r\nHOME"));
|
|
||||||
Wii.disconnect(); // If you disconnect you have to reset the Arduino to establish the connection again
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(Wii.getButtonClick(LEFT)) {
|
|
||||||
Wii.setAllOff();
|
|
||||||
Wii.setLedOn(LED1);
|
|
||||||
Serial.print(F("\r\nLeft"));
|
|
||||||
}
|
|
||||||
if(Wii.getButtonClick(RIGHT)) {
|
|
||||||
Wii.setAllOff();
|
|
||||||
Wii.setLedOn(LED3);
|
|
||||||
Serial.print(F("\r\nRight"));
|
|
||||||
}
|
|
||||||
if(Wii.getButtonClick(DOWN)) {
|
|
||||||
Wii.setAllOff();
|
|
||||||
Wii.setLedOn(LED4);
|
|
||||||
Serial.print(F("\r\nDown"));
|
|
||||||
}
|
|
||||||
if(Wii.getButtonClick(UP)) {
|
|
||||||
Wii.setAllOff();
|
|
||||||
Wii.setLedOn(LED2);
|
|
||||||
Serial.print(F("\r\nUp"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Wii.getButtonClick(PLUS)) {
|
|
||||||
Serial.print(F("\r\nPlus"));
|
|
||||||
}
|
|
||||||
if(Wii.getButtonClick(MINUS)) {
|
|
||||||
Serial.print(F("\r\nMinus"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Wii.getButtonClick(ONE)) {
|
|
||||||
Serial.print(F("\r\nOne"));
|
|
||||||
}
|
|
||||||
if(Wii.getButtonClick(TWO)) {
|
|
||||||
Serial.print(F("\r\nTwo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Wii.getButtonClick(A)) {
|
|
||||||
printAngle = !printAngle;
|
|
||||||
Serial.print(F("\r\nA"));
|
|
||||||
}
|
|
||||||
if(Wii.getButtonClick(B)) {
|
|
||||||
Wii.setRumbleToggle();
|
|
||||||
Serial.print(F("\r\nB"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(printAngle) {
|
|
||||||
Serial.print(F("\r\nPitch: "));
|
|
||||||
Serial.print(Wii.getPitch());
|
|
||||||
Serial.print(F("\tRoll: "));
|
|
||||||
Serial.print(Wii.getRoll());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -217,8 +217,12 @@ WII KEYWORD1
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
|
wiimoteConnected KEYWORD2
|
||||||
|
nunchuckConnected KEYWORD2
|
||||||
getButtonPress KEYWORD2
|
getButtonPress KEYWORD2
|
||||||
getButtonClick KEYWORD2
|
getButtonClick KEYWORD2
|
||||||
setRumbleToggle KEYWORD2
|
setRumbleToggle KEYWORD2
|
||||||
|
getNunchuckPitch KEYWORD2
|
||||||
|
getNunchuckRoll KEYWORD2
|
||||||
getPitch KEYWORD2
|
getPitch KEYWORD2
|
||||||
getRoll KEYWORD2
|
getRoll KEYWORD2
|
Loading…
Reference in a new issue