Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* 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
- */
- #include "Wii.h"
- #define DEBUG // Uncomment to print data for debugging
- #define EXTRADEBUG // Uncomment to get even more debugging data
- #define PRINTREPORT // Uncomment to print the report send by the Wiimote
- 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
- {
- if (pBtd)
- pBtd->wiiServiceID = pBtd->registerServiceClass(this); // Register it as a Bluetooth service
- pBtd->disc_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
- pBtd->disc_bdaddr[4] = btadr4;
- pBtd->disc_bdaddr[3] = btadr3;
- pBtd->disc_bdaddr[2] = btadr2;
- pBtd->disc_bdaddr[1] = btadr1;
- pBtd->disc_bdaddr[0] = btadr0;
- HIDBuffer[0] = 0xA2;// HID BT DATA_request (0x50) | Report Type (Output 0x02)
- /* 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() {
- connected = false;
- 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) {
- if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok
- 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\nL2CAP 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
- }
- else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
- Serial.print("\r\nL2CAP_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;
- }
- }
- }
- 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\nDisconnect Request: Control Channel"));
- #endif
- connected = false;
- 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\nDisconnect Request: Interrupt Channel"));
- #endif
- connected = false;
- 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\nL2CAP 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");
- if(connected) {
- /* Read Report */
- if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
- if(l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) { // These reports include the buttons
- ButtonState = (uint16_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
- ButtonClickState = ButtonState; // Update click state variable
- #ifdef PRINTREPORT
- Notify(PSTR("ButtonState: "));
- PrintHex<uint16_t>(ButtonState);
- Notify(PSTR("\r\n"));
- #endif
- if(ButtonState != OldButtonState) {
- buttonChanged = true;
- if(ButtonState != 0x0000) {
- buttonPressed = true;
- buttonReleased = false;
- } else {
- buttonPressed = false;
- buttonReleased = true;
- }
- }
- else {
- buttonChanged = false;
- buttonPressed = false;
- buttonReleased = false;
- }
- OldButtonState = ButtonState;
- }
- if(l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x35) { // Read the accelerometer
- int16_t accX = ((l2capinbuf[12] << 2) | (l2capinbuf[10] & 0x60 >> 5))-500;
- int16_t accY = ((l2capinbuf[13] << 2) | (l2capinbuf[11] & 0x20 >> 4))-500;
- int16_t accZ = ((l2capinbuf[14] << 2) | (l2capinbuf[11] & 0x40 >> 5))-500;
- /*
- Notify(PSTR("\r\naccX: "));
- Serial.print(accX);
- Notify(PSTR("\taccY: "));
- Serial.print(accY);
- Notify(PSTR("\taccZ: "));
- Serial.print(accZ);
- */
- pitch = (atan2(accY,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]) {
- case 0x20: // Status Information
- // (a1) 20 BB BB LF 00 00 VV
- if(l2capinbuf[12] & 0x02) // Check if a extension is connected
- setReportMode(false,0x35); // Also read the extension
- else
- setReportMode(false,0x31); // If there is no extension connected we will read the button and accelerometer
- break;
- case 0x30: // Core buttons
- // (a1) 30 BB BB
- break;
- case 0x31: // Core Buttons and Accelerometer
- // (a1) 31 BB BB AA AA AA
- break;
- case 0x32: // Core Buttons with 8 Extension bytes
- // (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;
- 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
- /*
- Notify(PSTR("\r\n"));
- for (uint8_t i = 0; i < 19; i++) {
- Serial.print(l2capinbuf[12+i]);
- Notify(PSTR(" "));
- }
- */
- break;
- 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
- /*
- Notify(PSTR("\r\n"));
- for (uint8_t i = 0; i < 16; i++) {
- Serial.print(l2capinbuf[15+i]);
- Notify(PSTR(" "));
- }
- */
- break;
- #ifdef DEBUG
- default:
- Notify(PSTR("\r\nUnknown Report type: "));
- Serial.print(l2capinbuf[9],HEX);
- break;
- #endif
- }
- }
- }
- }
- L2CAP_task();
- }
- }
- void WII::L2CAP_task() {
- switch (l2cap_state) {
- case L2CAP_CONTROL_CONNECT_REQUEST:
- if (l2cap_connected_control_flag) {
- #ifdef DEBUG
- Notify(PSTR("\r\nSend 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\nSend 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\nSend 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:
- if(l2cap_config_success_interrupt_flag) {
- #ifdef DEBUG
- Notify(PSTR("\r\nHID Channels Established"));
- #endif
- statusRequest();
- l2cap_state = L2CAP_WII_STATUS_STATE;
- }
- break;
- case L2CAP_WII_STATUS_STATE:
- connected = true;
- pBtd->connectToWii = false;
- ButtonState = 0;
- OldButtonState = 0;
- ButtonClickState = 0;
- setLedOn(LED1);
- l2cap_state = L2CAP_DONE;
- break;
- /*
- case L2CAP_WIIREMOTE_CAL_STATE:
- //Todo enable support for Motion Plus
- break;
- */
- case L2CAP_DONE:
- break;
- case L2CAP_INTERRUPT_DISCONNECT:
- if (l2cap_disconnect_response_interrupt_flag) {
- #ifdef DEBUG
- Notify(PSTR("\r\nDisconnected 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\nDisconnected Control Channel"));
- #endif
- pBtd->hci_disconnect(hci_handle);
- l2cap_event_flag = 0; // Reset flags
- l2cap_state = L2CAP_WAIT;
- }
- break;
- }
- }
- void WII::Run() {
- switch (l2cap_state) {
- case L2CAP_WAIT:
- if(pBtd->connectToWii) {
- #ifdef DEBUG
- Notify(PSTR("\r\nSend 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;
- }
- break;
- }
- }
- /************************************************************/
- /* HID Commands */
- /************************************************************/
- void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
- pBtd->L2CAP_Command(hci_handle,data,nbytes,control_scid[0],control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
- }
- 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;
- HIDBuffer[2] &= ~((uint8_t)a);
- HID_Command(HIDBuffer, 3);
- }
- void WII::setLedOn(LED a) {
- HIDBuffer[1] = 0x11;
- HIDBuffer[2] |= (uint8_t)a;
- HID_Command(HIDBuffer, 3);
- }
- void WII::setLedToggle(LED a) {
- HIDBuffer[1] = 0x11;
- HIDBuffer[2] ^= (uint8_t)a;
- HID_Command(HIDBuffer, 3);
- }
- void WII::setReportMode(bool continuous, uint8_t mode) {
- uint8_t cmd_buf[4];
- cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
- cmd_buf[1] = 0x12;
- if(continuous)
- cmd_buf[2] = 0x04;
- else
- cmd_buf[2] = 0x00;
- cmd_buf[3] = mode;
- HID_Command(cmd_buf, 4);
- }
- void WII::statusRequest() {
- uint8_t cmd_buf[3];
- cmd_buf[0] = 0xA2; // HID BT DATA_request (0x50) | Report Type (Output 0x02)
- cmd_buf[1] = 0x15;
- cmd_buf[2] = 0x00;
- HID_Command(cmd_buf, 3);
- }
- /************************************************************/
- /* WII Commands */
- /************************************************************/
- bool WII::getButtonPress(Button b) {
- if(ButtonState & (uint16_t)b)
- return true;
- else
- return false;
- }
- bool WII::getButtonClick(Button b) {
- bool click = ((ButtonClickState & (uint16_t)b) != 0);
- ButtonClickState &= ~((uint16_t)b); // clear "click" event
- return click;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement