From f783b97cb923baab4903e7856f4f3f2c5503d652 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 24 Nov 2013 21:55:15 +0100 Subject: [PATCH 01/24] Initial commit for BTHID library To see incoming data uncomment PRINTREPORT in BTHID.cpp --- BTD.cpp | 142 +++++++--- BTD.h | 56 ++-- BTHID.cpp | 410 +++++++++++++++++++++++++++++ BTHID.h | 162 ++++++++++++ Wii.h | 2 - controllerEnums.h | 2 + examples/Bluetooth/BTHID/BTHID.ino | 37 +++ keywords.txt | 1 + 8 files changed, 749 insertions(+), 63 deletions(-) create mode 100644 BTHID.cpp create mode 100644 BTHID.h create mode 100644 examples/Bluetooth/BTHID/BTHID.ino diff --git a/BTD.cpp b/BTD.cpp index 0b5715c2..ab858d46 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -27,6 +27,8 @@ const uint8_t BTD::BTD_DATAOUT_PIPE = 3; BTD::BTD(USB *p) : connectToWii(false), pairWithWii(false), +connectToHIDDevice(false), +pairWithHIDDevice(false), pUsb(p), // Pointer to USB class instance - mandatory bAddress(0), // Device address - mandatory bNumEP(1), // If config descriptor needs to be parsed @@ -303,6 +305,8 @@ void BTD::clearAllVariables() { connectToWii = false; incomingWii = false; + connectToHIDDevice = false; + incomingHIDDevice = false; bAddress = 0; // Clear device address bNumEP = 1; // Must have to be reset to 1 qNextPollTime = 0; // Reset next poll time @@ -411,13 +415,18 @@ void BTD::HCI_event_task() { break; case EV_INQUIRY_COMPLETE: - if (inquiry_counter >= 5 && pairWithWii) { + if (inquiry_counter >= 5 && (pairWithWii || pairWithHIDDevice)) { inquiry_counter = 0; #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80); + if (pairWithWii) + Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80); + else + Notify(PSTR("\r\nCouldn't find HID device"), 0x80); #endif connectToWii = false; pairWithWii = false; + connectToHIDDevice = false; + pairWithHIDDevice = false; hci_state = HCI_SCANNING_STATE; } inquiry_counter++; @@ -430,28 +439,44 @@ void BTD::HCI_event_task() { Notify(hcibuf[2], 0x80); #endif for (uint8_t i = 0; i < hcibuf[2]; i++) { - if ((hcibuf[4 + 8 * hcibuf[2] + 3 * i] == 0x04 && hcibuf[5 + 8 * hcibuf[2] + 3 * i] == 0x25 && hcibuf[6 + 8 * hcibuf[2] + 3 * i] == 0x00) || (hcibuf[4 + 8 * hcibuf[2] + 3 * i] == 0x08 && hcibuf[5 + 8 * hcibuf[2] + 3 * i] == 0x05 && hcibuf[6 + 8 * hcibuf[2] + 3 * i] == 0x00)) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html and http://wiibrew.org/wiki/Wiimote#SDP_information - if (hcibuf[4 + 8 * hcibuf[2] + 3 * i] == 0x08) // Check if it's the new Wiimote with motion plus inside that was detected + uint8_t offset = 8 * hcibuf[2] + 3 * i; + uint8_t classOfDevice[3]; + + for (uint8_t j = 0; j < 3; j++) + classOfDevice[j] = hcibuf[j + 4 + offset]; + + if (pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0x0C)) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html and http://wiibrew.org/wiki/Wiimote#SDP_information + if (classOfDevice[0] & 0x08) // Check if it's the new Wiimote with motion plus inside that was detected motionPlusInside = true; else motionPlusInside = false; - disc_bdaddr[0] = hcibuf[3 + 6 * i]; - disc_bdaddr[1] = hcibuf[4 + 6 * i]; - disc_bdaddr[2] = hcibuf[5 + 6 * i]; - disc_bdaddr[3] = hcibuf[6 + 6 * i]; - disc_bdaddr[4] = hcibuf[7 + 6 * i]; - disc_bdaddr[5] = hcibuf[8 + 6 * i]; - hci_event_flag |= HCI_FLAG_WII_FOUND; + + for (uint8_t j = 0; j < 6; j++) + disc_bdaddr[j] = hcibuf[j + 3 + 6 * i]; + + hci_event_flag |= HCI_FLAG_DEVICE_FOUND; break; + } else if (pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC0)) { // Check if it is a mouse or keyboard +#ifdef DEBUG_USB_HOST + if (classOfDevice[0] & 0x80) + Notify(PSTR("\r\nMouse found"), 0x80); + if (classOfDevice[0] & 0x40) + Notify(PSTR("\r\nKeyboard found"), 0x80); +#endif + + for (uint8_t j = 0; j < 6; j++) + disc_bdaddr[j] = hcibuf[j + 3 + 6 * i]; + + hci_event_flag |= HCI_FLAG_DEVICE_FOUND; } #ifdef EXTRADEBUG else { Notify(PSTR("\r\nClass of device: "), 0x80); - D_PrintHex (hcibuf[6 + 8 * hcibuf[2] + 3 * i], 0x80); + D_PrintHex (classOfDevice[2], 0x80); Notify(PSTR(" "), 0x80); - D_PrintHex (hcibuf[5 + 8 * hcibuf[2] + 3 * i], 0x80); + D_PrintHex (classOfDevice[1], 0x80); Notify(PSTR(" "), 0x80); - D_PrintHex (hcibuf[4 + 8 * hcibuf[2] + 3 * i], 0x80); + D_PrintHex (classOfDevice[0], 0x80); } #endif } @@ -467,7 +492,7 @@ void BTD::HCI_event_task() { hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // store the handle for the ACL connection hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag } else { - hci_state = HCI_CHECK_WII_SERVICE; + hci_state = HCI_CHECK_DEVICE_SERVICE; #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nConnection Failed: "), 0x80); D_PrintHex (hcibuf[2], 0x80); @@ -491,12 +516,19 @@ void BTD::HCI_event_task() { break; case EV_INCOMING_CONNECT: - disc_bdaddr[0] = hcibuf[2]; - disc_bdaddr[1] = hcibuf[3]; - disc_bdaddr[2] = hcibuf[4]; - disc_bdaddr[3] = hcibuf[5]; - disc_bdaddr[4] = hcibuf[6]; - disc_bdaddr[5] = hcibuf[7]; + for (uint8_t i = 0; i < 6; i++) + disc_bdaddr[i] = hcibuf[i + 2]; + + if ((hcibuf[9] & 0x05) && (hcibuf[8] & 0xC0)) { // Check if it is a mouse or keyboard +#ifdef DEBUG_USB_HOST + if (hcibuf[8] & 0x80) + Notify(PSTR("\r\nMouse is connecting"), 0x80); + if (hcibuf[8] & 0x40) + Notify(PSTR("\r\nKeyboard is connecting"), 0x80); +#endif + incomingHIDDevice = true; + } + #ifdef EXTRADEBUG Notify(PSTR("\r\nClass of device: "), 0x80); D_PrintHex (hcibuf[10], 0x80); @@ -538,9 +570,14 @@ void BTD::HCI_event_task() { case EV_AUTHENTICATION_COMPLETE: if (pairWithWii && !connectToWii) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nPairing successful"), 0x80); + Notify(PSTR("\r\nPairing successful with Wiimote"), 0x80); #endif connectToWii = true; // Only send the ACL data to the Wii service + } else if (pairWithHIDDevice && !connectToHIDDevice) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nPairing successful with HID device"), 0x80); +#endif + connectToHIDDevice = true; // Only send the ACL data to the Wii service } break; /* We will just ignore the following events */ @@ -639,7 +676,7 @@ void BTD::HCI_task() { hci_set_local_name(btdName); hci_state = HCI_SET_NAME_STATE; } else - hci_state = HCI_CHECK_WII_SERVICE; + hci_state = HCI_CHECK_DEVICE_SERVICE; } break; @@ -649,14 +686,17 @@ void BTD::HCI_task() { Notify(PSTR("\r\nThe name is set to: "), 0x80); NotifyStr(btdName, 0x80); #endif - hci_state = HCI_CHECK_WII_SERVICE; + hci_state = HCI_CHECK_DEVICE_SERVICE; } break; - case HCI_CHECK_WII_SERVICE: - if (pairWithWii) { // Check if it should try to connect to a wiimote + case HCI_CHECK_DEVICE_SERVICE: + if (pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a wiimote #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press sync if you are using a Wii U Pro Controller"), 0x80); + if (pairWithWii) + Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press sync if you are using a Wii U Pro Controller"), 0x80); + else + Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80); #endif hci_inquiry(); hci_state = HCI_INQUIRY_STATE; @@ -665,37 +705,55 @@ void BTD::HCI_task() { break; case HCI_INQUIRY_STATE: - if (hci_wii_found) { + if (hci_device_found) { hci_inquiry_cancel(); // Stop inquiry #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nWiimote found"), 0x80); + if (pairWithWii) + Notify(PSTR("\r\nWiimote found"), 0x80); + else + Notify(PSTR("\r\nHID device found"), 0x80); + Notify(PSTR("\r\nNow just create the instance like so:"), 0x80); - Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80); - Notify(PSTR("\r\nAnd then press any button on the Wiimote"), 0x80); + if (pairWithWii) + Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80); + else + Notify(PSTR("\r\nBTHID hid(&Btd);"), 0x80); + + Notify(PSTR("\r\nAnd then press any button on the "), 0x80); + if (pairWithWii) + Notify(PSTR("Wiimote"), 0x80); + else + Notify(PSTR("device"), 0x80); #endif if (motionPlusInside) { hci_remote_name(); // We need to know the name to distinguish between a Wiimote and a Wii U Pro Controller hci_state = HCI_REMOTE_NAME_STATE; } else - hci_state = HCI_CONNECT_WII_STATE; + hci_state = HCI_CONNECT_DEVICE_STATE; } break; - case HCI_CONNECT_WII_STATE: + case HCI_CONNECT_DEVICE_STATE: if (hci_cmd_complete) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nConnecting to Wiimote"), 0x80); + if (pairWithWii) + Notify(PSTR("\r\nConnecting to Wiimote"), 0x80); + else + Notify(PSTR("\r\nConnecting to HID device"), 0x80); #endif hci_connect(); - hci_state = HCI_CONNECTED_WII_STATE; + hci_state = HCI_CONNECTED_DEVICE_STATE; } break; - case HCI_CONNECTED_WII_STATE: + case HCI_CONNECTED_DEVICE_STATE: if (hci_connect_event) { if (hci_connect_complete) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nConnected to Wiimote"), 0x80); + if (pairWithWii) + Notify(PSTR("\r\nConnected to Wiimote"), 0x80); + else + Notify(PSTR("\r\nConnected to HID device"), 0x80); #endif hci_authentication_request(); // This will start the pairing with the wiimote hci_state = HCI_SCANNING_STATE; @@ -709,7 +767,7 @@ void BTD::HCI_task() { break; case HCI_SCANNING_STATE: - if (!connectToWii && !pairWithWii) { + if (!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80); #endif @@ -763,7 +821,7 @@ void BTD::HCI_task() { } } if (pairWithWii && motionPlusInside) - hci_state = HCI_CONNECT_WII_STATE; + hci_state = HCI_CONNECT_DEVICE_STATE; else { hci_accept_connection(); hci_state = HCI_CONNECTED_STATE; @@ -816,6 +874,10 @@ void BTD::HCI_task() { incomingWii = false; pairWithWii = false; + connectToHIDDevice = false; + incomingHIDDevice = false; + pairWithHIDDevice = false; + hci_state = HCI_SCANNING_STATE; } break; @@ -947,7 +1009,7 @@ void BTD::hci_set_local_name(const char* name) { } void BTD::hci_inquiry() { - hci_event_flag &= ~HCI_FLAG_WII_FOUND; + hci_event_flag &= ~HCI_FLAG_DEVICE_FOUND; hcibuf[0] = 0x01; hcibuf[1] = 0x01 << 2; // HCI OGF = 1 hcibuf[2] = 0x05; // Parameter Total Length = 5 diff --git a/BTD.h b/BTD.h index efaf8376..c419a252 100755 --- a/BTD.h +++ b/BTD.h @@ -39,25 +39,25 @@ #define HID_REQUEST_SET_REPORT 0x09 /* Bluetooth HCI states for hci_task() */ -#define HCI_INIT_STATE 0 -#define HCI_RESET_STATE 1 -#define HCI_CLASS_STATE 2 -#define HCI_BDADDR_STATE 3 -#define HCI_LOCAL_VERSION_STATE 4 -#define HCI_SET_NAME_STATE 5 -#define HCI_CHECK_WII_SERVICE 6 +#define HCI_INIT_STATE 0 +#define HCI_RESET_STATE 1 +#define HCI_CLASS_STATE 2 +#define HCI_BDADDR_STATE 3 +#define HCI_LOCAL_VERSION_STATE 4 +#define HCI_SET_NAME_STATE 5 +#define HCI_CHECK_DEVICE_SERVICE 6 -#define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a Wii controller -#define HCI_CONNECT_WII_STATE 8 -#define HCI_CONNECTED_WII_STATE 9 +#define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a Wii controller +#define HCI_CONNECT_DEVICE_STATE 8 +#define HCI_CONNECTED_DEVICE_STATE 9 -#define HCI_SCANNING_STATE 10 -#define HCI_CONNECT_IN_STATE 11 -#define HCI_REMOTE_NAME_STATE 12 -#define HCI_CONNECTED_STATE 13 -#define HCI_DISABLE_SCAN_STATE 14 -#define HCI_DONE_STATE 15 -#define HCI_DISCONNECT_STATE 16 +#define HCI_SCANNING_STATE 10 +#define HCI_CONNECT_IN_STATE 11 +#define HCI_REMOTE_NAME_STATE 12 +#define HCI_CONNECTED_STATE 13 +#define HCI_DISABLE_SCAN_STATE 14 +#define HCI_DONE_STATE 15 +#define HCI_DISCONNECT_STATE 16 /* HCI event flags*/ #define HCI_FLAG_CMD_COMPLETE 0x01 @@ -67,7 +67,7 @@ #define HCI_FLAG_INCOMING_REQUEST 0x10 #define HCI_FLAG_READ_BDADDR 0x20 #define HCI_FLAG_READ_VERSION 0x40 -#define HCI_FLAG_WII_FOUND 0x80 +#define HCI_FLAG_DEVICE_FOUND 0x80 #define HCI_FLAG_CONNECT_EVENT 0x100 /*Macros for HCI event flag tests */ @@ -78,7 +78,7 @@ #define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST) #define hci_read_bdaddr_complete (hci_event_flag & HCI_FLAG_READ_BDADDR) #define hci_read_version_complete (hci_event_flag & HCI_FLAG_READ_VERSION) -#define hci_wii_found (hci_event_flag & HCI_FLAG_WII_FOUND) +#define hci_device_found (hci_event_flag & HCI_FLAG_DEVICE_FOUND) #define hci_connect_event (hci_event_flag & HCI_FLAG_CONNECT_EVENT) /* HCI Events managed */ @@ -133,6 +133,8 @@ #define BTD_MAX_ENDPOINTS 4 #define BTD_NUMSERVICES 4 // Max number of Bluetooth services - if you need more than four simply increase this number +#define PAIR 1 + /** All Bluetooth services should include this class. */ class BluetoothService { public: @@ -422,19 +424,31 @@ public: /** Call this function to pair with a Wiimote */ void pairWithWiimote() { pairWithWii = true; - hci_state = HCI_CHECK_WII_SERVICE; + hci_state = HCI_CHECK_DEVICE_SERVICE; }; /** Used to only send the ACL data to the wiimote. */ bool connectToWii; /** True if a Wiimote is connecting. */ bool incomingWii; - /** True when it should pair with the incoming Wiimote. */ + /** True when it should pair with a Wiimote. */ bool pairWithWii; /** True if it's the new Wiimote with the Motion Plus Inside or a Wii U Pro Controller. */ bool motionPlusInside; /** True if it's a Wii U Pro Controller. */ bool wiiUProController; + /** Call this function to pair with a Wiimote */ + void pairWithHID() { + pairWithHIDDevice = true; + hci_state = HCI_CHECK_DEVICE_SERVICE; + }; + /** Used to only send the ACL data to the wiimote. */ + bool connectToHIDDevice; + /** True if a Wiimote is connecting. */ + bool incomingHIDDevice; + /** True when it should pair with a device like a mouse or keyboard. */ + bool pairWithHIDDevice; + /** * Read the poll interval taken from the endpoint descriptors. * @return The poll interval in ms. diff --git a/BTHID.cpp b/BTHID.cpp new file mode 100644 index 00000000..848cf12f --- /dev/null +++ b/BTHID.cpp @@ -0,0 +1,410 @@ +/* Copyright (C) 2013 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 "BTHID.h" +// To enable serial debugging see "settings.h" +//#define EXTRADEBUG // Uncomment to get even more debugging data +//#define PRINTREPORT // Uncomment to print the report send by the Wii controllers + +const uint8_t BUTTONS[] PROGMEM = { // Mouse buttons + 0x04, // MIDDLE + 0x02, // RIGHT + 0, // Skip + 0x01, // LEFT +}; + +BTHID::BTHID(BTD *p, bool pair, const char *pin) : +pBtd(p) // pointer to USB class instance - mandatory +{ + if (pBtd) + pBtd->registerServiceClass(this); // Register it as a Bluetooth service + + pBtd->pairWithHIDDevice = pair; + + if (pair) + pBtd->btdPin= pin; + + /* Set device cid for the control and intterrupt channelse - LSB */ + control_dcid[0] = 0x70; // 0x0070 + control_dcid[1] = 0x00; + interrupt_dcid[0] = 0x71; // 0x0071 + interrupt_dcid[1] = 0x00; + + Reset(); +} + +void BTHID::Reset() { + connected = false; + activeConnection = false; + l2cap_event_flag = 0; // Reset flags + l2cap_state = L2CAP_WAIT; +} + +void BTHID::disconnect() { // Use this void to disconnect any of the controllers + // First the HID interrupt channel has to be disconnected, 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 BTHID::ACLData(uint8_t* l2capinbuf) { + if (!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) { + if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { + pBtd->incomingHIDDevice = 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 + if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U + if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80); + D_PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[17], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[16], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[14], 0x80); +#endif + } 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 + //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80); + 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]) { + //Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80); + 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_CONNECTION_REQUEST) { +#ifdef EXTRADEBUG + Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80); + D_PrintHex (l2capinbuf[13], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[12], 0x80); + Notify(PSTR(" SCID: "), 0x80); + D_PrintHex (l2capinbuf[15], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[14], 0x80); + Notify(PSTR(" Identifier: "), 0x80); + D_PrintHex (l2capinbuf[9], 0x80); +#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; + } + } 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]) { + //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS; + } else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { + //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80); + 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]) { + //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80); + pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid); + } else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { + //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80); + 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_USB_HOST + Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80); +#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_USB_HOST + Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80); +#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]) { + //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE; + } else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { + //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80); + identifier = l2capinbuf[9]; + l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE; + } + } +#ifdef EXTRADEBUG + else { + identifier = l2capinbuf[9]; + Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); + D_PrintHex (l2capinbuf[8], 0x80); + } +#endif + } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt + //Notify(PSTR("\r\n\r\nL2CAP Interrupt: "), 0x80); +#ifdef PRINTREPORT + Notify(PSTR("\r\n"), 0x80); + for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { + D_PrintHex (l2capinbuf[i + 8], 0x80); + Notifyc(' ', 0x80); + } +#endif + if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT + switch (l2capinbuf[9]) { + case 0x01: // Keyboard events + break; + + case 0x02: // Mouse events + case 0x1A: + ButtonState = l2capinbuf[10]; + /*xAxis = l2capinbuf[11] | ((int16_t)l2capinbuf[12] << 8); + yAxis = l2capinbuf[13] | ((int16_t)l2capinbuf[14] << 8); + scroll = l2capinbuf[15] | ((int16_t)l2capinbuf[16] << 8);*/ + + if (ButtonState != OldButtonState) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; + } + break; + case 0x03: +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nChange mode event: "), 0x80); + D_PrintHex (l2capinbuf[11], 0x80); +#endif + break; +#ifdef DEBUG_USB_HOST + default: + Notify(PSTR("\r\nUnknown Report type: "), 0x80); + D_PrintHex (l2capinbuf[9], 0x80); + break; +#endif + } + } + } +#ifdef EXTRADEBUG + else { + Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80); + D_PrintHex (l2capinbuf[7], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (l2capinbuf[6], 0x80); + + Notify(PSTR("\r\nData: "), 0x80); + Notify(PSTR("\r\n"), 0x80); + for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { + D_PrintHex (l2capinbuf[i + 8], 0x80); + Notifyc(' ', 0x80); + } + } +#endif + L2CAP_task(); + } +} + +void BTHID::L2CAP_task() { + switch (l2cap_state) { + /* These states are used if the Wiimote is the host */ + case L2CAP_CONTROL_SUCCESS: + if (l2cap_config_success_control_flag) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); +#endif + l2cap_state = L2CAP_INTERRUPT_SETUP; + } + break; + + case L2CAP_INTERRUPT_SETUP: + if (l2cap_connection_request_interrupt_flag) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80); +#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 */ + case L2CAP_CONTROL_CONNECT_REQUEST: + if (l2cap_connected_control_flag) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSend HID Control Config Request"), 0x80); +#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_USB_HOST + Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); +#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_USB_HOST + Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80); +#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) { // Now the HID channels is established +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nHID Channels Established"), 0x80); +#endif + pBtd->connectToHIDDevice = false; + pBtd->pairWithHIDDevice = false; + connected = true; + setProtocol(); + onInit(); + l2cap_state = L2CAP_DONE; + } + break; + + case L2CAP_DONE: + break; + + case L2CAP_INTERRUPT_DISCONNECT: + if (l2cap_disconnect_response_interrupt_flag) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80); +#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_USB_HOST + Notify(PSTR("\r\nDisconnected Control Channel"), 0x80); +#endif + pBtd->hci_disconnect(hci_handle); + hci_handle = -1; // Reset handle + l2cap_event_flag = 0; // Reset flags + l2cap_state = L2CAP_WAIT; + } + break; + } +} + +void BTHID::Run() { + switch (l2cap_state) { + case L2CAP_WAIT: + if (pBtd->connectToHIDDevice && !pBtd->l2capConnectionClaimed && !connected && !activeConnection) { + pBtd->l2capConnectionClaimed = true; + activeConnection = true; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80); +#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; + } else if (l2cap_connection_request_control_flag) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80); +#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; + } + break; + } +} + +/************************************************************/ +/* HID Commands */ +/************************************************************/ +void BTHID::setProtocol() { + uint8_t command = 0x71; // Set Protocol to "Report Protocol Mode", see HID specs page 33 + pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]); +} + +/************************************************************/ +/* BT HID Commands */ +/************************************************************/ + +bool BTHID::getButtonPress(Button b) { // Return true when a button is pressed + return (bool)((ButtonState & pgm_read_byte(&BUTTONS[(uint8_t)b]))); +} + +bool BTHID::getButtonClick(Button b) { // Only return true when a button is clicked + uint8_t button = pgm_read_byte(&BUTTONS[(uint8_t)b]); + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // Clear "click" event + return click; +} + +void BTHID::onInit() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else { + // Do nothing + } +} \ No newline at end of file diff --git a/BTHID.h b/BTHID.h new file mode 100644 index 00000000..a62193a0 --- /dev/null +++ b/BTHID.h @@ -0,0 +1,162 @@ +/* Copyright (C) 2013 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 + */ + +#ifndef _bthid_h_ +#define _bthid_h_ + +#include "BTD.h" +#include "controllerEnums.h" + +/* Bluetooth L2CAP states for L2CAP_task() */ +#define L2CAP_WAIT 0 + +// These states are used if the device is the host +#define L2CAP_CONTROL_SUCCESS 1 +#define L2CAP_INTERRUPT_SETUP 2 + +// These states are used if the Arduino is the host +#define L2CAP_CONTROL_CONNECT_REQUEST 3 +#define L2CAP_CONTROL_CONFIG_REQUEST 4 +#define L2CAP_INTERRUPT_CONNECT_REQUEST 5 + +#define L2CAP_INTERRUPT_CONFIG_REQUEST 6 +#define L2CAP_DONE 7 + +#define L2CAP_INTERRUPT_DISCONNECT 8 +#define L2CAP_CONTROL_DISCONNECT 9 + +/* L2CAP event flags */ +#define L2CAP_FLAG_CONTROL_CONNECTED 0x01 +#define L2CAP_FLAG_INTERRUPT_CONNECTED 0x02 +#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS 0x04 +#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS 0x08 +#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE 0x10 +#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE 0x20 +#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST 0x40 +#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST 0x80 + +/* Macros for L2CAP event flag tests */ +#define l2cap_connected_control_flag (l2cap_event_flag & L2CAP_FLAG_CONTROL_CONNECTED) +#define l2cap_connected_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_INTERRUPT_CONNECTED) +#define l2cap_config_success_control_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_CONTROL_SUCCESS) +#define l2cap_config_success_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS) +#define l2cap_disconnect_response_control_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE) +#define l2cap_disconnect_response_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE) +#define l2cap_connection_request_control_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_CONTROL_REQUEST) +#define l2cap_connection_request_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST) + +/** This BluetoothService class implements support for the HID keyboard and mice. */ +class BTHID : public BluetoothService { +public: + /** + * Constructor for the BTHID class. + * @param p Pointer to the BTD class instance. + * @param pair Set this to true in order to pair with the device. If the argument is omitted then it will not pair with it. One can use ::PAIR to set it to true. + * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used. + */ + BTHID(BTD *p, bool pair = false, const char *pin = "1234"); + + /** @name BluetoothService implementation */ + /** + * Used to pass acldata to the services. + * @param ACLData Incoming acldata. + */ + virtual void ACLData(uint8_t* ACLData); + /** Used to run part of the state maschine. */ + virtual void Run(); + /** Use this to reset the service. */ + virtual void Reset(); + /** Used this to disconnect any of the controllers. */ + virtual void disconnect(); + /**@}*/ + + /** True if a device is connected */ + bool connected; + + /** @name HID mouse functions */ + /** + * getButtonPress(Button b) will return true as long as the button is held down. + * + * While getButtonClick(Button b) will only return it once. + * + * So you instance if you need to increase a variable once you would use getButtonClick(Button b), + * but if you need to drive a robot forward you would use getButtonPress(Button b). + */ + bool getButtonPress(Button b); + bool getButtonClick(Button b); + /**@}*/ + /** @name HID mouse functions */ + /*int16_t getXaxis() { + return xAxis; + } + int16_t getYaxis() { + return yAxis; + } + int16_t getScroll() { + return scroll; + }*/ + /**@}*/ + + /** Call this to start the paring sequence with a controller */ + void pair(void) { + if (pBtd) + pBtd->pairWithHID(); + } + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + +private: + BTD *pBtd; // Pointer to BTD instance + + /** Set report protocol. */ + void setProtocol(); + + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void onInit(); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + + void L2CAP_task(); // L2CAP state machine + + /* Variables filled from HCI event management */ + uint16_t hci_handle; + bool activeConnection; // Used to indicate if it's already has established a connection + + /* Variables used by high level L2CAP task */ + uint8_t l2cap_state; + uint8_t l2cap_event_flag; // l2cap flags of received Bluetooth events + + uint8_t ButtonState, OldButtonState, ButtonClickState; + int16_t xAxis, yAxis, scroll; + + /* L2CAP Channels */ + uint8_t control_scid[2]; // L2CAP source CID for HID_Control + uint8_t control_dcid[2]; // 0x0070 + uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt + uint8_t interrupt_dcid[2]; // 0x0071 + uint8_t identifier; // Identifier for connection +}; +#endif \ No newline at end of file diff --git a/Wii.h b/Wii.h index f8d206ef..397b837f 100755 --- a/Wii.h +++ b/Wii.h @@ -76,8 +76,6 @@ #define motion_plus_connected_flag (l2cap_event_flag & WII_FLAG_MOTION_PLUS_CONNECTED) #define nunchuck_connected_flag (l2cap_event_flag & WII_FLAG_NUNCHUCK_CONNECTED) -#define PAIR 1 - /** Enum used to read the joystick on the Nunchuck. */ enum Hat { /** Read the x-axis on the Nunchuck joystick. */ diff --git a/controllerEnums.h b/controllerEnums.h index 5e0d6dc8..504594ef 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -103,6 +103,8 @@ enum Button { BLACK = 8, // Available on the original Xbox controller WHITE = 9, // Available on the original Xbox controller /**@}*/ + + MIDDLE = 0, // Middle mouse button }; /** Joysticks on the PS3 and Xbox controllers. */ diff --git a/examples/Bluetooth/BTHID/BTHID.ino b/examples/Bluetooth/BTHID/BTHID.ino new file mode 100644 index 00000000..b9c3da4b --- /dev/null +++ b/examples/Bluetooth/BTHID/BTHID.ino @@ -0,0 +1,37 @@ +/* + Example sketch for the HID 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 +#include + +USB Usb; +//USBHub Hub1(&Usb); // Some dongles have a hub inside + +BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so +/* You can create the instance of the class in two ways */ +BTHID hid(&Btd, PAIR, "0000"); // This will start an inquiry and then pair with your Wiimote - you only have to do this once +//BTHID hid(&Btd); // After that you can simply create the instance like so and then press any button on the Wiimote + +void setup() { + Serial.begin(115200); + while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection + if (Usb.Init() == -1) { + Serial.print(F("\r\nOSC did not start")); + while (1); //halt + } + Serial.print(F("\r\nHID Bluetooth Library Started")); +} +void loop() { + Usb.Task(); + if (hid.connected) { + if (hid.getButtonClick(LEFT)) // Print mouse buttons + Serial.println(F("Left")); + if (hid.getButtonClick(RIGHT)) + Serial.println(F("Right")); + if (hid.getButtonClick(MIDDLE)) + Serial.println(F("Middle")); + } +} diff --git a/keywords.txt b/keywords.txt index 6847bb09..6ea68e90 100644 --- a/keywords.txt +++ b/keywords.txt @@ -97,6 +97,7 @@ L3 LITERAL1 R3 LITERAL1 START LITERAL1 UP LITERAL1 +MIDDLE LITERAL1 RIGHT LITERAL1 DOWN LITERAL1 LEFT LITERAL1 From aba004b0479a9b03fc88dd3ebe1abf9821455266 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 24 Nov 2013 23:51:45 +0100 Subject: [PATCH 02/24] Use the HIDBoot class to parse the incoming data --- BTHID.cpp | 56 ++++------------ BTHID.h | 52 +++++++-------- examples/Bluetooth/BTHID/BTHID.ino | 34 ++++++---- examples/Bluetooth/BTHID/KeyboardParser.h | 78 +++++++++++++++++++++++ examples/Bluetooth/BTHID/MouseParser.h | 46 +++++++++++++ 5 files changed, 186 insertions(+), 80 deletions(-) create mode 100644 examples/Bluetooth/BTHID/KeyboardParser.h create mode 100644 examples/Bluetooth/BTHID/MouseParser.h diff --git a/BTHID.cpp b/BTHID.cpp index 848cf12f..d6fbb43c 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -18,18 +18,14 @@ #include "BTHID.h" // To enable serial debugging see "settings.h" //#define EXTRADEBUG // Uncomment to get even more debugging data -//#define PRINTREPORT // Uncomment to print the report send by the Wii controllers - -const uint8_t BUTTONS[] PROGMEM = { // Mouse buttons - 0x04, // MIDDLE - 0x02, // RIGHT - 0, // Skip - 0x01, // LEFT -}; +//#define PRINTREPORT // Uncomment to print the report send by the HID device BTHID::BTHID(BTD *p, bool pair, const char *pin) : pBtd(p) // pointer to USB class instance - mandatory { + for(uint8_t i = 0; i < epMUL; i++) + pRptParser[i] = NULL; + if (pBtd) pBtd->registerServiceClass(this); // Register it as a Bluetooth service @@ -196,22 +192,21 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT switch (l2capinbuf[9]) { case 0x01: // Keyboard events + if (pRptParser[KEYBOARD_PARSER_ID]) { + uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); + pRptParser[KEYBOARD_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]); + } break; case 0x02: // Mouse events case 0x1A: - ButtonState = l2capinbuf[10]; - /*xAxis = l2capinbuf[11] | ((int16_t)l2capinbuf[12] << 8); - yAxis = l2capinbuf[13] | ((int16_t)l2capinbuf[14] << 8); - scroll = l2capinbuf[15] | ((int16_t)l2capinbuf[16] << 8);*/ - - if (ButtonState != OldButtonState) { - ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable - OldButtonState = ButtonState; + if (pRptParser[MOUSE_PARSER_ID]) { + uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); + pRptParser[MOUSE_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]); } break; case 0x03: -#ifdef DEBUG_USB_HOST +#ifdef EXTRADEBUG Notify(PSTR("\r\nChange mode event: "), 0x80); D_PrintHex (l2capinbuf[11], 0x80); #endif @@ -246,7 +241,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { void BTHID::L2CAP_task() { switch (l2cap_state) { - /* These states are used if the Wiimote is the host */ + /* These states are used if the HID device is the host */ case L2CAP_CONTROL_SUCCESS: if (l2cap_config_success_control_flag) { #ifdef DEBUG_USB_HOST @@ -382,29 +377,6 @@ void BTHID::Run() { /* HID Commands */ /************************************************************/ void BTHID::setProtocol() { - uint8_t command = 0x71; // Set Protocol to "Report Protocol Mode", see HID specs page 33 + uint8_t command = 0x70 | protocolMode; // Set Protocol, see HID specs page 33 pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]); -} - -/************************************************************/ -/* BT HID Commands */ -/************************************************************/ - -bool BTHID::getButtonPress(Button b) { // Return true when a button is pressed - return (bool)((ButtonState & pgm_read_byte(&BUTTONS[(uint8_t)b]))); -} - -bool BTHID::getButtonClick(Button b) { // Only return true when a button is clicked - uint8_t button = pgm_read_byte(&BUTTONS[(uint8_t)b]); - bool click = (ButtonClickState & button); - ButtonClickState &= ~button; // Clear "click" event - return click; -} - -void BTHID::onInit() { - if (pFuncOnInit) - pFuncOnInit(); // Call the user function - else { - // Do nothing - } } \ No newline at end of file diff --git a/BTHID.h b/BTHID.h index a62193a0..cd6b58dc 100644 --- a/BTHID.h +++ b/BTHID.h @@ -20,6 +20,7 @@ #include "BTD.h" #include "controllerEnums.h" +#include "hidboot.h" /* Bluetooth L2CAP states for L2CAP_task() */ #define L2CAP_WAIT 0 @@ -59,6 +60,10 @@ #define l2cap_connection_request_control_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_CONTROL_REQUEST) #define l2cap_connection_request_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST) +#define KEYBOARD_PARSER_ID 0 +#define MOUSE_PARSER_ID 1 +#define epMUL 2 + /** This BluetoothService class implements support for the HID keyboard and mice. */ class BTHID : public BluetoothService { public: @@ -84,38 +89,27 @@ public: virtual void disconnect(); /**@}*/ + HIDReportParser *GetReportParser(uint8_t id) { + return pRptParser[id]; + }; + + bool SetReportParser(uint8_t id, HIDReportParser *prs) { + pRptParser[id] = prs; + return true; + }; + + void setProtocolMode(uint8_t mode) { + protocolMode = mode; + }; + /** True if a device is connected */ bool connected; - /** @name HID mouse functions */ - /** - * getButtonPress(Button b) will return true as long as the button is held down. - * - * While getButtonClick(Button b) will only return it once. - * - * So you instance if you need to increase a variable once you would use getButtonClick(Button b), - * but if you need to drive a robot forward you would use getButtonPress(Button b). - */ - bool getButtonPress(Button b); - bool getButtonClick(Button b); - /**@}*/ - /** @name HID mouse functions */ - /*int16_t getXaxis() { - return xAxis; - } - int16_t getYaxis() { - return yAxis; - } - int16_t getScroll() { - return scroll; - }*/ - /**@}*/ - /** Call this to start the paring sequence with a controller */ void pair(void) { if (pBtd) pBtd->pairWithHID(); - } + }; /** * Used to call your own function when the controller is successfully initialized. @@ -128,15 +122,21 @@ public: private: BTD *pBtd; // Pointer to BTD instance + HIDReportParser *pRptParser[epMUL]; + /** Set report protocol. */ void setProtocol(); + uint8_t protocolMode; /** * Called when the controller is successfully initialized. * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. * This is useful for instance if you want to set the LEDs in a specific way. */ - void onInit(); + void onInit() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + } void (*pFuncOnInit)(void); // Pointer to function called in onInit() void L2CAP_task(); // L2CAP state machine diff --git a/examples/Bluetooth/BTHID/BTHID.ino b/examples/Bluetooth/BTHID/BTHID.ino index b9c3da4b..fecc4b50 100644 --- a/examples/Bluetooth/BTHID/BTHID.ino +++ b/examples/Bluetooth/BTHID/BTHID.ino @@ -6,32 +6,42 @@ #include #include +#include "KeyboardParser.h" +#include "MouseParser.h" USB Usb; //USBHub Hub1(&Usb); // Some dongles have a hub inside - BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so + /* You can create the instance of the class in two ways */ -BTHID hid(&Btd, PAIR, "0000"); // This will start an inquiry and then pair with your Wiimote - you only have to do this once -//BTHID hid(&Btd); // After that you can simply create the instance like so and then press any button on the Wiimote +// This will start an inquiry and then pair with your device - you only have to do this once +// If you are using a Bluetooth keyboard, then you should type in the password on the keypad and then press enter +BTHID hid(&Btd, PAIR, "0000"); + +// After that you can simply create the instance like so and then press any button on the device +//BTHID hid(&Btd); + +KbdRptParser keyboardPrs; +MouseRptParser mousePrs; void setup() { Serial.begin(115200); while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection if (Usb.Init() == -1) { Serial.print(F("\r\nOSC did not start")); - while (1); //halt + while (1); // Halt } + + hid.SetReportParser(KEYBOARD_PARSER_ID, (HIDReportParser*)&keyboardPrs); + hid.SetReportParser(MOUSE_PARSER_ID, (HIDReportParser*)&mousePrs); + + // If "Boot Protocol Mode" does not work, then try "Report Protocol Mode" + // If that does not work either, then uncomment PRINTREPORT in BTHID.cpp to see the raw report + hid.setProtocolMode(HID_BOOT_PROTOCOL); // Boot Protocol Mode + //hid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode + Serial.print(F("\r\nHID Bluetooth Library Started")); } void loop() { Usb.Task(); - if (hid.connected) { - if (hid.getButtonClick(LEFT)) // Print mouse buttons - Serial.println(F("Left")); - if (hid.getButtonClick(RIGHT)) - Serial.println(F("Right")); - if (hid.getButtonClick(MIDDLE)) - Serial.println(F("Middle")); - } } diff --git a/examples/Bluetooth/BTHID/KeyboardParser.h b/examples/Bluetooth/BTHID/KeyboardParser.h new file mode 100644 index 00000000..1054cac0 --- /dev/null +++ b/examples/Bluetooth/BTHID/KeyboardParser.h @@ -0,0 +1,78 @@ +#ifndef __kbdrptparser_h_ +#define __kbdrptparser_h_ + +class KbdRptParser : public KeyboardReportParser { + private: + void PrintKey(uint8_t mod, uint8_t key); + + protected: + virtual void OnControlKeysChanged(uint8_t before, uint8_t after); + virtual void OnKeyDown(uint8_t mod, uint8_t key); + virtual void OnKeyUp(uint8_t mod, uint8_t key); + virtual void OnKeyPressed(uint8_t key); +}; + +void KbdRptParser::PrintKey(uint8_t m, uint8_t key) { + MODIFIERKEYS mod; + *((uint8_t*)&mod) = m; + Serial.print((mod.bmLeftCtrl == 1) ? F("C") : F(" ")); + Serial.print((mod.bmLeftShift == 1) ? F("S") : F(" ")); + Serial.print((mod.bmLeftAlt == 1) ? F("A") : F(" ")); + Serial.print((mod.bmLeftGUI == 1) ? F("G") : F(" ")); + + Serial.print(F(" >")); + PrintHex(key, 0x80); + Serial.print(F("< ")); + + Serial.print((mod.bmRightCtrl == 1) ? F("C") : F(" ")); + Serial.print((mod.bmRightShift == 1) ? F("S") : F(" ")); + Serial.print((mod.bmRightAlt == 1) ? F("A") : F(" ")); + Serial.println((mod.bmRightGUI == 1) ? F("G") : F(" ")); +}; + +void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) { + Serial.print(F("DN ")); + PrintKey(mod, key); + uint8_t c = OemToAscii(mod, key); + + if (c) + OnKeyPressed(c); +} + +void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) { + MODIFIERKEYS beforeMod; + *((uint8_t*)&beforeMod) = before; + + MODIFIERKEYS afterMod; + *((uint8_t*)&afterMod) = after; + + if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) + Serial.println(F("LeftCtrl changed")); + if (beforeMod.bmLeftShift != afterMod.bmLeftShift) + Serial.println(F("LeftShift changed")); + if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) + Serial.println(F("LeftAlt changed")); + if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) + Serial.println(F("LeftGUI changed")); + + if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) + Serial.println(F("RightCtrl changed")); + if (beforeMod.bmRightShift != afterMod.bmRightShift) + Serial.println(F("RightShift changed")); + if (beforeMod.bmRightAlt != afterMod.bmRightAlt) + Serial.println(F("RightAlt changed")); + if (beforeMod.bmRightGUI != afterMod.bmRightGUI) + Serial.println(F("RightGUI changed")); +} + +void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) { + Serial.print(F("UP ")); + PrintKey(mod, key); +} + +void KbdRptParser::OnKeyPressed(uint8_t key) { + Serial.print(F("ASCII: ")); + Serial.println((char)key); +}; + +#endif diff --git a/examples/Bluetooth/BTHID/MouseParser.h b/examples/Bluetooth/BTHID/MouseParser.h new file mode 100644 index 00000000..a9245ded --- /dev/null +++ b/examples/Bluetooth/BTHID/MouseParser.h @@ -0,0 +1,46 @@ +#ifndef __mouserptparser_h__ +#define __mouserptparser_h__ + +class MouseRptParser : public MouseReportParser { + protected: + virtual void OnMouseMove(MOUSEINFO *mi); + virtual void OnLeftButtonUp(MOUSEINFO *mi); + virtual void OnLeftButtonDown(MOUSEINFO *mi); + virtual void OnRightButtonUp(MOUSEINFO *mi); + virtual void OnRightButtonDown(MOUSEINFO *mi); + virtual void OnMiddleButtonUp(MOUSEINFO *mi); + virtual void OnMiddleButtonDown(MOUSEINFO *mi); +}; + +void MouseRptParser::OnMouseMove(MOUSEINFO *mi) { + Serial.print(F("dx=")); + Serial.print(mi->dX, DEC); + Serial.print(F(" dy=")); + Serial.println(mi->dY, DEC); +}; + +void MouseRptParser::OnLeftButtonUp(MOUSEINFO *mi) { + Serial.println(F("L Butt Up")); +}; + +void MouseRptParser::OnLeftButtonDown(MOUSEINFO *mi) { + Serial.println(F("L Butt Dn")); +}; + +void MouseRptParser::OnRightButtonUp(MOUSEINFO *mi) { + Serial.println(F("R Butt Up")); +}; + +void MouseRptParser::OnRightButtonDown(MOUSEINFO *mi) { + Serial.println(F("R Butt Dn")); +}; + +void MouseRptParser::OnMiddleButtonUp(MOUSEINFO *mi) { + Serial.println(F("M Butt Up")); +}; + +void MouseRptParser::OnMiddleButtonDown(MOUSEINFO *mi) { + Serial.println(F("M Butt Dn")); +}; + +#endif From 69dbf06beab3bf50d0e40024ace2aea847c8cd34 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 24 Nov 2013 23:54:59 +0100 Subject: [PATCH 03/24] Updated keywords --- controllerEnums.h | 2 -- keywords.txt | 24 ++++++++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/controllerEnums.h b/controllerEnums.h index 504594ef..5e0d6dc8 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -103,8 +103,6 @@ enum Button { BLACK = 8, // Available on the original Xbox controller WHITE = 9, // Available on the original Xbox controller /**@}*/ - - MIDDLE = 0, // Middle mouse button }; /** Joysticks on the PS3 and Xbox controllers. */ diff --git a/keywords.txt b/keywords.txt index 6ea68e90..b3906513 100644 --- a/keywords.txt +++ b/keywords.txt @@ -19,6 +19,11 @@ USBHub KEYWORD1 BTD KEYWORD1 +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### +Task KEYWORD2 + #################################################### # Syntax Coloring Map For PS3 Bluetooth/USB Library #################################################### @@ -97,7 +102,6 @@ L3 LITERAL1 R3 LITERAL1 START LITERAL1 UP LITERAL1 -MIDDLE LITERAL1 RIGHT LITERAL1 DOWN LITERAL1 LEFT LITERAL1 @@ -293,4 +297,20 @@ getIRy3 KEYWORD2 getIRs3 KEYWORD2 getIRx4 KEYWORD2 getIRy4 KEYWORD2 -getIRs4 KEYWORD2 \ No newline at end of file +getIRs4 KEYWORD2 + +#################################################### +# Syntax Coloring Map For RFCOMM/SPP Library +#################################################### + +#################################################### +# Datatypes (KEYWORD1) +#################################################### + +BTHID KEYWORD1 + +#################################################### +# Methods and Functions (KEYWORD2) +#################################################### +SetReportParser KEYWORD2 +setProtocolMode KEYWORD2 \ No newline at end of file From f8c948f132cd480b469af10e093d2f095b616560 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 00:25:25 +0100 Subject: [PATCH 04/24] Added information about BTHID library --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 361caf1a..c36fb8e4 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir * __Alexei Glushchenko, Circuits@Home__ - * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries * __Kristian Lauszus, TKJ Electronics__ - - * Developer of the [BTD](#bluetooth-libraries), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries + * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries * __Andrew Kroll__ - * Major contributor to mass storage code @@ -86,7 +86,15 @@ This library make it easy to add support for different Bluetooth services like a Some different examples can be found in the [example directory](examples/Bluetooth). The BTD library will also make it possible to use multiple services at once, the following example sketch is an example of this: - +. + +### [BTHID library](BTHID.cpp) + +The [Bluetooth HID library](BTHID.cpp) allows you to connect HID devices via Bluetooth to the USB Host Shield. + +Currently HID mice and keyboards are supported. + +It uses the standard BOOT protocol, but it is very easy to modify it for your device, you simply have do edit the parser. See the example: for more information. ### [SPP library](SPP.cpp) From 27b8656f9165cb144ac1bc882ddf14fed5e1d5a4 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 00:31:42 +0100 Subject: [PATCH 05/24] Added information about how to change protocol mode --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c36fb8e4..c96ac1d9 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ The [Bluetooth HID library](BTHID.cpp) allows you to connect HID devices via Blu Currently HID mice and keyboards are supported. -It uses the standard BOOT protocol, but it is very easy to modify it for your device, you simply have do edit the parser. See the example: for more information. +It uses the standard Boot protocol by default, but it able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: for more information. ### [SPP library](SPP.cpp) From 0735774a4666b73ff7c723b99582d0bfe0010f79 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 00:32:06 +0100 Subject: [PATCH 06/24] Forgot to init protocolMode --- BTHID.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BTHID.cpp b/BTHID.cpp index d6fbb43c..de7b485d 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -21,7 +21,8 @@ //#define PRINTREPORT // Uncomment to print the report send by the HID device BTHID::BTHID(BTD *p, bool pair, const char *pin) : -pBtd(p) // pointer to USB class instance - mandatory +pBtd(p), // pointer to USB class instance - mandatory +protocolMode(HID_BOOT_PROTOCOL) { for(uint8_t i = 0; i < epMUL; i++) pRptParser[i] = NULL; From 1b9c3952ac838f5391b3f55a9bbaa70fa90dd33e Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 00:33:44 +0100 Subject: [PATCH 07/24] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c96ac1d9..9907d2d3 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ The [Bluetooth HID library](BTHID.cpp) allows you to connect HID devices via Blu Currently HID mice and keyboards are supported. -It uses the standard Boot protocol by default, but it able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: for more information. +It uses the standard Boot protocol by default, but it is also able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: for more information. ### [SPP library](SPP.cpp) From 45465fa9280635a83bb1ae38735512f6df3e2742 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 00:43:47 +0100 Subject: [PATCH 08/24] Fixed comment --- PS3USB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PS3USB.h b/PS3USB.h index ae5314f4..82559acd 100644 --- a/PS3USB.h +++ b/PS3USB.h @@ -140,7 +140,7 @@ public: void getMoveBdaddr(uint8_t *bdaddr); /** * Used to get the calibration data inside the Move controller. - * @param bdaddr Buffer to store data in. Must be at least 147 bytes + * @param data Buffer to store data in. Must be at least 147 bytes */ void getMoveCalibration(uint8_t *data); From 40993141004b215fa1b2b8da10e52e1d44505873 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 01:45:24 +0100 Subject: [PATCH 09/24] Can now set the LEDs on a keyboard --- BTHID.cpp | 8 ++++++ BTHID.h | 3 +++ examples/Bluetooth/BTHID/BTHID.ino | 2 +- examples/Bluetooth/BTHID/KeyboardParser.h | 33 +++++++++++++++++++++-- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index de7b485d..2fe77163 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -380,4 +380,12 @@ void BTHID::Run() { void BTHID::setProtocol() { uint8_t command = 0x70 | protocolMode; // Set Protocol, see HID specs page 33 pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]); +} + +void BTHID::setLeds(uint8_t data) { + uint8_t buf[3]; + buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) + buf[1] = 0x01; // Report ID + buf[2] = data; + pBtd->L2CAP_Command(hci_handle, buf, 3, interrupt_scid[0], interrupt_scid[1]); } \ No newline at end of file diff --git a/BTHID.h b/BTHID.h index cd6b58dc..c26de15b 100644 --- a/BTHID.h +++ b/BTHID.h @@ -102,6 +102,9 @@ public: protocolMode = mode; }; + /** Used to set the leds on a keyboard */ + void setLeds(uint8_t data); + /** True if a device is connected */ bool connected; diff --git a/examples/Bluetooth/BTHID/BTHID.ino b/examples/Bluetooth/BTHID/BTHID.ino index fecc4b50..444cc8d2 100644 --- a/examples/Bluetooth/BTHID/BTHID.ino +++ b/examples/Bluetooth/BTHID/BTHID.ino @@ -21,7 +21,7 @@ BTHID hid(&Btd, PAIR, "0000"); // After that you can simply create the instance like so and then press any button on the device //BTHID hid(&Btd); -KbdRptParser keyboardPrs; +KbdRptParser keyboardPrs(&hid); MouseRptParser mousePrs; void setup() { diff --git a/examples/Bluetooth/BTHID/KeyboardParser.h b/examples/Bluetooth/BTHID/KeyboardParser.h index 1054cac0..0d8c081d 100644 --- a/examples/Bluetooth/BTHID/KeyboardParser.h +++ b/examples/Bluetooth/BTHID/KeyboardParser.h @@ -2,16 +2,45 @@ #define __kbdrptparser_h_ class KbdRptParser : public KeyboardReportParser { - private: - void PrintKey(uint8_t mod, uint8_t key); + public: + KbdRptParser(BTHID *p) : pBTHID(p) {}; protected: + virtual uint8_t HandleLockingKeys(HID* hid, uint8_t key); virtual void OnControlKeysChanged(uint8_t before, uint8_t after); virtual void OnKeyDown(uint8_t mod, uint8_t key); virtual void OnKeyUp(uint8_t mod, uint8_t key); virtual void OnKeyPressed(uint8_t key); + + private: + void PrintKey(uint8_t mod, uint8_t key); + BTHID *pBTHID; }; +uint8_t KbdRptParser::HandleLockingKeys(HID* hid, uint8_t key) { + uint8_t old_keys = kbdLockingKeys.bLeds; + + switch (key) { + case KEY_NUM_LOCK: + Serial.println(F("Num lock")); + kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock; + break; + case KEY_CAPS_LOCK: + Serial.println(F("Caps lock")); + kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock; + break; + case KEY_SCROLL_LOCK: + Serial.println(F("Scroll lock")); + kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock; + break; + } + + if (old_keys != kbdLockingKeys.bLeds && pBTHID) + pBTHID->setLeds(kbdLockingKeys.bLeds); + + return 0; +} + void KbdRptParser::PrintKey(uint8_t m, uint8_t key) { MODIFIERKEYS mod; *((uint8_t*)&mod) = m; From 253b43c06fdd87b03165c86828ef0d1b4493fb20 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 02:15:33 +0100 Subject: [PATCH 10/24] Set protocol before establishing interrupt channel --- BTHID.cpp | 23 ++++++++++++++++------- BTHID.h | 13 +++++++------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index 2fe77163..7820d2d5 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -248,6 +248,7 @@ void BTHID::L2CAP_task() { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); #endif + setProtocol(); l2cap_state = L2CAP_INTERRUPT_SETUP; } break; @@ -276,19 +277,24 @@ void BTHID::L2CAP_task() { #endif identifier++; pBtd->l2cap_config_request(hci_handle, identifier, control_scid); + l2cap_state = L2CAP_SET_PROTOCOL; + } + break; + + case L2CAP_SET_PROTOCOL: + if (l2cap_config_success_control_flag) { + setProtocol(); l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST; } break; case L2CAP_CONTROL_CONFIG_REQUEST: - if (l2cap_config_success_control_flag) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); + Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); #endif - identifier++; - pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM); - l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST; - } + 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: @@ -310,7 +316,6 @@ void BTHID::L2CAP_task() { pBtd->connectToHIDDevice = false; pBtd->pairWithHIDDevice = false; connected = true; - setProtocol(); onInit(); l2cap_state = L2CAP_DONE; } @@ -378,6 +383,10 @@ void BTHID::Run() { /* HID Commands */ /************************************************************/ void BTHID::setProtocol() { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSet protocol mode: "), 0x80); + D_PrintHex (protocolMode, 0x80); +#endif uint8_t command = 0x70 | protocolMode; // Set Protocol, see HID specs page 33 pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]); } diff --git a/BTHID.h b/BTHID.h index c26de15b..e6e168b6 100644 --- a/BTHID.h +++ b/BTHID.h @@ -31,14 +31,15 @@ // These states are used if the Arduino is the host #define L2CAP_CONTROL_CONNECT_REQUEST 3 -#define L2CAP_CONTROL_CONFIG_REQUEST 4 -#define L2CAP_INTERRUPT_CONNECT_REQUEST 5 +#define L2CAP_SET_PROTOCOL 4 +#define L2CAP_CONTROL_CONFIG_REQUEST 5 +#define L2CAP_INTERRUPT_CONNECT_REQUEST 6 -#define L2CAP_INTERRUPT_CONFIG_REQUEST 6 -#define L2CAP_DONE 7 +#define L2CAP_INTERRUPT_CONFIG_REQUEST 7 +#define L2CAP_DONE 8 -#define L2CAP_INTERRUPT_DISCONNECT 8 -#define L2CAP_CONTROL_DISCONNECT 9 +#define L2CAP_INTERRUPT_DISCONNECT 9 +#define L2CAP_CONTROL_DISCONNECT 10 /* L2CAP event flags */ #define L2CAP_FLAG_CONTROL_CONNECTED 0x01 From eed70438be985a529838a2561c223970a90ec829 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 02:20:57 +0100 Subject: [PATCH 11/24] =?UTF-8?q?Set=20default=20pin=20to=20=E2=80=9C0000?= =?UTF-8?q?=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BTHID.h | 4 ++-- SPP.h | 4 ++-- examples/Bluetooth/PS3SPP/PS3SPP.ino | 2 +- examples/Bluetooth/SPPMulti/SPPMulti.ino | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/BTHID.h b/BTHID.h index e6e168b6..21b92720 100644 --- a/BTHID.h +++ b/BTHID.h @@ -72,9 +72,9 @@ public: * Constructor for the BTHID class. * @param p Pointer to the BTD class instance. * @param pair Set this to true in order to pair with the device. If the argument is omitted then it will not pair with it. One can use ::PAIR to set it to true. - * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used. + * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used. */ - BTHID(BTD *p, bool pair = false, const char *pin = "1234"); + BTHID(BTD *p, bool pair = false, const char *pin = "0000"); /** @name BluetoothService implementation */ /** diff --git a/SPP.h b/SPP.h index 558f16bc..a38014f0 100644 --- a/SPP.h +++ b/SPP.h @@ -96,9 +96,9 @@ public: * Constructor for the SPP class. * @param p Pointer to BTD class instance. * @param name Set the name to BTD#btdName. If argument is omitted, then "Arduino" will be used. - * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "1234" will be used. + * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used. */ - SPP(BTD *p, const char* name = "Arduino", const char* pin = "1234"); + SPP(BTD *p, const char *name = "Arduino", const char *pin = "0000"); /** * Used to provide Boolean tests for the class. diff --git a/examples/Bluetooth/PS3SPP/PS3SPP.ino b/examples/Bluetooth/PS3SPP/PS3SPP.ino index 214ce26a..3f9af1f3 100644 --- a/examples/Bluetooth/PS3SPP/PS3SPP.ino +++ b/examples/Bluetooth/PS3SPP/PS3SPP.ino @@ -19,7 +19,7 @@ USB Usb; BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so /* You can create the instances of the bluetooth services in two ways */ -SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "1234" +SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "0000" //SPP SerialBTBT(&Btd,"Lauszus's Arduino","0000"); // You can also set the name and pin like so PS3BT PS3(&Btd); // This will just create the instance //PS3BT PS3(&Btd,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch diff --git a/examples/Bluetooth/SPPMulti/SPPMulti.ino b/examples/Bluetooth/SPPMulti/SPPMulti.ino index af32fd85..3388bd7b 100644 --- a/examples/Bluetooth/SPPMulti/SPPMulti.ino +++ b/examples/Bluetooth/SPPMulti/SPPMulti.ino @@ -18,7 +18,7 @@ uint8_t buffer[50]; void setup() { for (uint8_t i = 0; i < length; i++) - SerialBT[i] = new SPP(&Btd); // This will set the name to the default: "Arduino" and the pin to "1234" for all connections + SerialBT[i] = new SPP(&Btd); // This will set the name to the default: "Arduino" and the pin to "0000" for all connections Serial.begin(115200); while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection From 5f49b321cb71170225e28633c30f065997bd8e2e Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 02:58:33 +0100 Subject: [PATCH 12/24] Print data receiving on the L2CAP control channel for debugging --- BTHID.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index 7820d2d5..5cd8701d 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -182,9 +182,8 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } #endif } else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt - //Notify(PSTR("\r\n\r\nL2CAP Interrupt: "), 0x80); #ifdef PRINTREPORT - Notify(PSTR("\r\n"), 0x80); + Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80); for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { D_PrintHex (l2capinbuf[i + 8], 0x80); Notifyc(' ', 0x80); @@ -200,14 +199,13 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { break; case 0x02: // Mouse events - case 0x1A: if (pRptParser[MOUSE_PARSER_ID]) { uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); pRptParser[MOUSE_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]); } break; case 0x03: -#ifdef EXTRADEBUG +#ifdef DEBUG_USB_HOST Notify(PSTR("\r\nChange mode event: "), 0x80); D_PrintHex (l2capinbuf[11], 0x80); #endif @@ -220,6 +218,14 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { #endif } } + } else if (l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control +#ifdef PRINTREPORT + Notify(PSTR("\r\nL2CAP Control: "), 0x80); + for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { + D_PrintHex (l2capinbuf[i + 8], 0x80); + Notifyc(' ', 0x80); + } +#endif } #ifdef EXTRADEBUG else { From a31cc4258549b4d9d92df4f72bd6f4394fc90274 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 17:39:59 +0100 Subject: [PATCH 13/24] Use reinterpret_cast to cast from BTHID to HID class, so it can be used in the parser --- BTHID.cpp | 6 +++--- examples/Bluetooth/BTHID/BTHID.ino | 2 +- examples/Bluetooth/BTHID/KeyboardParser.h | 14 ++++++-------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index 5cd8701d..b1c3c1f4 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -24,7 +24,7 @@ BTHID::BTHID(BTD *p, bool pair, const char *pin) : pBtd(p), // pointer to USB class instance - mandatory protocolMode(HID_BOOT_PROTOCOL) { - for(uint8_t i = 0; i < epMUL; i++) + for (uint8_t i = 0; i < epMUL; i++) pRptParser[i] = NULL; if (pBtd) @@ -194,14 +194,14 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { case 0x01: // Keyboard events if (pRptParser[KEYBOARD_PARSER_ID]) { uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); - pRptParser[KEYBOARD_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]); + pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast (this), 0, (uint8_t) length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance } break; case 0x02: // Mouse events if (pRptParser[MOUSE_PARSER_ID]) { uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); - pRptParser[MOUSE_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]); + pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast (this), 0, (uint8_t) length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance } break; case 0x03: diff --git a/examples/Bluetooth/BTHID/BTHID.ino b/examples/Bluetooth/BTHID/BTHID.ino index 444cc8d2..fecc4b50 100644 --- a/examples/Bluetooth/BTHID/BTHID.ino +++ b/examples/Bluetooth/BTHID/BTHID.ino @@ -21,7 +21,7 @@ BTHID hid(&Btd, PAIR, "0000"); // After that you can simply create the instance like so and then press any button on the device //BTHID hid(&Btd); -KbdRptParser keyboardPrs(&hid); +KbdRptParser keyboardPrs; MouseRptParser mousePrs; void setup() { diff --git a/examples/Bluetooth/BTHID/KeyboardParser.h b/examples/Bluetooth/BTHID/KeyboardParser.h index 0d8c081d..ed04b50e 100644 --- a/examples/Bluetooth/BTHID/KeyboardParser.h +++ b/examples/Bluetooth/BTHID/KeyboardParser.h @@ -2,11 +2,8 @@ #define __kbdrptparser_h_ class KbdRptParser : public KeyboardReportParser { - public: - KbdRptParser(BTHID *p) : pBTHID(p) {}; - protected: - virtual uint8_t HandleLockingKeys(HID* hid, uint8_t key); + virtual uint8_t HandleLockingKeys(HID *hid, uint8_t key); virtual void OnControlKeysChanged(uint8_t before, uint8_t after); virtual void OnKeyDown(uint8_t mod, uint8_t key); virtual void OnKeyUp(uint8_t mod, uint8_t key); @@ -14,10 +11,9 @@ class KbdRptParser : public KeyboardReportParser { private: void PrintKey(uint8_t mod, uint8_t key); - BTHID *pBTHID; }; -uint8_t KbdRptParser::HandleLockingKeys(HID* hid, uint8_t key) { +uint8_t KbdRptParser::HandleLockingKeys(HID *hid, uint8_t key) { uint8_t old_keys = kbdLockingKeys.bLeds; switch (key) { @@ -35,8 +31,10 @@ uint8_t KbdRptParser::HandleLockingKeys(HID* hid, uint8_t key) { break; } - if (old_keys != kbdLockingKeys.bLeds && pBTHID) - pBTHID->setLeds(kbdLockingKeys.bLeds); + if (old_keys != kbdLockingKeys.bLeds && hid) { + BTHID *pBTHID = reinterpret_cast (hid); // A cast the other way around is done in BTHID.cpp + pBTHID->setLeds(kbdLockingKeys.bLeds); // Update the LEDs on the keyboard + } return 0; } From 148b67ca2de2fc89c285da7359213895da76d520 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 18:15:10 +0100 Subject: [PATCH 14/24] Fixed flush It behaved like prior Arduino 1.0 --- SPP.cpp | 2 +- SPP.h | 8 ++++++-- keywords.txt | 3 +-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/SPP.cpp b/SPP.cpp index 24911da9..0c133830 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -801,7 +801,7 @@ int SPP::available(void) { return rfcommAvailable; }; -void SPP::flush(void) { +void SPP::discard(void) { rfcommAvailable = 0; } diff --git a/SPP.h b/SPP.h index a38014f0..e2904f14 100644 --- a/SPP.h +++ b/SPP.h @@ -130,8 +130,10 @@ public: * @return Return the number of bytes ready to be read. */ virtual int available(void); - /** Discard all the bytes in the buffer. */ - virtual void flush(void); + /** Send out all bytes in the buffer. */ + virtual void flush(void) { + send(); + }; /** * Used to read the next value in the buffer without advancing to the next one. * @return Return the byte. Will return -1 if no bytes are available. @@ -157,6 +159,8 @@ public: virtual size_t write(const uint8_t* data, size_t size); /** Pull in write(const char *str) from Print */ using Print::write; + /** Discard all the bytes in the buffer. */ + void discard(void); /** * This will send all the bytes in the buffer. * This is called whenever Usb.Task() is called, diff --git a/keywords.txt b/keywords.txt index b3906513..c4f5bd87 100644 --- a/keywords.txt +++ b/keywords.txt @@ -228,8 +228,7 @@ SPP KEYWORD1 #################################################### connected KEYWORD2 -printNumber KEYWORD2 -printNumberln KEYWORD2 +discard KEYWORD2 #################################################### # Syntax Coloring Map For Wiimote Library From 2de6238a6ba2b076c55a164a4ef4452407a40915 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 18:20:22 +0100 Subject: [PATCH 15/24] Updated comment about Stream class --- SPP.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SPP.h b/SPP.h index e2904f14..81b83829 100644 --- a/SPP.h +++ b/SPP.h @@ -89,7 +89,10 @@ #define BT_RFCOMM_NSC_RSP 0x11 */ -/** This BluetoothService class implements the Serial Port Protocol (SPP). */ +/** + * This BluetoothService class implements the Serial Port Protocol (SPP). + * It inherits the Arduino Stream class. This allows it to use all the standard Arduino print functions. + */ class SPP : public BluetoothService, public Stream { public: /** From 627c39019198bbbb6e624af15c338e14fecc690f Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 18:46:10 +0100 Subject: [PATCH 16/24] Minor --- BTHID.cpp | 6 +++--- Wii.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index b1c3c1f4..ec0535af 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -89,7 +89,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { #endif } 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 + if (l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80); identifier = l2capinbuf[9]; control_scid[0] = l2capinbuf[12]; @@ -186,7 +186,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR("\r\nL2CAP Interrupt: "), 0x80); for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { D_PrintHex (l2capinbuf[i + 8], 0x80); - Notifyc(' ', 0x80); + Notify(PSTR(" "), 0x80); } #endif if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT @@ -223,7 +223,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR("\r\nL2CAP Control: "), 0x80); for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { D_PrintHex (l2capinbuf[i + 8], 0x80); - Notifyc(' ', 0x80); + Notify(PSTR(" "), 0x80); } #endif } diff --git a/Wii.cpp b/Wii.cpp index 2e8669db..d55d4e79 100755 --- a/Wii.cpp +++ b/Wii.cpp @@ -163,7 +163,7 @@ void WII::ACLData(uint8_t* l2capinbuf) { #endif } 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 + if (l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80); identifier = l2capinbuf[9]; control_scid[0] = l2capinbuf[12]; From bcc4afede59fa8ad106c55d338ffc38ff073e52d Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 19:01:20 +0100 Subject: [PATCH 17/24] =?UTF-8?q?Set=20protocol=20shouldn=E2=80=99t=20have?= =?UTF-8?q?=20it=E2=80=99s=20own=20state,=20as=20it=20will=20then=20someti?= =?UTF-8?q?mes=20not=20call=20the=20other=20states=20afterwards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BTHID.cpp | 21 +++++++++------------ BTHID.h | 13 ++++++------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index ec0535af..02b9a884 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -254,7 +254,7 @@ void BTHID::L2CAP_task() { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); #endif - setProtocol(); + setProtocol(); // Set protocol before establishing HID interrupt channel l2cap_state = L2CAP_INTERRUPT_SETUP; } break; @@ -283,24 +283,21 @@ void BTHID::L2CAP_task() { #endif identifier++; pBtd->l2cap_config_request(hci_handle, identifier, control_scid); - l2cap_state = L2CAP_SET_PROTOCOL; - } - break; - - case L2CAP_SET_PROTOCOL: - if (l2cap_config_success_control_flag) { - setProtocol(); l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST; } break; case L2CAP_CONTROL_CONFIG_REQUEST: + if (l2cap_config_success_control_flag) { + setProtocol(); // Set protocol before establishing HID interrupt channel + delay(1); // Short delay between commands - just to be sure #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); + Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80); #endif - identifier++; - pBtd->l2cap_connection_request(hci_handle, identifier, interrupt_dcid, HID_INTR_PSM); - l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST; + 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: diff --git a/BTHID.h b/BTHID.h index 21b92720..ddd26d59 100644 --- a/BTHID.h +++ b/BTHID.h @@ -31,15 +31,14 @@ // These states are used if the Arduino is the host #define L2CAP_CONTROL_CONNECT_REQUEST 3 -#define L2CAP_SET_PROTOCOL 4 -#define L2CAP_CONTROL_CONFIG_REQUEST 5 -#define L2CAP_INTERRUPT_CONNECT_REQUEST 6 +#define L2CAP_CONTROL_CONFIG_REQUEST 4 +#define L2CAP_INTERRUPT_CONNECT_REQUEST 5 -#define L2CAP_INTERRUPT_CONFIG_REQUEST 7 -#define L2CAP_DONE 8 +#define L2CAP_INTERRUPT_CONFIG_REQUEST 6 +#define L2CAP_DONE 7 -#define L2CAP_INTERRUPT_DISCONNECT 9 -#define L2CAP_CONTROL_DISCONNECT 10 +#define L2CAP_INTERRUPT_DISCONNECT 8 +#define L2CAP_CONTROL_DISCONNECT 9 /* L2CAP event flags */ #define L2CAP_FLAG_CONTROL_CONNECTED 0x01 From 5edcc13c6c9b00f4841b614560e7220e2fe64f41 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 23:26:11 +0100 Subject: [PATCH 18/24] Added information about spi4teensy3 library --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9907d2d3..d208c2b8 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ Currently the following boards are supported by the library: * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.) * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.0) + * Note if you are using the Teensy 3.0 you should download this SPI library as well: . You should then add ```#include spi4teensy3.h``` to your .ino file. * Balanduino * Sanguino * Black Widdow From b5d997c821a9adb33b5cfbcbd780a3cc4f5bae33 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 25 Nov 2013 23:27:37 +0100 Subject: [PATCH 19/24] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d208c2b8..59c98caf 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Currently the following boards are supported by the library: * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.) * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.0) - * Note if you are using the Teensy 3.0 you should download this SPI library as well: . You should then add ```#include spi4teensy3.h``` to your .ino file. + * Note if you are using the Teensy 3.0 you should download this SPI library as well: . You should then add ```#include ``` to your .ino file. * Balanduino * Sanguino * Black Widdow From 6004d61de2afb0076c34658bdd1b9e33a4282def Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Wed, 27 Nov 2013 00:07:58 +0100 Subject: [PATCH 20/24] Removed some unused code and cleanup --- BTHID.cpp | 3 ++- BTHID.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index 02b9a884..908f5961 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -204,6 +204,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast (this), 0, (uint8_t) length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance } break; + case 0x03: #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nChange mode event: "), 0x80); @@ -238,7 +239,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR("\r\n"), 0x80); for (uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { D_PrintHex (l2capinbuf[i + 8], 0x80); - Notifyc(' ', 0x80); + Notify(PSTR(" "), 0x80); } } #endif diff --git a/BTHID.h b/BTHID.h index ddd26d59..7eae9494 100644 --- a/BTHID.h +++ b/BTHID.h @@ -19,7 +19,6 @@ #define _bthid_h_ #include "BTD.h" -#include "controllerEnums.h" #include "hidboot.h" /* Bluetooth L2CAP states for L2CAP_task() */ @@ -152,9 +151,6 @@ private: uint8_t l2cap_state; uint8_t l2cap_event_flag; // l2cap flags of received Bluetooth events - uint8_t ButtonState, OldButtonState, ButtonClickState; - int16_t xAxis, yAxis, scroll; - /* L2CAP Channels */ uint8_t control_scid[2]; // L2CAP source CID for HID_Control uint8_t control_dcid[2]; // 0x0070 From c84dce8e006828201ca949deab369259bbbd96c5 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 1 Dec 2013 16:02:23 +0100 Subject: [PATCH 21/24] Renamed clearAllVariables() to Initialize() --- BTD.cpp | 8 ++++---- BTD.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index ab858d46..cab5f7f8 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -39,7 +39,7 @@ bPollEnable(false) // Don't start polling before dongle is connected for (uint8_t i = 0; i < BTD_NUMSERVICES; i++) btService[i] = NULL; - clearAllVariables(); // Set all variables, endpoint structs etc. to default values + Initialize(); // Set all variables, endpoint structs etc. to default values if (pUsb) // Register in USB subsystem pUsb->RegisterDeviceClass(this); // Set devConfig[] entry @@ -52,7 +52,7 @@ uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { UsbDevice *p = NULL; EpInfo *oldep_ptr = NULL; - clearAllVariables(); // Set all variables, endpoint structs etc. to default values + Initialize(); // Set all variables, endpoint structs etc. to default values AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool #ifdef EXTRADEBUG @@ -290,7 +290,7 @@ Fail: return rcode; } -void BTD::clearAllVariables() { +void BTD::Initialize() { uint8_t i; for (i = 0; i < BTD_MAX_ENDPOINTS; i++) { epInfo[i].epAddr = 0; @@ -367,7 +367,7 @@ void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { /* Performs a cleanup after failed Init() attempt */ uint8_t BTD::Release() { - clearAllVariables(); // Set all variables, endpoint structs etc. to default values + Initialize(); // Set all variables, endpoint structs etc. to default values pUsb->GetAddressPool().FreeAddress(bAddress); return 0; } diff --git a/BTD.h b/BTD.h index c419a252..a048e098 100755 --- a/BTD.h +++ b/BTD.h @@ -488,7 +488,7 @@ protected: void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); private: - void clearAllVariables(); // Set all variables, endpoint structs etc. to default values + void Initialize(); // Set all variables, endpoint structs etc. to default values BluetoothService* btService[BTD_NUMSERVICES]; uint16_t PID, VID; // PID and VID of device connected From ab9338a55e7422682308c2a3d86d9efa02beb7cb Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 1 Dec 2013 16:03:11 +0100 Subject: [PATCH 22/24] Added missing semicolon Needed for STM32 --- examples/Bluetooth/BTHID/KeyboardParser.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Bluetooth/BTHID/KeyboardParser.h b/examples/Bluetooth/BTHID/KeyboardParser.h index ed04b50e..b7ab08e9 100644 --- a/examples/Bluetooth/BTHID/KeyboardParser.h +++ b/examples/Bluetooth/BTHID/KeyboardParser.h @@ -37,7 +37,7 @@ uint8_t KbdRptParser::HandleLockingKeys(HID *hid, uint8_t key) { } return 0; -} +}; void KbdRptParser::PrintKey(uint8_t m, uint8_t key) { MODIFIERKEYS mod; @@ -64,7 +64,7 @@ void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) { if (c) OnKeyPressed(c); -} +}; void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) { MODIFIERKEYS beforeMod; @@ -90,12 +90,12 @@ void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) { Serial.println(F("RightAlt changed")); if (beforeMod.bmRightGUI != afterMod.bmRightGUI) Serial.println(F("RightGUI changed")); -} +}; void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) { Serial.print(F("UP ")); PrintKey(mod, key); -} +}; void KbdRptParser::OnKeyPressed(uint8_t key) { Serial.print(F("ASCII: ")); From 315af437ed63cb7976afe1edb0acbbdbfba17d15 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 1 Dec 2013 17:06:32 +0100 Subject: [PATCH 23/24] Now easier to disable and enable printing of incoming data --- hidboot.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hidboot.h b/hidboot.h index 826e8e72..42224c68 100644 --- a/hidboot.h +++ b/hidboot.h @@ -495,10 +495,14 @@ uint8_t HIDBoot::Poll() { if(pRptParser[i]) pRptParser[i]->Parse((HID*)this, 0, (uint8_t) read, buf); - //for (uint8_t i=0; i(buf[i]); - //if (read) - // USB_HOST_SERIAL.println(""); +#if 0 // Set this to 1 to print the incoming data + for (uint8_t i=0; i < read; i++) { + PrintHex (buf[i], 0x80); + USB_HOST_SERIAL.write(' '); + } + if (read) + USB_HOST_SERIAL.println(); +#endif } else { if(rcode != hrNAK) { USBTRACE2("Poll:", rcode); From 237a8a58000c5e04ce39a890451e5f773748a9bf Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 1 Dec 2013 18:36:19 +0100 Subject: [PATCH 24/24] Formatting --- BTHID.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BTHID.cpp b/BTHID.cpp index 908f5961..3e626b18 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -71,7 +71,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } } if ((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000)) { // acl_handle_ok or it's a new connection - if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U + if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { // l2cap_control - Channel ID for ACL-U if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);