2012-08-21 14:31:11 +02:00
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 ( GPL2 ) as published by the Free Software
Foundation and appearing in the file GPL2 . TXT included in the packaging of
this file . Please note that GPL2 Section 2 [ b ] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ( " Copyleft " ) .
Contact information
- - - - - - - - - - - - - - - - - - -
Kristian Lauszus , TKJ Electronics
Web : http : //www.tkjelectronics.com
e - mail : kristianl @ tkjelectronics . com
2013-01-17 00:07:56 +01:00
IR camera support added by :
Allan Glover
adglover9 .81 @ gmail . com
2012-08-21 14:31:11 +02:00
*/
# include "Wii.h"
# define DEBUG // Uncomment to print data for debugging
//#define EXTRADEBUG // Uncomment to get even more debugging data
2012-08-22 23:41:38 +02:00
//#define PRINTREPORT // Uncomment to print the report send by the Wii controllers
2012-08-21 14:31:11 +02:00
2013-01-27 21:25:50 +01:00
const uint8_t LEDS [ ] PROGMEM = {
0x10 , // LED1
0x20 , // LED2
0x40 , // LED3
0x80 , // LED4
0x90 , // LED5
0xA0 , // LED6
0xC0 , // LED7
0xD0 , // LED8
0xE0 , // LED9
0xF0 // LED10
} ;
const uint32_t BUTTONS [ ] PROGMEM = {
0x00008 , // UP
0x00002 , // RIGHT
0x00004 , // DOWN
0x00001 , // LEFT
2013-01-28 00:55:01 +01:00
0 , // Skip
2013-01-27 21:25:50 +01:00
0x00010 , // PLUS
0x00100 , // TWO
0x00200 , // ONE
2013-01-28 00:55:01 +01:00
2013-01-27 21:25:50 +01:00
0x01000 , // MINUS
0x08000 , // HOME
0x10000 , // Z
2013-01-28 00:55:01 +01:00
0x20000 , // C
0x00400 , // B
0x00800 // A
2013-01-27 21:25:50 +01:00
} ;
2012-10-07 14:50:51 +02:00
WII : : WII ( BTD * p , bool pair ) :
2012-08-21 14:31:11 +02:00
pBtd ( p ) // pointer to USB class instance - mandatory
{
if ( pBtd )
2013-01-20 22:46:04 +01:00
pBtd - > registerServiceClass ( this ) ; // Register it as a Bluetooth service
2012-08-21 14:31:11 +02:00
2012-10-07 14:50:51 +02:00
pBtd - > pairWithWii = pair ;
2012-08-21 14:31:11 +02:00
2012-10-07 20:34:52 +02:00
HIDBuffer [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2012-08-21 14:31:11 +02:00
/* Set device cid for the control and intterrupt channelse - LSB */
control_dcid [ 0 ] = 0x60 ; //0x0060
control_dcid [ 1 ] = 0x00 ;
interrupt_dcid [ 0 ] = 0x61 ; //0x0061
interrupt_dcid [ 1 ] = 0x00 ;
Reset ( ) ;
}
void WII : : Reset ( ) {
2012-08-22 23:41:38 +02:00
wiimoteConnected = false ;
nunchuckConnected = false ;
2012-08-23 23:10:12 +02:00
motionPlusConnected = false ;
2012-10-07 14:50:51 +02:00
activateNunchuck = false ;
2012-10-07 19:12:26 +02:00
motionValuesReset = false ;
2013-01-20 22:46:04 +01:00
activeConnection = false ;
2013-01-28 00:55:01 +01:00
pBtd - > motionPlusInside = false ;
2012-08-21 14:31:11 +02:00
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_WAIT ;
}
void WII : : disconnect ( ) { // Use this void to disconnect any of the controllers
//First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection
pBtd - > l2cap_disconnection_request ( hci_handle , 0x0A , interrupt_scid , interrupt_dcid ) ;
Reset ( ) ;
l2cap_state = L2CAP_INTERRUPT_DISCONNECT ;
}
void WII : : ACLData ( uint8_t * l2capinbuf ) {
2013-01-31 21:58:13 +01:00
if ( ! pBtd - > l2capConnectionClaimed & & pBtd - > incomingWii & & ! wiimoteConnected & & ! activeConnection ) {
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_CTRL_PSM ) {
pBtd - > incomingWii = false ;
pBtd - > l2capConnectionClaimed = true ; // Claim that the incoming connection belongs to this service
activeConnection = true ;
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
l2cap_state = L2CAP_WAIT ;
}
}
}
if ( ( l2capinbuf [ 0 ] | ( l2capinbuf [ 1 ] < < 8 ) ) = = ( hci_handle | 0x2000 ) ) { // acl_handle_ok or it's a new connection
2012-08-21 14:31:11 +02:00
if ( ( l2capinbuf [ 6 ] | ( l2capinbuf [ 7 ] < < 8 ) ) = = 0x0001 ) { //l2cap_control - Channel ID for ACL-U
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_COMMAND_REJECT ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n L2CAP Command Rejected - Reason: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 13 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 12 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 17 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 16 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 15 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 14 ] ) ;
# endif
2012-10-07 19:12:26 +02:00
}
2012-08-21 14:31:11 +02:00
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_RESPONSE ) {
if ( ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) & & ( ( l2capinbuf [ 18 ] | ( l2capinbuf [ 19 ] < < 8 ) ) = = SUCCESSFUL ) ) { // Success
if ( l2capinbuf [ 14 ] = = control_dcid [ 0 ] & & l2capinbuf [ 15 ] = = control_dcid [ 1 ] ) { // Success
//Serial.print("\r\nHID Control Connection Complete");
identifier = l2capinbuf [ 9 ] ;
control_scid [ 0 ] = l2capinbuf [ 12 ] ;
control_scid [ 1 ] = l2capinbuf [ 13 ] ;
l2cap_event_flag | = L2CAP_FLAG_CONTROL_CONNECTED ;
}
else if ( l2capinbuf [ 14 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 15 ] = = interrupt_dcid [ 1 ] ) {
//Serial.print("\r\nHID Interrupt Connection Complete");
identifier = l2capinbuf [ 9 ] ;
interrupt_scid [ 0 ] = l2capinbuf [ 12 ] ;
interrupt_scid [ 1 ] = l2capinbuf [ 13 ] ;
l2cap_event_flag | = L2CAP_FLAG_INTERRUPT_CONNECTED ;
}
}
2012-10-07 14:50:51 +02:00
}
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n L2CAP Connection Request - PSM: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 13 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 12 ] ) ;
Notify ( PSTR ( " SCID: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 15 ] ) ;
Notify ( PSTR ( " " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 14 ] ) ;
Notify ( PSTR ( " Identifier: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 9 ] ) ;
# endif
if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_CTRL_PSM ) {
identifier = l2capinbuf [ 9 ] ;
control_scid [ 0 ] = l2capinbuf [ 14 ] ;
control_scid [ 1 ] = l2capinbuf [ 15 ] ;
l2cap_event_flag | = L2CAP_FLAG_CONNECTION_CONTROL_REQUEST ;
}
else if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_INTR_PSM ) {
identifier = l2capinbuf [ 9 ] ;
interrupt_scid [ 0 ] = l2capinbuf [ 14 ] ;
interrupt_scid [ 1 ] = l2capinbuf [ 15 ] ;
l2cap_event_flag | = L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST ;
}
2012-08-21 14:31:11 +02:00
}
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_RESPONSE ) {
if ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) { // Success
if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
//Serial.print("\r\nHID Control Configuration Complete");
identifier = l2capinbuf [ 9 ] ;
l2cap_event_flag | = L2CAP_FLAG_CONFIG_CONTROL_SUCCESS ;
}
else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
//Serial.print("\r\nHID Interrupt Configuration Complete");
identifier = l2capinbuf [ 9 ] ;
l2cap_event_flag | = L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS ;
}
}
}
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_REQUEST ) {
if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
//Serial.print("\r\nHID Control Configuration Request");
pBtd - > l2cap_config_response ( hci_handle , l2capinbuf [ 9 ] , control_scid ) ;
}
else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
//Serial.print("\r\nHID Interrupt Configuration Request");
pBtd - > l2cap_config_response ( hci_handle , l2capinbuf [ 9 ] , interrupt_scid ) ;
}
}
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_REQUEST ) {
if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Disconnect Request: Control Channel " ) ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , control_dcid , control_scid ) ;
Reset ( ) ;
}
else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Disconnect Request: Interrupt Channel " ) ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid ) ;
Reset ( ) ;
}
}
else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_RESPONSE ) {
if ( l2capinbuf [ 12 ] = = control_scid [ 0 ] & & l2capinbuf [ 13 ] = = control_scid [ 1 ] ) {
//Serial.print("\r\nDisconnect Response: Control Channel");
identifier = l2capinbuf [ 9 ] ;
l2cap_event_flag | = L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE ;
}
else if ( l2capinbuf [ 12 ] = = interrupt_scid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_scid [ 1 ] ) {
//Serial.print("\r\nDisconnect Response: Interrupt Channel");
identifier = l2capinbuf [ 9 ] ;
l2cap_event_flag | = L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE ;
}
}
# ifdef EXTRADEBUG
else {
identifier = l2capinbuf [ 9 ] ;
Notify ( PSTR ( " \r \n L2CAP Unknown Signaling Command: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 8 ] ) ;
}
# endif
} else if ( l2capinbuf [ 6 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 7 ] = = interrupt_dcid [ 1 ] ) { // l2cap_interrupt
//Serial.print("\r\nL2CAP Interrupt");
2012-08-22 23:41:38 +02:00
if ( wiimoteConnected ) {
2012-08-21 14:31:11 +02:00
if ( l2capinbuf [ 8 ] = = 0xA1 ) { // HID_THDR_DATA_INPUT
2013-01-23 22:28:40 +01:00
if ( ( l2capinbuf [ 9 ] > = 0x20 & & l2capinbuf [ 9 ] < = 0x22 ) | | ( l2capinbuf [ 9 ] > = 0x30 & & l2capinbuf [ 9 ] < = 0x37 ) | | l2capinbuf [ 9 ] = = 0x3e | | l2capinbuf [ 9 ] = = 0x3f ) { // These reports include the buttons
if ( ( l2capinbuf [ 9 ] > = 0x20 & & l2capinbuf [ 9 ] < = 0x22 ) | | l2capinbuf [ 9 ] = = 0x31 | | l2capinbuf [ 9 ] = = 0x33 ) // These reports have no extensions bytes
ButtonState = ( uint32_t ) ( ( l2capinbuf [ 10 ] & 0x1F ) | ( ( uint16_t ) ( l2capinbuf [ 11 ] & 0x9F ) < < 8 ) ) ;
else if ( motionPlusConnected ) {
2012-08-23 23:10:12 +02:00
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 ) ) ) ;
else if ( nunchuckConnected ) // Update if it's a report from the Nunchuck
2012-10-02 01:43:00 +02:00
ButtonState = ( uint32_t ) ( ( l2capinbuf [ 10 ] & 0x1F ) | ( ( uint16_t ) ( l2capinbuf [ 11 ] & 0x9F ) < < 8 ) | ( ( uint32_t ) ( ( ~ l2capinbuf [ 20 ] ) & 0x0C ) < < 14 ) ) ;
2013-01-23 22:28:40 +01:00
//else if(classicControllerConnected) // Update if it's a report from the Classic Controller
2012-08-23 23:10:12 +02:00
}
else if ( nunchuckConnected ) // The Nunchuck is directly connected
2012-10-02 01:43:00 +02:00
ButtonState = ( uint32_t ) ( ( l2capinbuf [ 10 ] & 0x1F ) | ( ( uint16_t ) ( l2capinbuf [ 11 ] & 0x9F ) < < 8 ) | ( ( uint32_t ) ( ( ~ l2capinbuf [ 20 ] ) & 0x03 ) < < 16 ) ) ;
2012-08-23 23:10:12 +02:00
//else if(classicControllerConnected) // The Classic Controller is directly connected
else if ( ! unknownExtensionConnected )
2012-08-22 23:41:38 +02:00
ButtonState = ( uint32_t ) ( ( l2capinbuf [ 10 ] & 0x1F ) | ( ( uint16_t ) ( l2capinbuf [ 11 ] & 0x9F ) < < 8 ) ) ;
2012-08-21 17:36:37 +02:00
# ifdef PRINTREPORT
Notify ( PSTR ( " ButtonState: " ) ) ;
2012-08-22 23:41:38 +02:00
PrintHex < uint32_t > ( ButtonState ) ;
2012-08-21 17:36:37 +02:00
Notify ( PSTR ( " \r \n " ) ) ;
# endif
2012-10-02 01:43:00 +02:00
if ( ButtonState ! = OldButtonState ) {
ButtonClickState = ButtonState & ~ OldButtonState ; // Update click state variable
OldButtonState = ButtonState ;
}
2012-08-21 17:36:37 +02:00
}
2013-01-23 22:28:40 +01:00
if ( l2capinbuf [ 9 ] = = 0x31 | | l2capinbuf [ 9 ] = = 0x33 | | l2capinbuf [ 9 ] = = 0x35 | | l2capinbuf [ 9 ] = = 0x37 ) { // Read the accelerometer
2012-08-22 23:41:38 +02:00
accX = ( ( l2capinbuf [ 12 ] < < 2 ) | ( l2capinbuf [ 10 ] & 0x60 > > 5 ) ) - 500 ;
accY = ( ( l2capinbuf [ 13 ] < < 2 ) | ( l2capinbuf [ 11 ] & 0x20 > > 4 ) ) - 500 ;
2012-08-23 23:10:12 +02:00
accZ = ( ( l2capinbuf [ 14 ] < < 2 ) | ( l2capinbuf [ 11 ] & 0x40 > > 5 ) ) - 500 ;
wiiMotePitch = ( atan2 ( accY , accZ ) + PI ) * RAD_TO_DEG ;
wiiMoteRoll = ( atan2 ( accX , accZ ) + PI ) * RAD_TO_DEG ;
2012-08-21 17:36:37 +02:00
}
2012-08-21 14:31:11 +02:00
switch ( l2capinbuf [ 9 ] ) {
2013-01-23 22:28:40 +01:00
case 0x20 : // Status Information - (a1) 20 BB BB LF 00 00 VV
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
if ( l2capinbuf [ 12 ] & 0x01 ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n WARNING: Battery is nearly empty " ) ) ;
# endif
}
2012-08-22 23:41:38 +02:00
if ( l2capinbuf [ 12 ] & 0x02 ) { // Check if a extension is connected
# ifdef DEBUG
2012-08-23 23:10:12 +02:00
if ( ! unknownExtensionConnected )
Notify ( PSTR ( " \r \n Extension connected " ) ) ;
2012-08-22 23:41:38 +02:00
# endif
2012-08-23 23:10:12 +02:00
unknownExtensionConnected = true ;
2013-01-24 00:23:09 +01:00
# ifdef WIICAMERA
if ( ! isIRCameraEnabled ( ) ) // Don't activate the Motion Plus if we are trying to initialize the IR camera
# endif
setReportMode ( false , 0x35 ) ; // Also read the extension
2012-08-22 23:41:38 +02:00
}
else {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Extension disconnected " ) ) ;
# endif
2012-08-23 23:10:12 +02:00
if ( motionPlusConnected ) {
# ifdef DEBUG
Notify ( PSTR ( " - from Motion Plus " ) ) ;
# endif
l2cap_event_flag & = ~ WII_FLAG_NUNCHUCK_CONNECTED ;
if ( ! activateNunchuck ) // If it's already trying to initialize the Nunchuck don't set it to false
nunchuckConnected = false ;
//else if(classicControllerConnected)
}
else if ( nunchuckConnected ) {
# ifdef DEBUG
Notify ( PSTR ( " - Nunchuck " ) ) ;
# endif
nunchuckConnected = false ; // It must be the Nunchuck controller then
l2cap_event_flag & = ~ WII_FLAG_NUNCHUCK_CONNECTED ;
2012-10-06 16:42:00 +02:00
setLedStatus ( ) ;
2012-08-23 23:10:12 +02:00
setReportMode ( false , 0x31 ) ; // If there is no extension connected we will read the button and accelerometer
} else {
setReportMode ( false , 0x31 ) ; // If there is no extension connected we will read the button and accelerometer
}
2012-08-22 23:41:38 +02:00
}
break ;
case 0x21 : // Read Memory Data
if ( ( l2capinbuf [ 12 ] & 0x0F ) = = 0 ) { // No error
2012-08-23 23:10:12 +02:00
// See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
2013-01-10 20:10:16 +01:00
if ( l2capinbuf [ 16 ] = = 0x00 & & l2capinbuf [ 17 ] = = 0xA4 & & l2capinbuf [ 18 ] = = 0x20 & & l2capinbuf [ 19 ] = = 0x00 & & l2capinbuf [ 20 ] = = 0x00 ) {
2012-08-23 23:10:12 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Nunchuck connected " ) ) ;
# endif
l2cap_event_flag | = WII_FLAG_NUNCHUCK_CONNECTED ;
2013-01-10 20:10:16 +01:00
} else if ( l2capinbuf [ 16 ] = = 0x00 & & ( l2capinbuf [ 17 ] = = 0xA6 | | l2capinbuf [ 17 ] = = 0xA4 ) & & l2capinbuf [ 18 ] = = 0x20 & & l2capinbuf [ 19 ] = = 0x00 & & l2capinbuf [ 20 ] = = 0x05 ) {
2012-08-23 23:10:12 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Motion Plus connected " ) ) ;
# endif
l2cap_event_flag | = WII_FLAG_MOTION_PLUS_CONNECTED ;
2013-01-10 20:10:16 +01:00
} else if ( l2capinbuf [ 16 ] = = 0x00 & & l2capinbuf [ 17 ] = = 0xA4 & & l2capinbuf [ 18 ] = = 0x20 & & l2capinbuf [ 19 ] = = 0x04 & & l2capinbuf [ 20 ] = = 0x05 ) {
2012-08-23 23:10:12 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Motion Plus activated in normal mode " ) ) ;
2012-08-22 23:41:38 +02:00
# endif
2012-08-23 23:10:12 +02:00
motionPlusConnected = true ;
2013-01-10 20:10:16 +01:00
} else if ( l2capinbuf [ 16 ] = = 0x00 & & l2capinbuf [ 17 ] = = 0xA4 & & l2capinbuf [ 18 ] = = 0x20 & & l2capinbuf [ 19 ] = = 0x05 & & l2capinbuf [ 20 ] = = 0x05 ) {
2012-08-22 23:41:38 +02:00
# ifdef DEBUG
2012-08-23 23:10:12 +02:00
Notify ( PSTR ( " \r \n Motion Plus activated in Nunchuck pass-through mode " ) ) ;
2012-08-22 23:41:38 +02:00
# endif
2012-08-23 23:10:12 +02:00
activateNunchuck = false ;
motionPlusConnected = true ;
2012-08-22 23:41:38 +02:00
nunchuckConnected = true ;
2013-01-10 20:10:16 +01:00
} 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 ) {
2012-10-07 20:07:48 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Inactive Wii Motion Plus " ) ) ;
Notify ( PSTR ( " \r \n Please unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension " ) ) ;
# endif
stateCounter = 300 ; // Skip the rest in "L2CAP_CHECK_MOTION_PLUS_STATE"
2012-08-22 23:41:38 +02:00
}
# ifdef DEBUG
2012-08-23 23:10:12 +02:00
else {
Notify ( PSTR ( " \r \n Unknown Device: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 13 ] ) ;
PrintHex < uint8_t > ( l2capinbuf [ 14 ] ) ;
Notify ( PSTR ( " \r \n Data: " ) ) ;
for ( uint8_t i = 0 ; i < ( ( l2capinbuf [ 12 ] > > 4 ) + 1 ) ; i + + ) { // bit 4-7 is the length-1
PrintHex < uint8_t > ( l2capinbuf [ 15 + i ] ) ;
Notify ( PSTR ( " " ) ) ;
}
}
# endif
}
# ifdef EXTRADEBUG
2012-08-22 23:41:38 +02:00
else {
Notify ( PSTR ( " \r \n Report Error: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 13 ] ) ;
PrintHex < uint8_t > ( l2capinbuf [ 14 ] ) ;
}
2012-08-23 23:10:12 +02:00
# endif
2012-08-22 23:41:38 +02:00
break ;
case 0x22 : // Acknowledge output report, return function result
# ifdef DEBUG
if ( l2capinbuf [ 13 ] ! = 0x00 ) { // Check if there is an error
Notify ( PSTR ( " \r \n Command failed: " ) ) ;
PrintHex < uint8_t > ( l2capinbuf [ 12 ] ) ;
2012-08-23 23:10:12 +02:00
}
2012-08-22 23:41:38 +02:00
# endif
2012-08-21 17:36:37 +02:00
break ;
2012-08-23 23:10:12 +02:00
case 0x30 : // Core buttons - (a1) 30 BB BB
2012-09-10 00:23:35 +02:00
break ;
2012-08-23 23:10:12 +02:00
case 0x31 : // Core Buttons and Accelerometer - (a1) 31 BB BB AA AA AA
pitch = wiiMotePitch ; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected
roll = wiiMoteRoll ;
2012-08-21 17:36:37 +02:00
break ;
2012-08-23 23:10:12 +02:00
case 0x32 : // Core Buttons with 8 Extension bytes - (a1) 32 BB BB EE EE EE EE EE EE EE EE
2013-01-23 22:28:40 +01:00
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
pitch = wiiMotePitch ; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus data available
roll = wiiMoteRoll ;
2013-01-17 00:07:56 +01:00
# ifdef WIICAMERA
// Read the IR data
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_s1 = ( l2capinbuf [ 17 ] & 0x0F ) ; // size value, 0-15
IR_object_x2 = ( l2capinbuf [ 18 ] | ( ( uint16_t ) ( l2capinbuf [ 20 ] & 0x30 ) < < 4 ) ) ;
IR_object_y2 = ( l2capinbuf [ 19 ] | ( ( uint16_t ) ( l2capinbuf [ 20 ] & 0xC0 ) < < 2 ) ) ;
IR_object_s2 = ( l2capinbuf [ 20 ] & 0x0F ) ;
2013-01-23 22:28:40 +01:00
IR_object_x3 = ( l2capinbuf [ 21 ] | ( ( uint16_t ) ( l2capinbuf [ 23 ] & 0x30 ) < < 4 ) ) ;
IR_object_y3 = ( l2capinbuf [ 22 ] | ( ( uint16_t ) ( l2capinbuf [ 23 ] & 0xC0 ) < < 2 ) ) ;
IR_object_s3 = ( l2capinbuf [ 23 ] & 0x0F ) ;
IR_object_x4 = ( l2capinbuf [ 24 ] | ( ( uint16_t ) ( l2capinbuf [ 26 ] & 0x30 ) < < 4 ) ) ;
IR_object_y4 = ( l2capinbuf [ 25 ] | ( ( uint16_t ) ( l2capinbuf [ 26 ] & 0xC0 ) < < 2 ) ) ;
IR_object_s4 = ( l2capinbuf [ 26 ] & 0x0F ) ;
2013-01-17 00:07:56 +01:00
# endif
break ;
2012-08-23 23:10:12 +02:00
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
2012-08-21 17:36:37 +02:00
break ;
2013-01-17 00:07:56 +01:00
/* 0x3e and 0x3f both give unknown report types when report mode is 0x3e or 0x3f with mode number 0x05 */
case 0x3E : // Core Buttons with Accelerometer and 32 IR bytes
// (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
// corresponds to output report mode 0x3e
/**** for reading in full mode: DOES NOT WORK YET ****/
/* When it works it will also have intensity and bounding box data */
/*
IR_object_x1 = ( l2capinbuf [ 13 ] | ( ( uint16_t ) ( l2capinbuf [ 15 ] & 0x30 ) < < 4 ) ) ;
IR_object_y1 = ( l2capinbuf [ 14 ] | ( ( uint16_t ) ( l2capinbuf [ 15 ] & 0xC0 ) < < 2 ) ) ;
IR_object_s1 = ( l2capinbuf [ 15 ] & 0x0F ) ;
*/
break ;
case 0x3F :
/*
IR_object_x1 = ( l2capinbuf [ 13 ] | ( ( uint16_t ) ( l2capinbuf [ 15 ] & 0x30 ) < < 4 ) ) ;
IR_object_y1 = ( l2capinbuf [ 14 ] | ( ( uint16_t ) ( l2capinbuf [ 15 ] & 0xC0 ) < < 2 ) ) ;
IR_object_s1 = ( l2capinbuf [ 15 ] & 0x0F ) ;
*/
break ;
2012-08-21 17:36:37 +02:00
case 0x35 : // Core Buttons and Accelerometer with 16 Extension Bytes
2012-08-23 23:10:12 +02:00
// (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
if ( motionPlusConnected ) {
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
gyroYawRaw = ( ( l2capinbuf [ 15 ] | ( ( l2capinbuf [ 18 ] & 0xFC ) < < 6 ) ) - gyroYawZero ) ;
gyroRollRaw = ( ( l2capinbuf [ 16 ] | ( ( l2capinbuf [ 19 ] & 0xFC ) < < 6 ) ) - gyroRollZero ) ;
gyroPitchRaw = ( ( l2capinbuf [ 17 ] | ( ( l2capinbuf [ 20 ] & 0xFC ) < < 6 ) ) - gyroPitchZero ) ;
2012-08-22 23:41:38 +02:00
2012-08-23 23:10:12 +02:00
yawGyroSpeed = ( double ) gyroYawRaw / ( ( double ) gyroYawZero / yawGyroScale ) ;
rollGyroSpeed = - ( double ) gyroRollRaw / ( ( double ) gyroRollZero / rollGyroScale ) ; // We invert these values so they will fit the acc values
pitchGyroSpeed = ( double ) gyroPitchRaw / ( ( double ) gyroPitchZero / pitchGyroScale ) ;
/* The onboard gyro has two ranges for slow and fast mode */
if ( ! ( l2capinbuf [ 18 ] & 0x02 ) ) // Check if fast more is used
yawGyroSpeed * = 4.545 ;
if ( ! ( l2capinbuf [ 18 ] & 0x01 ) ) // Check if fast more is used
pitchGyroSpeed * = 4.545 ;
if ( ! ( l2capinbuf [ 19 ] & 0x02 ) ) // Check if fast more is used
rollGyroSpeed * = 4.545 ;
pitch = ( 0.93 * ( pitch + ( pitchGyroSpeed * ( double ) ( micros ( ) - timer ) / 1000000 ) ) ) + ( 0.07 * wiiMotePitch ) ; // Use a complimentary filter to calculate the angle
roll = ( 0.93 * ( roll + ( rollGyroSpeed * ( double ) ( micros ( ) - timer ) / 1000000 ) ) ) + ( 0.07 * wiiMoteRoll ) ;
gyroYaw + = ( yawGyroSpeed * ( ( double ) ( micros ( ) - timer ) / 1000000 ) ) ;
gyroRoll + = ( rollGyroSpeed * ( ( double ) ( micros ( ) - timer ) / 1000000 ) ) ;
gyroPitch + = ( pitchGyroSpeed * ( ( double ) ( micros ( ) - timer ) / 1000000 ) ) ;
timer = micros ( ) ;
/*
// Uncomment these lines to tune the gyro scale variabels
Serial . print ( " \r \n gyroYaw: " ) ;
Serial . print ( gyroYaw ) ;
Serial . print ( " \t gyroRoll: " ) ;
Serial . print ( gyroRoll ) ;
Serial . print ( " \t gyroPitch: " ) ;
Serial . print ( gyroPitch ) ;
*/
/*
Serial . print ( " \t wiiMoteRoll: " ) ;
Serial . print ( wiiMoteRoll ) ;
Serial . print ( " \t wiiMotePitch: " ) ;
Serial . print ( wiiMotePitch ) ;
*/
} else {
if ( ( micros ( ) - timer ) > 1000000 ) { // Loop for 1 sec before resetting the values
# ifdef DEBUG
Notify ( PSTR ( " \r \n The gyro values has been reset " ) ) ;
# endif
gyroYawZero = ( l2capinbuf [ 15 ] | ( ( l2capinbuf [ 18 ] & 0xFC ) < < 6 ) ) ;
gyroRollZero = ( l2capinbuf [ 16 ] | ( ( l2capinbuf [ 19 ] & 0xFC ) < < 6 ) ) ;
gyroPitchZero = ( l2capinbuf [ 17 ] | ( ( l2capinbuf [ 20 ] & 0xFC ) < < 6 ) ) ;
rollGyroScale = 500 ; // You might need to adjust these
pitchGyroScale = 400 ;
yawGyroScale = 415 ;
2013-01-31 21:58:13 +01:00
gyroYaw = 0 ;
gyroRoll = 0 ;
gyroPitch = 0 ;
2012-08-23 23:10:12 +02:00
motionValuesReset = true ;
timer = micros ( ) ;
}
}
} else {
if ( nunchuckConnected ) {
hatValues [ 0 ] = l2capinbuf [ 15 ] ;
hatValues [ 1 ] = l2capinbuf [ 16 ] ;
accX = ( ( l2capinbuf [ 17 ] < < 2 ) | ( l2capinbuf [ 20 ] & 0x10 > > 3 ) ) - 416 ;
accY = ( ( l2capinbuf [ 18 ] < < 2 ) | ( l2capinbuf [ 20 ] & 0x20 > > 4 ) ) - 416 ;
accZ = ( ( ( l2capinbuf [ 19 ] & 0xFE ) < < 2 ) | ( l2capinbuf [ 20 ] & 0xC0 > > 5 ) ) - 416 ;
nunchuckPitch = ( atan2 ( accY , accZ ) + PI ) * RAD_TO_DEG ;
nunchuckRoll = ( atan2 ( accX , accZ ) + PI ) * RAD_TO_DEG ;
}
//else if(classicControllerConnected) { }
}
if ( l2capinbuf [ 19 ] & 0x01 ) {
if ( ! extensionConnected ) {
extensionConnected = true ;
unknownExtensionConnected = true ;
2012-08-24 00:59:43 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Extension connected to Motion Plus " ) ) ;
# endif
2012-08-23 23:10:12 +02:00
}
}
else {
if ( extensionConnected & & ! unknownExtensionConnected ) {
extensionConnected = false ;
unknownExtensionConnected = true ;
2012-08-24 00:59:43 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Extension disconnected from Motion Plus " ) ) ;
# endif
2012-08-23 23:10:12 +02:00
nunchuckConnected = false ; // There is no extension connected to the Motion Plus if this report is sent
}
}
} else if ( nunchuckConnected ) {
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 ;
nunchuckPitch = ( atan2 ( accY , accZ ) + PI ) * RAD_TO_DEG ;
nunchuckRoll = ( atan2 ( accX , accZ ) + PI ) * RAD_TO_DEG ;
pitch = wiiMotePitch ; // The pitch is just equal to the angle calculated from the wiimote as there is no Motion Plus connected
roll = wiiMoteRoll ;
}
2012-08-21 14:31:11 +02:00
break ;
# ifdef DEBUG
default :
Notify ( PSTR ( " \r \n Unknown Report type: " ) ) ;
Serial . print ( l2capinbuf [ 9 ] , HEX ) ;
break ;
# endif
}
}
}
}
L2CAP_task ( ) ;
}
}
void WII : : L2CAP_task ( ) {
switch ( l2cap_state ) {
2012-10-07 14:50:51 +02:00
/* These states are used if the Wiimote is the host */
case L2CAP_CONTROL_SUCCESS :
if ( l2cap_config_success_control_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n HID Control Successfully Configured " ) ) ;
# endif
l2cap_state = L2CAP_INTERRUPT_SETUP ;
}
break ;
case L2CAP_INTERRUPT_SETUP :
if ( l2cap_connection_request_interrupt_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n HID Interrupt Incoming Connection Request " ) ) ;
# endif
pBtd - > l2cap_connection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid , PENDING ) ;
delay ( 1 ) ;
pBtd - > l2cap_connection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid , SUCCESSFUL ) ;
identifier + + ;
delay ( 1 ) ;
pBtd - > l2cap_config_request ( hci_handle , identifier , interrupt_scid ) ;
l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST ;
}
break ;
/* These states are used if the Arduino is the host */
2012-08-21 14:31:11 +02:00
case L2CAP_CONTROL_CONNECT_REQUEST :
if ( l2cap_connected_control_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Send HID Control Config Request " ) ) ;
# endif
identifier + + ;
pBtd - > l2cap_config_request ( hci_handle , identifier , control_scid ) ;
l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST ;
}
break ;
case L2CAP_CONTROL_CONFIG_REQUEST :
if ( l2cap_config_success_control_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Send HID Interrupt Connection Request " ) ) ;
# endif
identifier + + ;
pBtd - > l2cap_connection_request ( hci_handle , identifier , interrupt_dcid , HID_INTR_PSM ) ;
l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST ;
}
break ;
case L2CAP_INTERRUPT_CONNECT_REQUEST :
if ( l2cap_connected_interrupt_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Send HID Interrupt Config Request " ) ) ;
# endif
identifier + + ;
pBtd - > l2cap_config_request ( hci_handle , identifier , interrupt_scid ) ;
l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST ;
}
break ;
case L2CAP_INTERRUPT_CONFIG_REQUEST :
2012-10-07 14:50:51 +02:00
if ( l2cap_config_success_interrupt_flag ) { // Now the HID channels is established
2012-08-21 14:31:11 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n HID Channels Established " ) ) ;
# endif
2012-08-23 23:10:12 +02:00
pBtd - > connectToWii = false ;
2012-10-07 14:50:51 +02:00
pBtd - > pairWithWii = false ;
2012-08-23 23:10:12 +02:00
wiimoteConnected = true ;
stateCounter = 0 ;
l2cap_state = L2CAP_CHECK_MOTION_PLUS_STATE ;
2012-08-21 14:31:11 +02:00
}
2012-10-07 14:50:51 +02:00
break ;
2012-08-21 17:36:37 +02:00
2012-08-23 23:10:12 +02:00
/* The next states are in run() */
2012-08-21 14:31:11 +02:00
case L2CAP_INTERRUPT_DISCONNECT :
if ( l2cap_disconnect_response_interrupt_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Disconnected Interrupt Channel " ) ) ;
# endif
identifier + + ;
pBtd - > l2cap_disconnection_request ( hci_handle , identifier , control_scid , control_dcid ) ;
l2cap_state = L2CAP_CONTROL_DISCONNECT ;
}
break ;
case L2CAP_CONTROL_DISCONNECT :
if ( l2cap_disconnect_response_control_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Disconnected Control Channel " ) ) ;
# endif
pBtd - > hci_disconnect ( hci_handle ) ;
2013-01-28 00:55:01 +01:00
hci_handle = - 1 ; // Reset handle
2012-08-21 14:31:11 +02:00
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_WAIT ;
}
break ;
}
}
void WII : : Run ( ) {
switch ( l2cap_state ) {
case L2CAP_WAIT :
2013-01-20 22:46:04 +01:00
if ( pBtd - > connectToWii & & ! pBtd - > l2capConnectionClaimed & & ! wiimoteConnected & & ! activeConnection ) {
pBtd - > l2capConnectionClaimed = true ;
activeConnection = true ;
2012-08-21 14:31:11 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Send HID Control Connection Request " ) ) ;
# endif
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
l2cap_event_flag = 0 ; // Reset flags
identifier = 0 ;
pBtd - > l2cap_connection_request ( hci_handle , identifier , control_dcid , HID_CTRL_PSM ) ;
l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST ;
2012-10-07 14:50:51 +02:00
} else if ( l2cap_connection_request_control_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n HID Control Incoming Connection Request " ) ) ;
# endif
pBtd - > l2cap_connection_response ( hci_handle , identifier , control_dcid , control_scid , PENDING ) ;
delay ( 1 ) ;
pBtd - > l2cap_connection_response ( hci_handle , identifier , control_dcid , control_scid , SUCCESSFUL ) ;
identifier + + ;
delay ( 1 ) ;
pBtd - > l2cap_config_request ( hci_handle , identifier , control_scid ) ;
l2cap_state = L2CAP_CONTROL_SUCCESS ;
2012-08-21 14:31:11 +02:00
}
2012-10-07 14:50:51 +02:00
break ;
2012-08-23 23:10:12 +02:00
case L2CAP_CHECK_MOTION_PLUS_STATE :
# ifdef DEBUG
if ( stateCounter = = 0 ) // Only print onnce
Notify ( PSTR ( " \r \n Checking if a Motion Plus is connected " ) ) ;
# endif
stateCounter + + ;
2013-01-10 20:10:16 +01:00
if ( stateCounter % 200 = = 0 )
2012-08-23 23:10:12 +02:00
checkMotionPresent ( ) ; // Check if there is a motion plus connected
if ( motion_plus_connected_flag ) {
stateCounter = 0 ;
l2cap_state = L2CAP_INIT_MOTION_PLUS_STATE ;
timer = micros ( ) ;
if ( unknownExtensionConnected ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n A extension is also connected " ) ) ;
# endif
activateNunchuck = true ; // For we will just set this to true as this the only extension supported so far
}
}
2013-01-10 20:10:16 +01:00
else if ( stateCounter = = 601 ) { // We will try three times to check for the motion plus
2012-08-23 23:10:12 +02:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n No Motion Plus was detected " ) ) ;
# endif
stateCounter = 0 ;
l2cap_state = L2CAP_CHECK_EXTENSION_STATE ;
}
break ;
case L2CAP_CHECK_EXTENSION_STATE : // This is used to check if there is anything plugged in to the extension port
# ifdef DEBUG
if ( stateCounter = = 0 ) // Only print onnce
Notify ( PSTR ( " \r \n Checking if there is any extension connected " ) ) ;
# endif
stateCounter + + ; // We use this counter as there has to be a short delay between the commands
if ( stateCounter = = 1 )
statusRequest ( ) ; // See if a new device has connected
if ( stateCounter = = 100 ) {
if ( unknownExtensionConnected ) // Check if there is a extension is connected to the port
initExtension1 ( ) ;
else
stateCounter = 399 ;
} else if ( stateCounter = = 200 )
2013-01-10 20:10:16 +01:00
initExtension2 ( ) ;
2012-08-23 23:10:12 +02:00
else if ( stateCounter = = 300 ) {
readExtensionType ( ) ;
unknownExtensionConnected = false ;
} else if ( stateCounter = = 400 ) {
stateCounter = 0 ;
l2cap_state = L2CAP_LED_STATE ;
}
break ;
2012-10-07 16:24:12 +02:00
case L2CAP_INIT_MOTION_PLUS_STATE :
2012-08-23 23:10:12 +02:00
stateCounter + + ;
if ( stateCounter = = 1 )
initMotionPlus ( ) ;
else if ( stateCounter = = 100 )
activateMotionPlus ( ) ;
else if ( stateCounter = = 200 )
readExtensionType ( ) ; // Check if it has been activated
else if ( stateCounter = = 300 ) {
stateCounter = 0 ;
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
l2cap_state = L2CAP_LED_STATE ;
}
break ;
2012-10-07 16:24:12 +02:00
case L2CAP_LED_STATE :
2012-10-02 01:43:00 +02:00
if ( nunchuck_connected_flag )
2012-08-23 23:10:12 +02:00
nunchuckConnected = true ;
2012-10-06 16:42:00 +02:00
setLedStatus ( ) ;
2012-08-23 23:10:12 +02:00
l2cap_state = L2CAP_DONE ;
2012-10-07 16:24:12 +02:00
break ;
2012-10-07 14:50:51 +02:00
2012-08-23 23:10:12 +02:00
case L2CAP_DONE :
if ( unknownExtensionConnected ) {
# ifdef DEBUG
if ( stateCounter = = 0 ) // Only print once
Notify ( PSTR ( " \r \n Checking extension port " ) ) ;
# endif
stateCounter + + ; // We will use this counter as there has to be a short delay between the commands
if ( stateCounter = = 50 )
statusRequest ( ) ;
else if ( stateCounter = = 100 )
initExtension1 ( ) ;
else if ( stateCounter = = 150 )
if ( ( extensionConnected & & motionPlusConnected ) | | ( unknownExtensionConnected & & ! motionPlusConnected ) )
initExtension2 ( ) ;
else
stateCounter = 299 ; // There is no extension connected
else if ( stateCounter = = 200 )
readExtensionType ( ) ;
else if ( stateCounter = = 250 ) {
if ( nunchuck_connected_flag ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Nunchuck was reconnected " ) ) ;
# endif
activateNunchuck = true ;
nunchuckConnected = true ;
}
if ( ! motionPlusConnected )
stateCounter = 449 ;
}
else if ( stateCounter = = 300 ) {
if ( motionPlusConnected ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Reactivating the Motion Plus " ) ) ;
# endif
initMotionPlus ( ) ;
} else
stateCounter = 449 ;
}
else if ( stateCounter = = 350 )
activateMotionPlus ( ) ;
else if ( stateCounter = = 400 )
readExtensionType ( ) ; // Check if it has been activated
else if ( stateCounter = = 450 ) {
2012-10-06 16:42:00 +02:00
setLedStatus ( ) ;
2012-08-23 23:10:12 +02:00
stateCounter = 0 ;
unknownExtensionConnected = false ;
}
} else
stateCounter = 0 ;
2012-08-21 14:31:11 +02:00
break ;
}
}
/************************************************************/
/* HID Commands */
/************************************************************/
void WII : : HID_Command ( uint8_t * data , uint8_t nbytes ) {
2013-01-10 20:10:16 +01:00
if ( pBtd - > motionPlusInside )
pBtd - > L2CAP_Command ( hci_handle , data , nbytes , interrupt_scid [ 0 ] , interrupt_scid [ 1 ] ) ; // It's the new wiimote with the Motion Plus Inside
else
pBtd - > L2CAP_Command ( hci_handle , data , nbytes , control_scid [ 0 ] , control_scid [ 1 ] ) ;
2012-08-21 14:31:11 +02:00
}
void WII : : setAllOff ( ) {
HIDBuffer [ 1 ] = 0x11 ;
HIDBuffer [ 2 ] = 0x00 ;
HID_Command ( HIDBuffer , 3 ) ;
}
void WII : : setRumbleOff ( ) {
HIDBuffer [ 1 ] = 0x11 ;
HIDBuffer [ 2 ] & = ~ 0x01 ; // Bit 0 control the rumble
HID_Command ( HIDBuffer , 3 ) ;
}
void WII : : setRumbleOn ( ) {
HIDBuffer [ 1 ] = 0x11 ;
HIDBuffer [ 2 ] | = 0x01 ; // Bit 0 control the rumble
HID_Command ( HIDBuffer , 3 ) ;
}
void WII : : setRumbleToggle ( ) {
HIDBuffer [ 1 ] = 0x11 ;
HIDBuffer [ 2 ] ^ = 0x01 ; // Bit 0 control the rumble
HID_Command ( HIDBuffer , 3 ) ;
}
void WII : : setLedOff ( LED a ) {
HIDBuffer [ 1 ] = 0x11 ;
2013-01-27 21:25:50 +01:00
HIDBuffer [ 2 ] & = ~ ( pgm_read_byte ( & LEDS [ ( uint8_t ) a ] ) ) ;
2012-08-22 23:41:38 +02:00
HID_Command ( HIDBuffer , 3 ) ;
2012-08-21 14:31:11 +02:00
}
void WII : : setLedOn ( LED a ) {
HIDBuffer [ 1 ] = 0x11 ;
2013-01-27 21:25:50 +01:00
HIDBuffer [ 2 ] | = pgm_read_byte ( & LEDS [ ( uint8_t ) a ] ) ;
2012-08-21 14:31:11 +02:00
HID_Command ( HIDBuffer , 3 ) ;
}
void WII : : setLedToggle ( LED a ) {
2012-08-21 17:36:37 +02:00
HIDBuffer [ 1 ] = 0x11 ;
2013-01-27 21:25:50 +01:00
HIDBuffer [ 2 ] ^ = pgm_read_byte ( & LEDS [ ( uint8_t ) a ] ) ;
2012-08-21 17:36:37 +02:00
HID_Command ( HIDBuffer , 3 ) ;
}
2012-10-06 16:42:00 +02:00
void WII : : setLedStatus ( ) {
HIDBuffer [ 1 ] = 0x11 ;
2012-10-08 17:29:30 +02:00
HIDBuffer [ 2 ] = ( HIDBuffer [ 2 ] & 0x01 ) ; // Keep the rumble bit
2012-10-06 16:42:00 +02:00
if ( wiimoteConnected )
HIDBuffer [ 2 ] | = 0x10 ; // If it's connected LED1 will light up
if ( motionPlusConnected )
HIDBuffer [ 2 ] | = 0x20 ; // If it's connected LED2 will light up
if ( nunchuckConnected )
HIDBuffer [ 2 ] | = 0x40 ; // If it's connected LED3 will light up
HID_Command ( HIDBuffer , 3 ) ;
}
2012-08-21 17:36:37 +02:00
void WII : : setReportMode ( bool continuous , uint8_t mode ) {
uint8_t cmd_buf [ 4 ] ;
2012-10-08 17:29:30 +02:00
cmd_buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2012-08-21 17:36:37 +02:00
cmd_buf [ 1 ] = 0x12 ;
if ( continuous )
2012-10-08 17:29:30 +02:00
cmd_buf [ 2 ] = 0x04 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Keep the rumble bit
2012-08-21 17:36:37 +02:00
else
2012-10-08 17:29:30 +02:00
cmd_buf [ 2 ] = 0x00 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Keep the rumble bit
2012-08-21 17:36:37 +02:00
cmd_buf [ 3 ] = mode ;
HID_Command ( cmd_buf , 4 ) ;
}
void WII : : statusRequest ( ) {
uint8_t cmd_buf [ 3 ] ;
2012-10-08 17:29:30 +02:00
cmd_buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2012-08-21 17:36:37 +02:00
cmd_buf [ 1 ] = 0x15 ;
2012-10-08 17:29:30 +02:00
cmd_buf [ 2 ] = ( HIDBuffer [ 2 ] & 0x01 ) ; // Keep the rumble bit
2012-08-21 17:36:37 +02:00
HID_Command ( cmd_buf , 3 ) ;
2012-08-21 14:31:11 +02:00
}
2012-08-22 23:41:38 +02:00
/************************************************************/
/* Memmory Commands */
/************************************************************/
void WII : : writeData ( uint32_t offset , uint8_t size , uint8_t * data ) {
uint8_t cmd_buf [ 23 ] ;
2012-10-08 17:29:30 +02:00
cmd_buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2012-08-22 23:41:38 +02:00
cmd_buf [ 1 ] = 0x16 ; // Write data
2012-10-08 17:29:30 +02:00
cmd_buf [ 2 ] = 0x04 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Write to memory, clear bit 2 to write to EEPROM
2012-08-22 23:41:38 +02:00
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 ) ;
}
2012-08-23 23:10:12 +02:00
void WII : : initExtension1 ( ) {
2012-08-22 23:41:38 +02:00
uint8_t buf [ 1 ] ;
buf [ 0 ] = 0x55 ;
writeData ( 0xA400F0 , 1 , buf ) ;
}
2012-08-23 23:10:12 +02:00
void WII : : initExtension2 ( ) {
2012-08-22 23:41:38 +02:00
uint8_t buf [ 1 ] ;
buf [ 0 ] = 0x00 ;
writeData ( 0xA400FB , 1 , buf ) ;
}
2012-08-23 23:10:12 +02:00
void WII : : initMotionPlus ( ) {
uint8_t buf [ 1 ] ;
buf [ 0 ] = 0x55 ;
writeData ( 0xA600F0 , 1 , buf ) ;
}
void WII : : activateMotionPlus ( ) {
uint8_t buf [ 1 ] ;
if ( activateNunchuck ) {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Activating Motion Plus in pass-through mode " ) ) ;
# endif
buf [ 0 ] = 0x05 ; // Activate nunchuck pass-through mode
}
//else if(classicControllerConnected && extensionConnected)
//buf[0] = 0x07;
else {
# ifdef DEBUG
Notify ( PSTR ( " \r \n Activating Motion Plus in normal mode " ) ) ;
# endif
buf [ 0 ] = 0x04 ; // Don't use any extension
}
writeData ( 0xA600FE , 1 , buf ) ;
}
2012-08-22 23:41:38 +02:00
void WII : : readData ( uint32_t offset , uint16_t size , bool EEPROM ) {
uint8_t cmd_buf [ 8 ] ;
2012-10-08 17:29:30 +02:00
cmd_buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2012-08-22 23:41:38 +02:00
cmd_buf [ 1 ] = 0x17 ; // Read data
if ( EEPROM )
2012-10-08 17:29:30 +02:00
cmd_buf [ 2 ] = 0x00 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Read from EEPROM
2012-08-22 23:41:38 +02:00
else
2012-10-08 17:29:30 +02:00
cmd_buf [ 2 ] = 0x04 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Read from memory
2012-08-22 23:41:38 +02:00
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 ) ;
}
2012-08-23 23:10:12 +02:00
void WII : : checkMotionPresent ( ) {
readData ( 0xA600FA , 6 , false ) ;
}
2012-08-22 23:41:38 +02:00
2012-08-21 14:31:11 +02:00
/************************************************************/
/* WII Commands */
/************************************************************/
2012-08-22 23:41:38 +02:00
bool WII : : getButtonPress ( Button b ) { // Return true when a button is pressed
2013-01-27 21:25:50 +01:00
return ( ButtonState & pgm_read_dword ( & BUTTONS [ ( uint8_t ) b ] ) ) ;
2012-08-21 14:31:11 +02:00
}
2012-08-22 23:41:38 +02:00
bool WII : : getButtonClick ( Button b ) { // Only return true when a button is clicked
2013-01-27 21:25:50 +01:00
uint32_t button = pgm_read_dword ( & BUTTONS [ ( uint8_t ) b ] ) ;
bool click = ( ButtonClickState & button ) ;
ButtonClickState & = ~ button ; // clear "click" event
2012-08-21 14:31:11 +02:00
return click ;
2012-08-22 23:41:38 +02:00
}
2013-01-27 21:25:50 +01:00
uint8_t WII : : getAnalogHat ( Hat a ) {
2012-08-22 23:41:38 +02:00
if ( ! nunchuckConnected )
2012-08-23 23:10:12 +02:00
return 127 ; // Return center position
2012-08-22 23:41:38 +02:00
else {
uint8_t output = hatValues [ ( uint8_t ) a ] ;
2012-08-23 23:10:12 +02:00
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
2012-08-22 23:41:38 +02:00
return 127 ;
else
return output ;
}
2013-01-17 00:07:56 +01:00
}
/************************************************************/
/* The following functions are for the IR camera */
/************************************************************/
# ifdef WIICAMERA
2013-01-17 00:47:19 +01:00
void WII : : IRinitialize ( ) { // Turns on and initialises the IR camera
2013-01-17 00:07:56 +01:00
2013-01-17 00:47:19 +01:00
enableIRCamera1 ( ) ;
2013-01-17 00:07:56 +01:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Enable IR Camera1 Complete " ) ) ;
# endif
delay ( 80 ) ;
2013-01-17 00:47:19 +01:00
enableIRCamera2 ( ) ;
2013-01-17 00:07:56 +01:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Enable IR Camera2 Complete " ) ) ;
# endif
delay ( 80 ) ;
write0x08Value ( ) ;
# ifdef DEBUG
Notify ( PSTR ( " \r \n Wrote hex number 0x08 " ) ) ;
# endif
delay ( 80 ) ;
2013-01-17 00:47:19 +01:00
writeSensitivityBlock1 ( ) ;
2013-01-17 00:07:56 +01:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Wrote Sensitivity Block 1 " ) ) ;
# endif
delay ( 80 ) ;
2013-01-17 00:47:19 +01:00
writeSensitivityBlock2 ( ) ;
2013-01-17 00:07:56 +01:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Wrote Sensitivity Block 2 " ) ) ;
# endif
delay ( 80 ) ;
2013-01-17 00:47:19 +01:00
uint8_t mode_num = 0x03 ;
setWiiModeNumber ( mode_num ) ; // Change input for whatever mode you want i.e. 0x01, 0x03, or 0x05
2013-01-17 00:07:56 +01:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Set Wii Mode Number To 0x " ) ) ;
2013-01-17 00:47:19 +01:00
PrintHex < uint8_t > ( mode_num ) ;
2013-01-17 00:07:56 +01:00
# endif
delay ( 80 ) ;
write0x08Value ( ) ;
# ifdef DEBUG
Notify ( PSTR ( " \r \n Wrote Hex Number 0x08 " ) ) ;
# endif
delay ( 80 ) ;
2013-01-23 22:28:40 +01:00
setReportMode ( false , 0x33 ) ;
2013-01-17 00:47:19 +01:00
//setReportMode(false, 0x3f); // For full reporting mode, doesn't work yet
2013-01-17 00:07:56 +01:00
# ifdef DEBUG
Notify ( PSTR ( " \r \n Set Report Mode to 0x33 " ) ) ;
# endif
2013-01-23 22:28:40 +01:00
delay ( 80 ) ;
statusRequest ( ) ; // Used to update wiiState - call isIRCameraEnabled() afterwards to check if it actually worked
# ifdef DEBUG
Notify ( PSTR ( " \r \n IR Initialized " ) ) ;
# endif
2013-01-17 00:07:56 +01:00
}
2013-01-17 00:47:19 +01:00
void WII : : enableIRCamera1 ( ) {
2013-01-17 00:07:56 +01:00
uint8_t cmd_buf [ 3 ] ;
cmd_buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2013-01-17 00:47:19 +01:00
cmd_buf [ 1 ] = 0x13 ; // Output report 13
2013-01-17 00:07:56 +01:00
cmd_buf [ 2 ] = 0x04 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Keep the rumble bit and sets bit 2
HID_Command ( cmd_buf , 3 ) ;
}
2013-01-17 00:47:19 +01:00
void WII : : enableIRCamera2 ( ) {
2013-01-17 00:07:56 +01:00
uint8_t cmd_buf [ 3 ] ;
cmd_buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
2013-01-17 00:47:19 +01:00
cmd_buf [ 1 ] = 0x1A ; // Output report 1A
2013-01-17 00:07:56 +01:00
cmd_buf [ 2 ] = 0x04 | ( HIDBuffer [ 2 ] & 0x01 ) ; // Keep the rumble bit and sets bit 2
HID_Command ( cmd_buf , 3 ) ;
}
2013-01-17 00:47:19 +01:00
void WII : : writeSensitivityBlock1 ( ) {
2013-01-17 00:07:56 +01:00
uint8_t buf [ 9 ] ;
buf [ 0 ] = 0x00 ;
buf [ 1 ] = 0x00 ;
buf [ 2 ] = 0x00 ;
buf [ 3 ] = 0x00 ;
buf [ 4 ] = 0x00 ;
buf [ 5 ] = 0x00 ;
buf [ 6 ] = 0x90 ;
buf [ 7 ] = 0x00 ;
buf [ 8 ] = 0x41 ;
writeData ( 0xB00000 , 9 , buf ) ;
}
2013-01-17 00:47:19 +01:00
void WII : : writeSensitivityBlock2 ( ) {
2013-01-17 00:07:56 +01:00
uint8_t buf [ 2 ] ;
buf [ 0 ] = 0x40 ;
buf [ 1 ] = 0x00 ;
writeData ( 0xB0001A , 2 , buf ) ;
}
void WII : : write0x08Value ( ) {
2013-01-17 00:47:19 +01:00
uint8_t cmd = 0x08 ;
writeData ( 0xb00030 , 1 , & cmd ) ;
2013-01-17 00:07:56 +01:00
}
2013-01-23 22:28:40 +01:00
void WII : : setWiiModeNumber ( uint8_t mode_number ) { // mode_number in hex i.e. 0x03 for extended mode
2013-01-17 00:47:19 +01:00
writeData ( 0xb00033 , 1 , & mode_number ) ;
2013-01-17 00:07:56 +01:00
}
# endif