From 30ac619331fd43cbbc12150dc244a2457b733566 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 30 Jun 2019 20:44:12 +0200 Subject: [PATCH 01/12] Initial code for Xbox One S controller support I lack a dongle that support simply paring, so it has been confirmed working yet --- BTD.cpp | 181 +++++++++++++++++++++++++++-- BTD.h | 13 +++ examples/Bluetooth/BTHID/BTHID.ino | 2 +- settings.h | 2 +- 4 files changed, 185 insertions(+), 13 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index 536aa84e..f74cda7a 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -17,7 +17,7 @@ #include "BTD.h" // To enable serial debugging see "settings.h" -//#define EXTRADEBUG // Uncomment to get even more debugging data +#define EXTRADEBUG // Uncomment to get even more debugging data const uint8_t BTD::BTD_CONTROL_PIPE = 0; const uint8_t BTD::BTD_EVENT_PIPE = 1; @@ -408,7 +408,46 @@ void BTD::HCI_event_task() { hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm +#ifdef EXTRADEBUG + if(!hci_check_flag(HCI_FLAG_READ_VERSION)) { + Notify(PSTR("\r\nHCI version: "), 0x80); + D_PrintHex (hci_version, 0x80); + } +#endif hci_set_flag(HCI_FLAG_READ_VERSION); + } else if((hcibuf[3] == 0x04) && (hcibuf[4] == 0x10)) { // Parameters from read local extended features + if(!hci_check_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES)) { +#ifdef EXTRADEBUG + Notify(PSTR("\r\nPage number: "), 0x80); + D_PrintHex (hcibuf[6], 0x80); + Notify(PSTR("\r\nMaximum page number: "), 0x80); + D_PrintHex (hcibuf[7], 0x80); + Notify(PSTR("\r\nExtended LMP features:"), 0x80); + for(uint8_t i = 0; i < 8; i++) { + Notify(PSTR(" "), 0x80); + D_PrintHex (hcibuf[8 + i], 0x80); + } +#endif +#ifdef DEBUG_USB_HOST + if(hcibuf[6] == 0) { // Page 0 + Notify(PSTR("\r\nLocal "), 0x80); + if(hcibuf[8 + 6] & (1U << 3)) + Notify(PSTR("supports"), 0x80); + else + Notify(PSTR("does NOT support"), 0x80); + Notify(PSTR(" secure simple paring (controller support)"), 0x80); + } else if(hcibuf[6] == 1) { // Page 1 + Notify(PSTR("\r\nLocal "), 0x80); + if(hcibuf[8 + 0] & (1U << 0)) + Notify(PSTR("supports"), 0x80); + else + Notify(PSTR("does NOT support"), 0x80); + Notify(PSTR(" secure simple paring (host support)"), 0x80); + } +#endif + } + + hci_set_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES); } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address for(uint8_t i = 0; i < 6; i++) my_bdaddr[i] = hcibuf[6 + i]; @@ -446,7 +485,7 @@ void BTD::HCI_event_task() { case EV_INQUIRY_RESULT: if(hcibuf[2]) { // Check that there is more than zero responses -#ifdef EXTRADEBUG +#if defined(EXTRADEBUG) && 0 Notify(PSTR("\r\nNumber of responses: "), 0x80); Notify(hcibuf[2], 0x80); #endif @@ -456,7 +495,7 @@ void BTD::HCI_event_task() { for(uint8_t j = 0; j < 3; j++) classOfDevice[j] = hcibuf[j + 4 + offset]; -#ifdef EXTRADEBUG +#if defined(EXTRADEBUG) && 0 Notify(PSTR("\r\nClass of device: "), 0x80); D_PrintHex (classOfDevice[2], 0x80); Notify(PSTR(" "), 0x80); @@ -465,7 +504,7 @@ void BTD::HCI_event_task() { D_PrintHex (classOfDevice[0], 0x80); #endif - if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information + if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] == 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information checkRemoteName = true; // Check remote name to distinguish between the different controllers for(uint8_t j = 0; j < 6; j++) @@ -473,8 +512,10 @@ void BTD::HCI_event_task() { hci_set_flag(HCI_FLAG_DEVICE_FOUND); break; - } else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html + } else if(pairWithHIDDevice && (classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html #ifdef DEBUG_USB_HOST + checkRemoteName = true; // Used to print name in the serial monitor if serial debugging is enabled + if(classOfDevice[0] & 0x80) Notify(PSTR("\r\nMouse found"), 0x80); if(classOfDevice[0] & 0x40) @@ -524,7 +565,7 @@ void BTD::HCI_event_task() { if(remote_name[i] == '\0') // End of string break; } - // TODO: Altid sæt '\0' i remote name! + // TODO: Always set '\0' in remote name! hci_set_flag(HCI_FLAG_REMOTE_NAME_COMPLETE); } break; @@ -536,7 +577,7 @@ void BTD::HCI_event_task() { for(uint8_t i = 0; i < 3; i++) classOfDevice[i] = hcibuf[i + 8]; - if((classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad + if((classOfDevice[1] & 0x0F) == 0x05 && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad #ifdef DEBUG_USB_HOST if(classOfDevice[0] & 0x80) Notify(PSTR("\r\nMouse is connecting"), 0x80); @@ -608,18 +649,84 @@ void BTD::HCI_event_task() { hci_state = HCI_DISCONNECT_STATE; } break; + + case EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE: + if(!hcibuf[2]) { // Check if connected OK + if(!hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) { +#ifdef EXTRADEBUG + Notify(PSTR("\r\nPage number: "), 0x80); + D_PrintHex (hcibuf[5], 0x80); + Notify(PSTR("\r\nMaximum page number: "), 0x80); + D_PrintHex (hcibuf[6], 0x80); + Notify(PSTR("\r\nExtended LMP features:"), 0x80); + for(uint8_t i = 0; i < 8; i++) { + Notify(PSTR(" "), 0x80); + D_PrintHex (hcibuf[7 + i], 0x80); + } +#endif +#ifdef DEBUG_USB_HOST + if(hcibuf[5] == 0) { // Page 0 + Notify(PSTR("\r\nRemote "), 0x80); + if(hcibuf[7 + 6] & (1U << 3)) + Notify(PSTR("supports"), 0x80); + else + Notify(PSTR("does NOT support"), 0x80); + Notify(PSTR(" secure simple paring (controller support)"), 0x80); + } else if(hcibuf[5] == 1) { // Page 1 + Notify(PSTR("\r\nRemote "), 0x80); + if(hcibuf[7 + 0] & (1U << 0)) + Notify(PSTR("supports"), 0x80); + else + Notify(PSTR("\r\ndoes NOT support"), 0x80); + Notify(PSTR(" secure simple paring (host support)"), 0x80); + } +#endif + } + hci_set_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES); + } else { + hci_state = HCI_CHECK_DEVICE_SERVICE; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nFailed to read remote extended featues: "), 0x80); + D_PrintHex (hcibuf[2], 0x80); +#endif + } + break; + + case EV_USER_CONFIRMATION_REQUEST: +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nUser confirmation Request: "), 0x80); +#endif +#ifdef EXTRADEBUG + Notify(PSTR("\r\nNumeric value: "), 0x80); + for(uint8_t i = 0; i < 4; i++) { + Notify(PSTR(" "), 0x80); + D_PrintHex (hcibuf[8 + i], 0x80); + } +#endif + + hci_user_confirmation_request_reply(); + hci_state = HCI_SCANNING_STATE; + break; + /* We will just ignore the following events */ + case EV_MAX_SLOTS_CHANGE: + break; case EV_NUM_COMPLETE_PKT: case EV_ROLE_CHANGED: case EV_PAGE_SCAN_REP_MODE: case EV_LOOPBACK_COMMAND: case EV_DATA_BUFFER_OVERFLOW: case EV_CHANGE_CONNECTION_LINK: - case EV_MAX_SLOTS_CHANGE: case EV_QOS_SETUP_COMPLETE: case EV_LINK_KEY_NOTIFICATION: case EV_ENCRYPTION_CHANGE: case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE: +#ifdef EXTRADEBUG + if(hcibuf[0] != 0x00) { + Notify(PSTR("\r\nIgnore HCI Event: "), 0x80); + D_PrintHex (hcibuf[0], 0x80); + } +#endif break; #ifdef EXTRADEBUG default: @@ -699,6 +806,14 @@ void BTD::HCI_task() { case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class if(hci_check_flag(HCI_FLAG_READ_VERSION)) { + hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" + //hci_read_local_extended_features(1); // Read page 1 + hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; + } + break; + + case HCI_LOCAL_EXTENDED_FEATURES_STATE: + if(hci_check_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES)) { if(btdName != NULL) { hci_set_local_name(btdName); hci_state = HCI_SET_NAME_STATE; @@ -783,8 +898,9 @@ void BTD::HCI_task() { 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; + hci_read_remote_extended_features(0); // "Requests the normal LMP features as returned by the HCI_Read_Remote_Supported_Features command" + //hci_read_remote_extended_features(1); // Read page 1 + hci_state = HCI_REMOTE_EXTENDED_FEATURES_STATE; } else { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nTrying to connect one more time..."), 0x80); @@ -794,6 +910,13 @@ void BTD::HCI_task() { } break; + case HCI_REMOTE_EXTENDED_FEATURES_STATE: + if(hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) { + hci_authentication_request(); + hci_state = HCI_SCANNING_STATE; + } + break; + case HCI_SCANNING_STATE: if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) { #ifdef DEBUG_USB_HOST @@ -855,7 +978,7 @@ void BTD::HCI_task() { #endif incomingPS4 = true; } - if(pairWithWii && checkRemoteName) + if((pairWithWii || pairWithHIDDevice) && checkRemoteName) hci_state = HCI_CONNECT_DEVICE_STATE; else { hci_accept_connection(); @@ -999,6 +1122,16 @@ void BTD::hci_read_local_version_information() { HCI_Command(hcibuf, 3); } +void BTD::hci_read_local_extended_features(uint8_t page_number) { + hci_clear_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES); + hcibuf[0] = 0x04; // HCI OCF = 4 + hcibuf[1] = 0x04 << 2; // HCI OGF = 4 + hcibuf[2] = 0x01; // parameter length = 1 + hcibuf[3] = page_number; + + HCI_Command(hcibuf, 4); +} + void BTD::hci_accept_connection() { hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); hcibuf[0] = 0x09; // HCI OCF = 9 @@ -1034,6 +1167,18 @@ void BTD::hci_remote_name() { HCI_Command(hcibuf, 13); } +void BTD::hci_read_remote_extended_features(uint8_t page_number) { + hci_clear_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES); + hcibuf[0] = 0x1C; // HCI OCF = 1C + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x03; // parameter length = 3 + hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte + hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte + hcibuf[5] = page_number; + + HCI_Command(hcibuf, 6); +} + void BTD::hci_set_local_name(const char* name) { hcibuf[0] = 0x13; // HCI OCF = 13 hcibuf[1] = 0x03 << 2; // HCI OGF = 3 @@ -1158,6 +1303,20 @@ void BTD::hci_link_key_request_negative_reply() { HCI_Command(hcibuf, 9); } +void BTD::hci_user_confirmation_request_reply() { + hcibuf[0] = 0x2C; // HCI OCF = 2C + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x06; // parameter length 6 + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + + HCI_Command(hcibuf, 9); +} + void BTD::hci_authentication_request() { hcibuf[0] = 0x11; // HCI OCF = 11 hcibuf[1] = 0x01 << 2; // HCI OGF = 1 diff --git a/BTD.h b/BTD.h index baf39364..e7ab9f96 100644 --- a/BTD.h +++ b/BTD.h @@ -59,6 +59,8 @@ #define HCI_DISABLE_SCAN_STATE 14 #define HCI_DONE_STATE 15 #define HCI_DISCONNECT_STATE 16 +#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17 +#define HCI_REMOTE_EXTENDED_FEATURES_STATE 18 /* HCI event flags*/ #define HCI_FLAG_CMD_COMPLETE (1UL << 0) @@ -70,6 +72,8 @@ #define HCI_FLAG_READ_VERSION (1UL << 6) #define HCI_FLAG_DEVICE_FOUND (1UL << 7) #define HCI_FLAG_CONNECT_EVENT (1UL << 8) +#define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9) +#define HCI_FLAG_REMOTE_EXTENDED_FEATURES (1UL << 10) /* Macros for HCI event flag tests */ #define hci_check_flag(flag) (hci_event_flag & (flag)) @@ -99,6 +103,9 @@ #define EV_COMMAND_STATUS 0x0F #define EV_LOOPBACK_COMMAND 0x19 #define EV_PAGE_SCAN_REP_MODE 0x20 +#define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23 +#define EV_USER_CONFIRMATION_REQUEST 0x33 + /* Bluetooth states for the different Bluetooth drivers */ #define L2CAP_WAIT 0 @@ -320,6 +327,8 @@ public: void hci_read_bdaddr(); /** Read the HCI Version of the Bluetooth dongle. */ void hci_read_local_version_information(); + + void hci_read_local_extended_features(uint8_t page_number); /** * Set the local name of the Bluetooth dongle. * @param name Desired name. @@ -331,6 +340,8 @@ public: void hci_write_scan_disable(); /** Read the remote devices name. */ void hci_remote_name(); + + void hci_read_remote_extended_features(uint8_t page_number); /** Accept the connection with the Bluetooth device. */ void hci_accept_connection(); /** @@ -351,6 +362,8 @@ public: * if the Host does not have a stored Link Key for the connection. */ void hci_link_key_request_negative_reply(); + + void hci_user_confirmation_request_reply(); /** Used to try to authenticate with the remote device. */ void hci_authentication_request(); /** Start a HCI inquiry. */ diff --git a/examples/Bluetooth/BTHID/BTHID.ino b/examples/Bluetooth/BTHID/BTHID.ino index 58a2f92f..3d848726 100644 --- a/examples/Bluetooth/BTHID/BTHID.ino +++ b/examples/Bluetooth/BTHID/BTHID.ino @@ -25,7 +25,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so BTHID bthid(&Btd, PAIR, "0000"); // After that you can simply create the instance like so and then press any button on the device -//BTHID hid(&Btd); +//BTHID bthid(&Btd); KbdRptParser keyboardPrs; MouseRptParser mousePrs; diff --git a/settings.h b/settings.h index 2d176053..63be1770 100644 --- a/settings.h +++ b/settings.h @@ -39,7 +39,7 @@ e-mail : support@circuitsathome.com //////////////////////////////////////////////////////////////////////////////// /* Set this to 1 to activate serial debugging */ -#define ENABLE_UHS_DEBUGGING 0 +#define ENABLE_UHS_DEBUGGING 1 /* This can be used to select which serial port to use for debugging if * multiple serial ports are available. From a347b3bacea4157eac012babf598d4733861b2e0 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Tue, 2 Jul 2019 20:30:33 +0200 Subject: [PATCH 02/12] Enable simple paring mode --- BTD.cpp | 41 ++++++++++++++++++++++++++++++----------- BTD.h | 13 ++++++++----- BTHID.cpp | 14 +++++++++++++- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index f74cda7a..36e7e705 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -430,19 +430,19 @@ void BTD::HCI_event_task() { #endif #ifdef DEBUG_USB_HOST if(hcibuf[6] == 0) { // Page 0 - Notify(PSTR("\r\nLocal "), 0x80); + Notify(PSTR("\r\nDongle "), 0x80); if(hcibuf[8 + 6] & (1U << 3)) Notify(PSTR("supports"), 0x80); else Notify(PSTR("does NOT support"), 0x80); - Notify(PSTR(" secure simple paring (controller support)"), 0x80); + Notify(PSTR(" secure simple pairing (controller support)"), 0x80); } else if(hcibuf[6] == 1) { // Page 1 - Notify(PSTR("\r\nLocal "), 0x80); + Notify(PSTR("\r\nDongle "), 0x80); if(hcibuf[8 + 0] & (1U << 0)) Notify(PSTR("supports"), 0x80); else Notify(PSTR("does NOT support"), 0x80); - Notify(PSTR(" secure simple paring (host support)"), 0x80); + Notify(PSTR(" secure simple pairing (host support)"), 0x80); } #endif } @@ -671,14 +671,14 @@ void BTD::HCI_event_task() { Notify(PSTR("supports"), 0x80); else Notify(PSTR("does NOT support"), 0x80); - Notify(PSTR(" secure simple paring (controller support)"), 0x80); + Notify(PSTR(" secure simple pairing (controller support)"), 0x80); } else if(hcibuf[5] == 1) { // Page 1 Notify(PSTR("\r\nRemote "), 0x80); if(hcibuf[7 + 0] & (1U << 0)) Notify(PSTR("supports"), 0x80); else Notify(PSTR("\r\ndoes NOT support"), 0x80); - Notify(PSTR(" secure simple paring (host support)"), 0x80); + Notify(PSTR(" secure simple pairing (host support)"), 0x80); } #endif } @@ -814,18 +814,28 @@ void BTD::HCI_task() { case HCI_LOCAL_EXTENDED_FEATURES_STATE: if(hci_check_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES)) { + hci_write_simple_pairing_mode(true); + hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE; + } + break; + + case HCI_WRITE_SIMPLE_PAIRING_STATE: + if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSimple pairing was enabled"), 0x80); +#endif if(btdName != NULL) { - hci_set_local_name(btdName); - hci_state = HCI_SET_NAME_STATE; + hci_write_local_name(btdName); + hci_state = HCI_WRITE_NAME_STATE; } else hci_state = HCI_CHECK_DEVICE_SERVICE; } break; - case HCI_SET_NAME_STATE: + case HCI_WRITE_NAME_STATE: if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nThe name is set to: "), 0x80); + Notify(PSTR("\r\nThe name was set to: "), 0x80); NotifyStr(btdName, 0x80); #endif hci_state = HCI_CHECK_DEVICE_SERVICE; @@ -1179,7 +1189,7 @@ void BTD::hci_read_remote_extended_features(uint8_t page_number) { HCI_Command(hcibuf, 6); } -void BTD::hci_set_local_name(const char* name) { +void BTD::hci_write_local_name(const char* name) { hcibuf[0] = 0x13; // HCI OCF = 13 hcibuf[1] = 0x03 << 2; // HCI OGF = 3 hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte @@ -1191,6 +1201,15 @@ void BTD::hci_set_local_name(const char* name) { HCI_Command(hcibuf, 4 + strlen(name)); } +void BTD::hci_write_simple_pairing_mode(bool enable) { + hcibuf[0] = 0x56; // HCI OCF = 56 + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = 1; // parameter length = 1 + hcibuf[3] = enable ? 1 : 0; + + HCI_Command(hcibuf, 4); +} + void BTD::hci_inquiry() { hci_clear_flag(HCI_FLAG_DEVICE_FOUND); hcibuf[0] = 0x01; diff --git a/BTD.h b/BTD.h index e7ab9f96..ed179937 100644 --- a/BTD.h +++ b/BTD.h @@ -45,7 +45,7 @@ #define HCI_CLASS_STATE 2 #define HCI_BDADDR_STATE 3 #define HCI_LOCAL_VERSION_STATE 4 -#define HCI_SET_NAME_STATE 5 +#define HCI_WRITE_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 device @@ -59,8 +59,9 @@ #define HCI_DISABLE_SCAN_STATE 14 #define HCI_DONE_STATE 15 #define HCI_DISCONNECT_STATE 16 -#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17 -#define HCI_REMOTE_EXTENDED_FEATURES_STATE 18 +#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17 +#define HCI_WRITE_SIMPLE_PAIRING_STATE 18 +#define HCI_REMOTE_EXTENDED_FEATURES_STATE 19 /* HCI event flags*/ #define HCI_FLAG_CMD_COMPLETE (1UL << 0) @@ -72,7 +73,7 @@ #define HCI_FLAG_READ_VERSION (1UL << 6) #define HCI_FLAG_DEVICE_FOUND (1UL << 7) #define HCI_FLAG_CONNECT_EVENT (1UL << 8) -#define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9) +#define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9) #define HCI_FLAG_REMOTE_EXTENDED_FEATURES (1UL << 10) /* Macros for HCI event flag tests */ @@ -333,7 +334,9 @@ public: * Set the local name of the Bluetooth dongle. * @param name Desired name. */ - void hci_set_local_name(const char* name); + void hci_write_local_name(const char* name); + + void hci_write_simple_pairing_mode(bool enable); /** Enable visibility to other Bluetooth devices. */ void hci_write_scan_enable(); /** Disable visibility to other Bluetooth devices. */ diff --git a/BTHID.cpp b/BTHID.cpp index d32e9aa6..225aa1f8 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -17,7 +17,7 @@ #include "BTHID.h" // To enable serial debugging see "settings.h" -//#define EXTRADEBUG // Uncomment to get even more debugging data +#define EXTRADEBUG // Uncomment to get even more debugging data //#define PRINTREPORT // Uncomment to print the report send by the HID device BTHID::BTHID(BTD *p, bool pair, const char *pin) : @@ -54,6 +54,18 @@ void BTHID::disconnect() { // Use this void to disconnect the device } void BTHID::ACLData(uint8_t* l2capinbuf) { + Notify(PSTR("\r\nL2CAP 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); + Notify(PSTR(" "), 0x80); + } + if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) { if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { From 7714e807f6ea505bca8aabe8f75c3f82d4789b8b Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Wed, 3 Jul 2019 00:30:18 +0200 Subject: [PATCH 03/12] Added SDP support to the BTHID, as needed for the Xbox One S controller --- BTD.cpp | 61 ++++++++------- BTD.h | 12 +++ BTHID.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- BTHID.h | 10 +++ SPP.h | 6 -- 5 files changed, 268 insertions(+), 38 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index 36e7e705..20d6b9cf 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -34,6 +34,7 @@ bAddress(0), // Device address - mandatory bNumEP(1), // If config descriptor needs to be parsed qNextPollTime(0), // Reset NextPollTime pollInterval(0), +simple_pairing_supported(false), bPollEnable(false) // Don't start polling before dongle is connected { for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) @@ -321,6 +322,7 @@ void BTD::Initialize() { qNextPollTime = 0; // Reset next poll time pollInterval = 0; bPollEnable = false; // Don't start polling before dongle is connected + simple_pairing_supported = false; } /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */ @@ -431,10 +433,13 @@ void BTD::HCI_event_task() { #ifdef DEBUG_USB_HOST if(hcibuf[6] == 0) { // Page 0 Notify(PSTR("\r\nDongle "), 0x80); - if(hcibuf[8 + 6] & (1U << 3)) + if(hcibuf[8 + 6] & (1U << 3)) { + simple_pairing_supported = true; Notify(PSTR("supports"), 0x80); - else + } else { + simple_pairing_supported = false; Notify(PSTR("does NOT support"), 0x80); + } Notify(PSTR(" secure simple pairing (controller support)"), 0x80); } else if(hcibuf[6] == 1) { // Page 1 Notify(PSTR("\r\nDongle "), 0x80); @@ -485,7 +490,7 @@ void BTD::HCI_event_task() { case EV_INQUIRY_RESULT: if(hcibuf[2]) { // Check that there is more than zero responses -#if defined(EXTRADEBUG) && 0 +#ifdef EXTRADEBUG Notify(PSTR("\r\nNumber of responses: "), 0x80); Notify(hcibuf[2], 0x80); #endif @@ -495,7 +500,7 @@ void BTD::HCI_event_task() { for(uint8_t j = 0; j < 3; j++) classOfDevice[j] = hcibuf[j + 4 + offset]; -#if defined(EXTRADEBUG) && 0 +#ifdef EXTRADEBUG Notify(PSTR("\r\nClass of device: "), 0x80); D_PrintHex (classOfDevice[2], 0x80); Notify(PSTR(" "), 0x80); @@ -710,8 +715,8 @@ void BTD::HCI_event_task() { /* We will just ignore the following events */ case EV_MAX_SLOTS_CHANGE: - break; case EV_NUM_COMPLETE_PKT: + break; case EV_ROLE_CHANGED: case EV_PAGE_SCAN_REP_MODE: case EV_LOOPBACK_COMMAND: @@ -806,29 +811,14 @@ void BTD::HCI_task() { case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class if(hci_check_flag(HCI_FLAG_READ_VERSION)) { - hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" - //hci_read_local_extended_features(1); // Read page 1 - hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; - } - break; - - case HCI_LOCAL_EXTENDED_FEATURES_STATE: - if(hci_check_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES)) { - hci_write_simple_pairing_mode(true); - hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE; - } - break; - - case HCI_WRITE_SIMPLE_PAIRING_STATE: - if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nSimple pairing was enabled"), 0x80); -#endif if(btdName != NULL) { hci_write_local_name(btdName); hci_state = HCI_WRITE_NAME_STATE; - } else - hci_state = HCI_CHECK_DEVICE_SERVICE; + } else { + hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" + //hci_read_local_extended_features(1); // Read page 1 + hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; + } } break; @@ -837,6 +827,27 @@ void BTD::HCI_task() { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nThe name was set to: "), 0x80); NotifyStr(btdName, 0x80); +#endif + hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" + //hci_read_local_extended_features(1); // Read page 1 + hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; + } + break; + + case HCI_LOCAL_EXTENDED_FEATURES_STATE: + if(hci_check_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES)) { + if(simple_pairing_supported) { + hci_write_simple_pairing_mode(true); + hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE; + } else + hci_state = HCI_CHECK_DEVICE_SERVICE; + } + break; + + case HCI_WRITE_SIMPLE_PAIRING_STATE: + if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSimple pairing was enabled"), 0x80); #endif hci_state = HCI_CHECK_DEVICE_SERVICE; } diff --git a/BTD.h b/BTD.h index ed179937..c12e325b 100644 --- a/BTD.h +++ b/BTD.h @@ -191,6 +191,17 @@ #define HID_CTRL_PSM 0x11 // HID_Control PSM Value #define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value +/* Used for SDP */ +#define SDP_SERVICE_SEARCH_REQUEST 0x02 +#define SDP_SERVICE_SEARCH_RESPONSE 0x03 +#define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04 +#define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05 +#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs +#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs +#define PNP_INFORMATION_UUID 0x1200 +#define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm +#define L2CAP_UUID 0x0100 + // Used to determine if it is a Bluetooth dongle #define WI_SUBCLASS_RF 0x01 // RF Controller #define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface @@ -553,6 +564,7 @@ private: uint16_t PID, VID; // PID and VID of device connected uint8_t pollInterval; + bool simple_pairing_supported; bool bPollEnable; bool pairWiiUsingSync; // True if pairing was done using the Wii SYNC button. diff --git a/BTHID.cpp b/BTHID.cpp index 225aa1f8..3928c7dd 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -41,15 +41,20 @@ protocolMode(USB_HID_BOOT_PROTOCOL) { void BTHID::Reset() { connected = false; activeConnection = false; + SDPConnected = false; l2cap_event_flag = 0; // Reset flags + l2cap_sdp_state = L2CAP_SDP_WAIT; l2cap_state = L2CAP_WAIT; ResetBTHID(); } void BTHID::disconnect() { // Use this void to disconnect the device + if(SDPConnected) + pBtd->l2cap_disconnection_request(hci_handle, ++identifier, sdp_scid, sdp_dcid); // 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, ++identifier, interrupt_scid, interrupt_dcid); Reset(); + l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE; l2cap_state = L2CAP_INTERRUPT_DISCONNECT; } @@ -59,13 +64,22 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR(" "), 0x80); D_PrintHex (l2capinbuf[6], 0x80); - Notify(PSTR("\r\nData: "), 0x80); - Notify(PSTR("\r\n"), 0x80); + Notify(PSTR(", data: "), 0x80); for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { D_PrintHex (l2capinbuf[i + 8], 0x80); Notify(PSTR(" "), 0x80); } + if(!connected) { + if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) { + pBtd->sdpConnectionClaimed = true; + hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection + l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state + } + } + } + if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) { if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { @@ -124,7 +138,12 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR(" Identifier: "), 0x80); D_PrintHex (l2capinbuf[9], 0x80); #endif - if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { + if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { + identifier = l2capinbuf[9]; + sdp_scid[0] = l2capinbuf[14]; + sdp_scid[1] = l2capinbuf[15]; + l2cap_set_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST); + } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { identifier = l2capinbuf[9]; control_scid[0] = l2capinbuf[14]; control_scid[1] = l2capinbuf[15]; @@ -137,7 +156,11 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } } 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]) { + if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { + //Notify(PSTR("\r\nSDP Configuration Complete"), 0x80); + identifier = l2capinbuf[9]; + l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); + } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS); @@ -148,7 +171,10 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } } } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { - if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { + if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { + //Notify(PSTR("\r\nSDP Configuration Request"), 0x80); + pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid); + } else 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]) { @@ -156,7 +182,13 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { 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]) { + if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80); +#endif + identifier = l2capinbuf[9]; + l2cap_set_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST); + } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80); #endif @@ -172,7 +204,11 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Reset(); } } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { - if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { + if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) { + //Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80); + identifier = l2capinbuf[9]; + l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE); + } else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80); identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE); @@ -181,6 +217,12 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE); } + } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nInformation request"), 0x80); +#endif + identifier = l2capinbuf[9]; + pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]); } #ifdef EXTRADEBUG else { @@ -188,6 +230,97 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); D_PrintHex (l2capinbuf[8], 0x80); } +#endif + } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP + if(l2capinbuf[8] == SDP_SERVICE_SEARCH_REQUEST) { + Notify(PSTR("\r\nSDP_SERVICE_SEARCH_REQUEST"), 0x80); + + // Send response + l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE; + l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; + l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow; +#if 1 + l2capoutbuf[3] = 0x00; // MSB Parameter Length + l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 + + l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount + l2capoutbuf[6] = 0x00; // LSB TotalServiceRecordCount = 0 + + l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount + l2capoutbuf[8] = 0x00; // LSB CurrentServiceRecordCount = 0 + + l2capoutbuf[9] = 0x00; // No continuation state + + SDP_Command(l2capoutbuf, 10); +#else + l2capoutbuf[3] = 0x00; // MSB Parameter Length + l2capoutbuf[4] = 0x09; // LSB Parameter Length = 9 + + l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount + l2capoutbuf[6] = 0x01; // LSB TotalServiceRecordCount = 1 + + l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount + l2capoutbuf[8] = 0x01; // LSB CurrentServiceRecordCount = 1 + + l2capoutbuf[9] = 0x00; // ServiceRecordHandleList + l2capoutbuf[10] = 0x01; // ServiceRecordHandleList + l2capoutbuf[11] = 0x00; // ServiceRecordHandleList + l2capoutbuf[12] = 0x01; // ServiceRecordHandleList: 0x10001. + + l2capoutbuf[13] = 0x00; // No continuation state + + SDP_Command(l2capoutbuf, 14); +#endif + } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) { + Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80); + + // Send response + l2capoutbuf[0] = SDP_SERVICE_ATTRIBUTE_RESPONSE; + l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; + l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow; + + l2capoutbuf[3] = 0x00; // MSB Parameter Length + l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 + + l2capoutbuf[5] = 0x00; // MSB AttributeListByteCount + l2capoutbuf[6] = 0x02; // LSB AttributeListByteCount = 2 + + // TODO: What to send? + l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte + l2capoutbuf[8] = 0x00; // Length = 0 + + l2capoutbuf[9] = 0x00; // No continuation state + + SDP_Command(l2capoutbuf, 10); + } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) { + Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU"), 0x80); + +#ifdef EXTRADEBUG + Notify(PSTR("\r\nUUID: "), 0x80); + uint16_t uuid; + if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID + uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]); + else // Short UUID + uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]); + D_PrintHex (uuid, 0x80); + + Notify(PSTR("\r\nLength: "), 0x80); + uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12]; + D_PrintHex (length, 0x80); + Notify(PSTR("\r\nData: "), 0x80); + for(uint8_t i = 0; i < length; i++) { + D_PrintHex (l2capinbuf[13 + i], 0x80); + Notify(PSTR(" "), 0x80); + } +#endif + + serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported + } +#ifdef EXTRADEBUG + else { + Notify(PSTR("\r\nUnknown PDU: "), 0x80); + D_PrintHex (l2capinbuf[8], 0x80); + } #endif } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt #ifdef PRINTREPORT @@ -243,10 +376,59 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } } #endif + SDP_task(); L2CAP_task(); } } +void BTHID::SDP_task() { + switch(l2cap_sdp_state) { + case L2CAP_SDP_WAIT: + if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST)) { + l2cap_clear_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST); // Clear flag +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80); +#endif + pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING); + delay(1); + pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, SUCCESSFUL); + identifier++; + delay(1); + pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid); + l2cap_sdp_state = L2CAP_SDP_SUCCESS; + } else if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST)) { + l2cap_clear_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST); // Clear flag + SDPConnected = false; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80); +#endif + pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid); + } + break; + case L2CAP_SDP_SUCCESS: + if(l2cap_check_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS)) { + l2cap_clear_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); // Clear flag +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSDP Successfully Configured"), 0x80); +#endif + SDPConnected = true; + l2cap_sdp_state = L2CAP_SDP_WAIT; + } + break; + + case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected + if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_RESPONSE)) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80); +#endif + pBtd->hci_disconnect(hci_handle); + hci_handle = -1; // Reset handle + Reset(); + } + break; + } +} + void BTHID::L2CAP_task() { switch(l2cap_state) { /* These states are used if the HID device is the host */ @@ -383,6 +565,27 @@ void BTHID::Run() { } } +void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs + pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]); +} + +void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[1] = transactionIDHigh; + l2capoutbuf[2] = transactionIDLow; + l2capoutbuf[3] = 0x00; // MSB Parameter Length + l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 + l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount + l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2 + + /* Attribute ID/Value Sequence: */ + l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte + l2capoutbuf[8] = 0x00; // Length = 0 + l2capoutbuf[9] = 0x00; // No continuation state + + SDP_Command(l2capoutbuf, 10); +} + /************************************************************/ /* HID Commands */ diff --git a/BTHID.h b/BTHID.h index 7d1d1116..b15649b5 100644 --- a/BTHID.h +++ b/BTHID.h @@ -141,20 +141,30 @@ protected: /** L2CAP source CID for HID_Interrupt */ uint8_t interrupt_scid[2]; + uint8_t l2cap_sdp_state; + uint8_t sdp_scid[2]; // L2CAP source CID for SDP + private: HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers. + uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data + void SDP_Command(uint8_t* data, uint8_t nbytes); + void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow); + /** Set report protocol. */ void setProtocol(); uint8_t protocolMode; + void SDP_task(); void L2CAP_task(); // L2CAP state machine bool activeConnection; // Used to indicate if it already has established a connection + bool SDPConnected; /* Variables used for L2CAP communication */ uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070 uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071 + uint8_t sdp_dcid[2]; uint8_t l2cap_state; }; #endif diff --git a/SPP.h b/SPP.h index bb3027b4..116296ca 100644 --- a/SPP.h +++ b/SPP.h @@ -20,12 +20,6 @@ #include "BTD.h" -/* Used for SDP */ -#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs -#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs -#define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm -#define L2CAP_UUID 0x0100 - /* Used for RFCOMM */ #define RFCOMM_SABM 0x2F #define RFCOMM_UA 0x63 From 8d7265f92c02e258538c7f77d606f8d6c551fe2d Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Wed, 3 Jul 2019 00:54:27 +0200 Subject: [PATCH 04/12] Try to figure out which HCI command that is failing --- BTD.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BTD.cpp b/BTD.cpp index 20d6b9cf..4855c65c 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -466,6 +466,12 @@ void BTD::HCI_event_task() { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nHCI Command Failed: "), 0x80); D_PrintHex (hcibuf[2], 0x80); + Notify(PSTR("\r\nNum HCI Command Packets: "), 0x80); + D_PrintHex (hcibuf[3], 0x80); + Notify(PSTR("\r\nCommand Opcode: "), 0x80); + D_PrintHex (hcibuf[4], 0x80); + Notify(PSTR(" "), 0x80); + D_PrintHex (hcibuf[5], 0x80); #endif } break; From ad9360b8653a9cc35291c563b8eea5e02f661c5d Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sat, 31 Aug 2019 18:22:21 +0200 Subject: [PATCH 05/12] Yet another go at getting the Xbox One S controller working It just connects and opens a SDP channel it then disconnects the SDP channel and I get a "Paring Faild: 05 (Authentication Failure)" For some reason I never receive the "IO Capability Request" event --- BTD.cpp | 64 +++++++++++++++++++- BTD.h | 11 +++- BTHID.cpp | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++---- SPP.cpp | 27 +-------- 4 files changed, 236 insertions(+), 41 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index 4855c65c..ade16f4c 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -430,26 +430,34 @@ void BTD::HCI_event_task() { D_PrintHex (hcibuf[8 + i], 0x80); } #endif -#ifdef DEBUG_USB_HOST if(hcibuf[6] == 0) { // Page 0 +#ifdef DEBUG_USB_HOST Notify(PSTR("\r\nDongle "), 0x80); +#endif if(hcibuf[8 + 6] & (1U << 3)) { simple_pairing_supported = true; +#ifdef DEBUG_USB_HOST Notify(PSTR("supports"), 0x80); +#endif } else { simple_pairing_supported = false; +#ifdef DEBUG_USB_HOST Notify(PSTR("does NOT support"), 0x80); +#endif } +#ifdef DEBUG_USB_HOST Notify(PSTR(" secure simple pairing (controller support)"), 0x80); +#endif } else if(hcibuf[6] == 1) { // Page 1 +#ifdef DEBUG_USB_HOST Notify(PSTR("\r\nDongle "), 0x80); if(hcibuf[8 + 0] & (1U << 0)) Notify(PSTR("supports"), 0x80); else Notify(PSTR("does NOT support"), 0x80); Notify(PSTR(" secure simple pairing (host support)"), 0x80); - } #endif + } } hci_set_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES); @@ -650,6 +658,10 @@ void BTD::HCI_event_task() { Notify(PSTR("\r\nPairing successful with HID device"), 0x80); #endif connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device + } else { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nPairing was successful"), 0x80); +#endif } } else { #ifdef DEBUG_USB_HOST @@ -744,6 +756,12 @@ void BTD::HCI_event_task() { if(hcibuf[0] != 0x00) { Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80); D_PrintHex (hcibuf[0], 0x80); + + Notify(PSTR(", data: "), 0x80); + for(uint16_t i = 0; i < hcibuf[1]; i++) { + D_PrintHex (hcibuf[2 + i], 0x80); + Notify(PSTR(" "), 0x80); + } } break; #endif @@ -939,6 +957,12 @@ void BTD::HCI_task() { case HCI_REMOTE_EXTENDED_FEATURES_STATE: if(hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) { + /*hci_read_remote_version_information(); + delay(1); + hci_change_connection_packet_type_command(); + delay(1); + hci_write_link_policy_settings(); + delay(1);*/ hci_authentication_request(); hci_state = HCI_SCANNING_STATE; } @@ -1255,7 +1279,7 @@ void BTD::hci_connect() { void BTD::hci_connect(uint8_t *bdaddr) { hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE | HCI_FLAG_CONNECT_EVENT); - hcibuf[0] = 0x05; + hcibuf[0] = 0x05; // HCI OCF = 5 hcibuf[1] = 0x01 << 2; // HCI OGF = 1 hcibuf[2] = 0x0D; // parameter Total Length = 13 hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB) @@ -1275,6 +1299,40 @@ void BTD::hci_connect(uint8_t *bdaddr) { HCI_Command(hcibuf, 16); } +void BTD::hci_read_remote_version_information() { + hcibuf[0] = 0x1D; // HCI OCF = 1D + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x02; // parameter Total Length = 2 + hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte + hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte + + HCI_Command(hcibuf, 5); +} + +void BTD::hci_change_connection_packet_type_command() { + hcibuf[0] = 0x0F; // HCI OCF = 0F + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x04; // parameter Total Length = 4 + hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte + hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte + hcibuf[5] = 0x18; // DM1 or DH1 may be used + hcibuf[6] = 0xCC; // DM3, DH3, DM5, DH5 may be used + + HCI_Command(hcibuf, 7); +} + +void BTD::hci_write_link_policy_settings() { + hcibuf[0] = 0x0D; // HCI OCF = 0D + hcibuf[1] = 0x02 << 2; // HCI OGF = 2 + hcibuf[2] = 0x04; // parameter Total Length = 4 + hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte + hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte + hcibuf[5] = 0x0F; // Enable role switch, enable hold mode, enable sniff mode, enable park mode + hcibuf[6] = 0x00; + + HCI_Command(hcibuf, 7); +} + void BTD::hci_pin_code_request_reply() { hcibuf[0] = 0x0D; // HCI OCF = 0D hcibuf[1] = 0x01 << 2; // HCI OGF = 1 diff --git a/BTD.h b/BTD.h index c12e325b..4ba59ef3 100644 --- a/BTD.h +++ b/BTD.h @@ -196,8 +196,8 @@ #define SDP_SERVICE_SEARCH_RESPONSE 0x03 #define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04 #define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05 -#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs -#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs +#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 // See the RFCOMM specs +#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 // See the RFCOMM specs #define PNP_INFORMATION_UUID 0x1200 #define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm #define L2CAP_UUID 0x0100 @@ -386,6 +386,13 @@ public: void hci_inquiry_cancel(); /** Connect to last device communicated with. */ void hci_connect(); + + void hci_read_remote_version_information(); + + void hci_change_connection_packet_type_command(); + + void hci_write_link_policy_settings(); + /** * Connect to device. * @param bdaddr Bluetooth address of the device. diff --git a/BTHID.cpp b/BTHID.cpp index 3928c7dd..6f9e0492 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -30,6 +30,8 @@ protocolMode(USB_HID_BOOT_PROTOCOL) { pBtd->btdPin = pin; /* Set device cid for the control and intterrupt channelse - LSB */ + sdp_dcid[0] = 0x50; // 0x0050 + sdp_dcid[1] = 0x00; control_dcid[0] = 0x70; // 0x0070 control_dcid[1] = 0x00; interrupt_dcid[0] = 0x71; // 0x0071 @@ -59,6 +61,7 @@ void BTHID::disconnect() { // Use this void to disconnect the device } void BTHID::ACLData(uint8_t* l2capinbuf) { +/* Notify(PSTR("\r\nL2CAP Data - Channel ID: "), 0x80); D_PrintHex (l2capinbuf[7], 0x80); Notify(PSTR(" "), 0x80); @@ -69,6 +72,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { D_PrintHex (l2capinbuf[i + 8], 0x80); Notify(PSTR(" "), 0x80); } +*/ if(!connected) { if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { @@ -111,14 +115,25 @@ 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]) { - //Notify(PSTR("\r\nHID Control Connection Complete"), 0x80); + if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) { + Notify(PSTR("\r\nSDP Connection Complete"), 0x80); + identifier = l2capinbuf[9]; + sdp_scid[0] = l2capinbuf[12]; + sdp_scid[1] = l2capinbuf[13]; + +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSend SDP Config Request"), 0x80); +#endif + identifier++; + pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid); + } else 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]; control_scid[1] = l2capinbuf[13]; l2cap_set_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); + Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80); identifier = l2capinbuf[9]; interrupt_scid[0] = l2capinbuf[12]; interrupt_scid[1] = l2capinbuf[13]; @@ -157,28 +172,28 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { - //Notify(PSTR("\r\nSDP Configuration Complete"), 0x80); + Notify(PSTR("\r\nSDP Configuration Complete"), 0x80); identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { - //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); + Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); identifier = l2capinbuf[9]; l2cap_set_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); + Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80); identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS); } } } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { - //Notify(PSTR("\r\nSDP Configuration Request"), 0x80); + Notify(PSTR("\r\nSDP Configuration Request"), 0x80); pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid); } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { - //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80); + 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); + 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) { @@ -271,6 +286,10 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { SDP_Command(l2capoutbuf, 14); #endif + + //pBtd->hci_authentication_request(); + //identifier++; + //pBtd->l2cap_connection_request(hci_handle, identifier, sdp_dcid, SDP_PSM); } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) { Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80); @@ -279,6 +298,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow; +#if 1 l2capoutbuf[3] = 0x00; // MSB Parameter Length l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 @@ -292,8 +312,139 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { l2capoutbuf[9] = 0x00; // No continuation state SDP_Command(l2capoutbuf, 10); - } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) { - Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU"), 0x80); +#else + size_t i = 3; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x5a; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x57; + l2capoutbuf[i++] = 0x35; + l2capoutbuf[i++] = 0x55; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x0a; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x35; + l2capoutbuf[i++] = 0x03; + l2capoutbuf[i++] = 0x19; + l2capoutbuf[i++] = 0x12; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x05; + l2capoutbuf[i++] = 0x35; + l2capoutbuf[i++] = 0x03; + l2capoutbuf[i++] = 0x19; + l2capoutbuf[i++] = 0x10; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x06; + l2capoutbuf[i++] = 0x35; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x65; + l2capoutbuf[i++] = 0x6e; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x6a; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x03; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x4c; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x4a; + l2capoutbuf[i++] = 0x34; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x03; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x10; + l2capoutbuf[i++] = 0x11; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x04; + l2capoutbuf[i++] = 0x28; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x02; + l2capoutbuf[i++] = 0x05; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0xa0; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x16; + l2capoutbuf[i++] = 0xc4; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0xaf; + l2capoutbuf[i++] = 0xff; + l2capoutbuf[i++] = 0x09; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x01; + l2capoutbuf[i++] = 0x00; + + Serial.print("\nLENGTH: "); + Serial.println(i); + + SDP_Command(l2capoutbuf, i); +#endif + +/* + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST; + l2capoutbuf[1] = 0x00; // TODO: Do not hardcode + l2capoutbuf[2] = 0x01; + + l2capoutbuf[3] = 0x00; // MSB Parameter Length + l2capoutbuf[4] = 0x0F; // LSB Parameter Length = 15 + + i = 5; + l2capoutbuf[i++] = 0x35; + l2capoutbuf[i++] = 0x03; + l2capoutbuf[i++] = 0x19; + l2capoutbuf[i++] = 0x12; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0xff; + l2capoutbuf[i++] = 0xff; + l2capoutbuf[i++] = 0x35; + l2capoutbuf[i++] = 0x05; + l2capoutbuf[i++] = 0x0a; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0x00; + l2capoutbuf[i++] = 0xff; + l2capoutbuf[i++] = 0xff; + l2capoutbuf[i++] = 0x00; + + Serial.print("\nLENGTH: "); + Serial.println(i); + + SDP_Command(l2capoutbuf, i); +*/ + } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) { + Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80); #ifdef EXTRADEBUG Notify(PSTR("\r\nUUID: "), 0x80); @@ -570,7 +721,7 @@ void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the } void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE; l2capoutbuf[1] = transactionIDHigh; l2capoutbuf[2] = transactionIDLow; l2capoutbuf[3] = 0x00; // MSB Parameter Length diff --git a/SPP.cpp b/SPP.cpp index 009ea7bc..5e421097 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -189,7 +189,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) { } #endif } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP - if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) { + if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) { if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == SERIALPORT_UUID)) { // Check if it's sending the full UUID, see: https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm, we will just check the first four bytes if(firstMessage) { serialPortResponse1(l2capinbuf[9], l2capinbuf[10]); @@ -531,29 +531,8 @@ void SPP::RFCOMM_task() { /* SDP Commands */ /************************************************************/ -void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs - pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]); -} - -void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; - l2capoutbuf[1] = transactionIDHigh; - l2capoutbuf[2] = transactionIDLow; - l2capoutbuf[3] = 0x00; // MSB Parameter Length - l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 - l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount - l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2 - - /* Attribute ID/Value Sequence: */ - l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte - l2capoutbuf[8] = 0x00; // Length = 0 - l2capoutbuf[9] = 0x00; // No continuation state - - SDP_Command(l2capoutbuf, 10); -} - void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) { - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE; l2capoutbuf[1] = transactionIDHigh; l2capoutbuf[2] = transactionIDLow; l2capoutbuf[3] = 0x00; // MSB Parameter Length @@ -615,7 +594,7 @@ void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLo } void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) { - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU; + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE; l2capoutbuf[1] = transactionIDHigh; l2capoutbuf[2] = transactionIDLow; l2capoutbuf[3] = 0x00; // MSB Parameter Length From 102746ef6bb2fe5f5cce428522673be1591c2b6b Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 17:29:54 +0100 Subject: [PATCH 06/12] Xbox One S controller support is now finally working --- BTD.cpp | 186 +++++++++------------ BTD.h | 34 ++-- BTHID.cpp | 207 ++++-------------------- README.md | 11 +- SPP.cpp | 21 +++ XBOXONESBT.h | 100 ++++++++++++ XBOXONESParser.cpp | 200 +++++++++++++++++++++++ XBOXONESParser.h | 127 +++++++++++++++ controllerEnums.h | 6 + examples/Xbox/XBOXONESBT/XBOXONESBT.ino | 135 ++++++++++++++++ keywords.txt | 4 + settings.h | 2 +- 12 files changed, 726 insertions(+), 307 deletions(-) create mode 100644 XBOXONESBT.h create mode 100644 XBOXONESParser.cpp create mode 100644 XBOXONESParser.h create mode 100644 examples/Xbox/XBOXONESBT/XBOXONESBT.ino diff --git a/BTD.cpp b/BTD.cpp index ade16f4c..bd2d2587 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -17,7 +17,7 @@ #include "BTD.h" // To enable serial debugging see "settings.h" -#define EXTRADEBUG // Uncomment to get even more debugging data +//#define EXTRADEBUG // Uncomment to get even more debugging data const uint8_t BTD::BTD_CONTROL_PIPE = 0; const uint8_t BTD::BTD_EVENT_PIPE = 1; @@ -542,7 +542,6 @@ void BTD::HCI_event_task() { if(classOfDevice[0] & 0x08) Notify(PSTR("\r\nGamepad found"), 0x80); #endif - for(uint8_t j = 0; j < 6; j++) disc_bdaddr[j] = hcibuf[j + 3 + 6 * i]; @@ -673,62 +672,49 @@ void BTD::HCI_event_task() { } break; - case EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE: - if(!hcibuf[2]) { // Check if connected OK - if(!hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) { + case EV_IO_CAPABILITY_REQUEST: +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nReceived IO Capability Request"), 0x80); +#endif + hci_io_capability_request_reply(); + break; + + case EV_IO_CAPABILITY_RESPONSE: #ifdef EXTRADEBUG - Notify(PSTR("\r\nPage number: "), 0x80); - D_PrintHex (hcibuf[5], 0x80); - Notify(PSTR("\r\nMaximum page number: "), 0x80); - D_PrintHex (hcibuf[6], 0x80); - Notify(PSTR("\r\nExtended LMP features:"), 0x80); - for(uint8_t i = 0; i < 8; i++) { - Notify(PSTR(" "), 0x80); - D_PrintHex (hcibuf[7 + i], 0x80); - } + Notify(PSTR("\r\nReceived IO Capability Response: "), 0x80); + Notify(PSTR("\r\nIO capability: "), 0x80); + D_PrintHex (hcibuf[8], 0x80); + Notify(PSTR("\r\nOOB data present: "), 0x80); + D_PrintHex (hcibuf[9], 0x80); + Notify(PSTR("\r\nAuthentication request: "), 0x80); + D_PrintHex (hcibuf[10], 0x80); #endif -#ifdef DEBUG_USB_HOST - if(hcibuf[5] == 0) { // Page 0 - Notify(PSTR("\r\nRemote "), 0x80); - if(hcibuf[7 + 6] & (1U << 3)) - Notify(PSTR("supports"), 0x80); - else - Notify(PSTR("does NOT support"), 0x80); - Notify(PSTR(" secure simple pairing (controller support)"), 0x80); - } else if(hcibuf[5] == 1) { // Page 1 - Notify(PSTR("\r\nRemote "), 0x80); - if(hcibuf[7 + 0] & (1U << 0)) - Notify(PSTR("supports"), 0x80); - else - Notify(PSTR("\r\ndoes NOT support"), 0x80); - Notify(PSTR(" secure simple pairing (host support)"), 0x80); - } -#endif - } - hci_set_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES); - } else { - hci_state = HCI_CHECK_DEVICE_SERVICE; -#ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nFailed to read remote extended featues: "), 0x80); - D_PrintHex (hcibuf[2], 0x80); -#endif - } break; case EV_USER_CONFIRMATION_REQUEST: #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nUser confirmation Request: "), 0x80); -#endif + Notify(PSTR("\r\nUser confirmation Request"), 0x80); #ifdef EXTRADEBUG - Notify(PSTR("\r\nNumeric value: "), 0x80); + Notify(PSTR(": \r\nNumeric value: "), 0x80); for(uint8_t i = 0; i < 4; i++) { Notify(PSTR(" "), 0x80); D_PrintHex (hcibuf[8 + i], 0x80); } #endif - +#endif + // Simply confirm the connection, as the host has no "NoInputNoOutput" capabilities hci_user_confirmation_request_reply(); - hci_state = HCI_SCANNING_STATE; + break; + + case EV_SIMPLE_PAIRING_COMPLETE: +#ifdef EXTRADEBUG + if(!hcibuf[2]) { // Check if connected OK + Notify(PSTR("\r\nSimple Pairing succeeded"), 0x80); + } else { + Notify(PSTR("\r\nSimple Pairing failed: "), 0x80); + D_PrintHex (hcibuf[2], 0x80); + } +#endif break; /* We will just ignore the following events */ @@ -756,7 +742,6 @@ void BTD::HCI_event_task() { if(hcibuf[0] != 0x00) { Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80); D_PrintHex (hcibuf[0], 0x80); - Notify(PSTR(", data: "), 0x80); for(uint16_t i = 0; i < hcibuf[1]; i++) { D_PrintHex (hcibuf[2 + i], 0x80); @@ -872,6 +857,16 @@ void BTD::HCI_task() { if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nSimple pairing was enabled"), 0x80); +#endif + hci_set_event_mask(); + hci_state = HCI_SET_EVENT_MASK_STATE; + } + break; + + case HCI_SET_EVENT_MASK_STATE: + if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nSet event mask completed"), 0x80); #endif hci_state = HCI_CHECK_DEVICE_SERVICE; } @@ -943,9 +938,8 @@ void BTD::HCI_task() { else Notify(PSTR("\r\nConnected to HID device"), 0x80); #endif - hci_read_remote_extended_features(0); // "Requests the normal LMP features as returned by the HCI_Read_Remote_Supported_Features command" - //hci_read_remote_extended_features(1); // Read page 1 - hci_state = HCI_REMOTE_EXTENDED_FEATURES_STATE; + hci_authentication_request(); // This will start the pairing with the device + hci_state = HCI_SCANNING_STATE; } else { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nTrying to connect one more time..."), 0x80); @@ -955,19 +949,6 @@ void BTD::HCI_task() { } break; - case HCI_REMOTE_EXTENDED_FEATURES_STATE: - if(hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) { - /*hci_read_remote_version_information(); - delay(1); - hci_change_connection_packet_type_command(); - delay(1); - hci_write_link_policy_settings(); - delay(1);*/ - hci_authentication_request(); - hci_state = HCI_SCANNING_STATE; - } - break; - case HCI_SCANNING_STATE: if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) { #ifdef DEBUG_USB_HOST @@ -1218,18 +1199,6 @@ void BTD::hci_remote_name() { HCI_Command(hcibuf, 13); } -void BTD::hci_read_remote_extended_features(uint8_t page_number) { - hci_clear_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES); - hcibuf[0] = 0x1C; // HCI OCF = 1C - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x03; // parameter length = 3 - hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte - hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte - hcibuf[5] = page_number; - - HCI_Command(hcibuf, 6); -} - void BTD::hci_write_local_name(const char* name) { hcibuf[0] = 0x13; // HCI OCF = 13 hcibuf[1] = 0x03 << 2; // HCI OGF = 3 @@ -1242,6 +1211,24 @@ void BTD::hci_write_local_name(const char* name) { HCI_Command(hcibuf, 4 + strlen(name)); } +void BTD::hci_set_event_mask() { + hcibuf[0] = 0x01; // HCI OCF = 01 + hcibuf[1] = 0x03 << 2; // HCI OGF = 3 + hcibuf[2] = 0x08; + // The first 6 bytes are the default of 1FFF FFFF FFFF + // However we need to set bits 48-55 for simple pairing to work + hcibuf[3] = 0xFF; + hcibuf[4] = 0xFF; + hcibuf[5] = 0xFF; + hcibuf[6] = 0xFF; + hcibuf[7] = 0xFF; + hcibuf[8] = 0x1F; + hcibuf[9] = 0xFF; // Enable bits 48-55 used for simple pairing + hcibuf[10] = 0x00; + + HCI_Command(hcibuf, 11); +} + void BTD::hci_write_simple_pairing_mode(bool enable) { hcibuf[0] = 0x56; // HCI OCF = 56 hcibuf[1] = 0x03 << 2; // HCI OGF = 3 @@ -1299,40 +1286,6 @@ void BTD::hci_connect(uint8_t *bdaddr) { HCI_Command(hcibuf, 16); } -void BTD::hci_read_remote_version_information() { - hcibuf[0] = 0x1D; // HCI OCF = 1D - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x02; // parameter Total Length = 2 - hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte - hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte - - HCI_Command(hcibuf, 5); -} - -void BTD::hci_change_connection_packet_type_command() { - hcibuf[0] = 0x0F; // HCI OCF = 0F - hcibuf[1] = 0x01 << 2; // HCI OGF = 1 - hcibuf[2] = 0x04; // parameter Total Length = 4 - hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte - hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte - hcibuf[5] = 0x18; // DM1 or DH1 may be used - hcibuf[6] = 0xCC; // DM3, DH3, DM5, DH5 may be used - - HCI_Command(hcibuf, 7); -} - -void BTD::hci_write_link_policy_settings() { - hcibuf[0] = 0x0D; // HCI OCF = 0D - hcibuf[1] = 0x02 << 2; // HCI OGF = 2 - hcibuf[2] = 0x04; // parameter Total Length = 4 - hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte - hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte - hcibuf[5] = 0x0F; // Enable role switch, enable hold mode, enable sniff mode, enable park mode - hcibuf[6] = 0x00; - - HCI_Command(hcibuf, 7); -} - void BTD::hci_pin_code_request_reply() { hcibuf[0] = 0x0D; // HCI OCF = 0D hcibuf[1] = 0x01 << 2; // HCI OGF = 1 @@ -1397,6 +1350,23 @@ void BTD::hci_link_key_request_negative_reply() { HCI_Command(hcibuf, 9); } +void BTD::hci_io_capability_request_reply() { + hcibuf[0] = 0x2B; // HCI OCF = 2B + hcibuf[1] = 0x01 << 2; // HCI OGF = 1 + hcibuf[2] = 0x09; + hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr + hcibuf[4] = disc_bdaddr[1]; + hcibuf[5] = disc_bdaddr[2]; + hcibuf[6] = disc_bdaddr[3]; + hcibuf[7] = disc_bdaddr[4]; + hcibuf[8] = disc_bdaddr[5]; + hcibuf[9] = 0x03; // NoInputNoOutput + hcibuf[10] = 0x00; // OOB authentication data not present + hcibuf[11] = 0x00; // MITM Protection Not Required – No Bonding. Numeric comparison with automatic accept allowed + + HCI_Command(hcibuf, 12); +} + void BTD::hci_user_confirmation_request_reply() { hcibuf[0] = 0x2C; // HCI OCF = 2C hcibuf[1] = 0x01 << 2; // HCI OGF = 1 diff --git a/BTD.h b/BTD.h index 4ba59ef3..e0b3a46d 100644 --- a/BTD.h +++ b/BTD.h @@ -61,7 +61,7 @@ #define HCI_DISCONNECT_STATE 16 #define HCI_LOCAL_EXTENDED_FEATURES_STATE 17 #define HCI_WRITE_SIMPLE_PAIRING_STATE 18 -#define HCI_REMOTE_EXTENDED_FEATURES_STATE 19 +#define HCI_SET_EVENT_MASK_STATE 19 /* HCI event flags*/ #define HCI_FLAG_CMD_COMPLETE (1UL << 0) @@ -74,7 +74,6 @@ #define HCI_FLAG_DEVICE_FOUND (1UL << 7) #define HCI_FLAG_CONNECT_EVENT (1UL << 8) #define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9) -#define HCI_FLAG_REMOTE_EXTENDED_FEATURES (1UL << 10) /* Macros for HCI event flag tests */ #define hci_check_flag(flag) (hci_event_flag & (flag)) @@ -91,6 +90,10 @@ #define EV_REMOTE_NAME_COMPLETE 0x07 #define EV_ENCRYPTION_CHANGE 0x08 #define EV_CHANGE_CONNECTION_LINK 0x09 +#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C +#define EV_QOS_SETUP_COMPLETE 0x0D +#define EV_COMMAND_COMPLETE 0x0E +#define EV_COMMAND_STATUS 0x0F #define EV_ROLE_CHANGED 0x12 #define EV_NUM_COMPLETE_PKT 0x13 #define EV_PIN_CODE_REQUEST 0x16 @@ -98,15 +101,13 @@ #define EV_LINK_KEY_NOTIFICATION 0x18 #define EV_DATA_BUFFER_OVERFLOW 0x1A #define EV_MAX_SLOTS_CHANGE 0x1B -#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C -#define EV_QOS_SETUP_COMPLETE 0x0D -#define EV_COMMAND_COMPLETE 0x0E -#define EV_COMMAND_STATUS 0x0F #define EV_LOOPBACK_COMMAND 0x19 #define EV_PAGE_SCAN_REP_MODE 0x20 #define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23 +#define EV_IO_CAPABILITY_REQUEST 0x31 +#define EV_IO_CAPABILITY_RESPONSE 0x32 #define EV_USER_CONFIRMATION_REQUEST 0x33 - +#define EV_SIMPLE_PAIRING_COMPLETE 0x36 /* Bluetooth states for the different Bluetooth drivers */ #define L2CAP_WAIT 0 @@ -339,23 +340,23 @@ public: void hci_read_bdaddr(); /** Read the HCI Version of the Bluetooth dongle. */ void hci_read_local_version_information(); - + /** Used to check if the dongle supports simple paring */ void hci_read_local_extended_features(uint8_t page_number); /** * Set the local name of the Bluetooth dongle. * @param name Desired name. */ void hci_write_local_name(const char* name); - + /** Used to enable simply paring if the dongle supports it */ void hci_write_simple_pairing_mode(bool enable); + /** Used to enable events related to simple paring */ + void hci_set_event_mask(); /** Enable visibility to other Bluetooth devices. */ void hci_write_scan_enable(); /** Disable visibility to other Bluetooth devices. */ void hci_write_scan_disable(); /** Read the remote devices name. */ void hci_remote_name(); - - void hci_read_remote_extended_features(uint8_t page_number); /** Accept the connection with the Bluetooth device. */ void hci_accept_connection(); /** @@ -376,7 +377,7 @@ public: * if the Host does not have a stored Link Key for the connection. */ void hci_link_key_request_negative_reply(); - + /** Used to during simple paring to confirm that the we want to connect */ void hci_user_confirmation_request_reply(); /** Used to try to authenticate with the remote device. */ void hci_authentication_request(); @@ -386,13 +387,8 @@ public: void hci_inquiry_cancel(); /** Connect to last device communicated with. */ void hci_connect(); - - void hci_read_remote_version_information(); - - void hci_change_connection_packet_type_command(); - - void hci_write_link_policy_settings(); - + /** Used during simple paring to reply to a IO capability request */ + void hci_io_capability_request_reply(); /** * Connect to device. * @param bdaddr Bluetooth address of the device. diff --git a/BTHID.cpp b/BTHID.cpp index 6f9e0492..ad2a0ac2 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -17,7 +17,7 @@ #include "BTHID.h" // To enable serial debugging see "settings.h" -#define EXTRADEBUG // Uncomment to get even more debugging data +//#define EXTRADEBUG // Uncomment to get even more debugging data //#define PRINTREPORT // Uncomment to print the report send by the HID device BTHID::BTHID(BTD *p, bool pair, const char *pin) : @@ -61,19 +61,6 @@ void BTHID::disconnect() { // Use this void to disconnect the device } void BTHID::ACLData(uint8_t* l2capinbuf) { -/* - Notify(PSTR("\r\nL2CAP Data - Channel ID: "), 0x80); - D_PrintHex (l2capinbuf[7], 0x80); - Notify(PSTR(" "), 0x80); - D_PrintHex (l2capinbuf[6], 0x80); - - Notify(PSTR(", data: "), 0x80); - for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) { - D_PrintHex (l2capinbuf[i + 8], 0x80); - Notify(PSTR(" "), 0x80); - } -*/ - if(!connected) { if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) { @@ -116,24 +103,29 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } 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] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nSDP Connection Complete"), 0x80); +#endif identifier = l2capinbuf[9]; sdp_scid[0] = l2capinbuf[12]; sdp_scid[1] = l2capinbuf[13]; - #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nSend SDP Config Request"), 0x80); #endif identifier++; pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid); } else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nHID Control Connection Complete"), 0x80); +#endif identifier = l2capinbuf[9]; control_scid[0] = l2capinbuf[12]; control_scid[1] = l2capinbuf[13]; l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED); } else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80); +#endif identifier = l2capinbuf[9]; interrupt_scid[0] = l2capinbuf[12]; interrupt_scid[1] = l2capinbuf[13]; @@ -172,28 +164,40 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nSDP Configuration Complete"), 0x80); +#endif identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); +#endif identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS); } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80); +#endif identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS); } } } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nSDP Configuration Request"), 0x80); +#endif pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid); } else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nHID Control Configuration Request"), 0x80); +#endif pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid); } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80); +#endif pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid); } } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { @@ -220,15 +224,21 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) { - //Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80); +#ifdef EXTRADEBUG + Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80); +#endif identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE); } else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { - //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80); +#ifdef EXTRADEBUG + Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80); +#endif identifier = l2capinbuf[9]; l2cap_set_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); +#ifdef EXTRADEBUG + Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80); +#endif identifier = l2capinbuf[9]; l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE); } @@ -254,7 +264,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE; l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow; -#if 1 + l2capoutbuf[3] = 0x00; // MSB Parameter Length l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 @@ -267,29 +277,6 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { l2capoutbuf[9] = 0x00; // No continuation state SDP_Command(l2capoutbuf, 10); -#else - l2capoutbuf[3] = 0x00; // MSB Parameter Length - l2capoutbuf[4] = 0x09; // LSB Parameter Length = 9 - - l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount - l2capoutbuf[6] = 0x01; // LSB TotalServiceRecordCount = 1 - - l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount - l2capoutbuf[8] = 0x01; // LSB CurrentServiceRecordCount = 1 - - l2capoutbuf[9] = 0x00; // ServiceRecordHandleList - l2capoutbuf[10] = 0x01; // ServiceRecordHandleList - l2capoutbuf[11] = 0x00; // ServiceRecordHandleList - l2capoutbuf[12] = 0x01; // ServiceRecordHandleList: 0x10001. - - l2capoutbuf[13] = 0x00; // No continuation state - - SDP_Command(l2capoutbuf, 14); -#endif - - //pBtd->hci_authentication_request(); - //identifier++; - //pBtd->l2cap_connection_request(hci_handle, identifier, sdp_dcid, SDP_PSM); } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) { Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80); @@ -298,7 +285,6 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow; -#if 1 l2capoutbuf[3] = 0x00; // MSB Parameter Length l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 @@ -312,141 +298,9 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { l2capoutbuf[9] = 0x00; // No continuation state SDP_Command(l2capoutbuf, 10); -#else - size_t i = 3; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x5a; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x57; - l2capoutbuf[i++] = 0x35; - l2capoutbuf[i++] = 0x55; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x0a; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x35; - l2capoutbuf[i++] = 0x03; - l2capoutbuf[i++] = 0x19; - l2capoutbuf[i++] = 0x12; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x05; - l2capoutbuf[i++] = 0x35; - l2capoutbuf[i++] = 0x03; - l2capoutbuf[i++] = 0x19; - l2capoutbuf[i++] = 0x10; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x06; - l2capoutbuf[i++] = 0x35; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x65; - l2capoutbuf[i++] = 0x6e; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x6a; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x03; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x4c; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x4a; - l2capoutbuf[i++] = 0x34; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x03; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x10; - l2capoutbuf[i++] = 0x11; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x04; - l2capoutbuf[i++] = 0x28; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x02; - l2capoutbuf[i++] = 0x05; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0xa0; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x16; - l2capoutbuf[i++] = 0xc4; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0xaf; - l2capoutbuf[i++] = 0xff; - l2capoutbuf[i++] = 0x09; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x01; - l2capoutbuf[i++] = 0x00; - - Serial.print("\nLENGTH: "); - Serial.println(i); - - SDP_Command(l2capoutbuf, i); -#endif - -/* - l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST; - l2capoutbuf[1] = 0x00; // TODO: Do not hardcode - l2capoutbuf[2] = 0x01; - - l2capoutbuf[3] = 0x00; // MSB Parameter Length - l2capoutbuf[4] = 0x0F; // LSB Parameter Length = 15 - - i = 5; - l2capoutbuf[i++] = 0x35; - l2capoutbuf[i++] = 0x03; - l2capoutbuf[i++] = 0x19; - l2capoutbuf[i++] = 0x12; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0xff; - l2capoutbuf[i++] = 0xff; - l2capoutbuf[i++] = 0x35; - l2capoutbuf[i++] = 0x05; - l2capoutbuf[i++] = 0x0a; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0x00; - l2capoutbuf[i++] = 0xff; - l2capoutbuf[i++] = 0xff; - l2capoutbuf[i++] = 0x00; - - Serial.print("\nLENGTH: "); - Serial.println(i); - - SDP_Command(l2capoutbuf, i); -*/ } else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) { - Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80); - #ifdef EXTRADEBUG + Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80); Notify(PSTR("\r\nUUID: "), 0x80); uint16_t uuid; if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID @@ -464,7 +318,6 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { Notify(PSTR(" "), 0x80); } #endif - serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported } #ifdef EXTRADEBUG diff --git a/README.md b/README.md index 8b8a5d4b..ea42cdca 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir * __Oleg Mazurov, Circuits@Home__ - * __Alexei Glushchenko, Circuits@Home__ - * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries -* __Kristian Lauszus, TKJ Electronics__ - +* __Kristian Sloth Lauszus__ - * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries * __Andrew Kroll__ - * Major contributor to mass storage code @@ -55,6 +55,7 @@ Help yourself by helping us support you! Many thousands of hours have been spent * [Xbox library](#xbox-library) * [Xbox 360 Library](#xbox-360-library) * [Xbox ONE Library](#xbox-one-library) + * [Xbox ONE S Library](#xbox-one-s-library) * [Wii library](#wii-library) * [PS Buzz Library](#ps-buzz-library) * [HID Libraries](#hid-libraries) @@ -262,12 +263,18 @@ All the information regarding the Xbox 360 controller protocol are form these si #### Xbox ONE Library -An Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at: +A Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at: * * * +#### Xbox ONE S Library + +A Xbox ONE controller is supported via Bluetooth in the [XBOXONESBT](XBOXONESBT.cpp) class. + +Special thanks to [HisashiKato](https://github.com/HisashiKato) for his help: . + ### [Wii library](Wii.cpp) The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller and Wii Balance Board are also supported via Bluetooth. diff --git a/SPP.cpp b/SPP.cpp index 5e421097..910f7db8 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -531,6 +531,27 @@ void SPP::RFCOMM_task() { /* SDP Commands */ /************************************************************/ +void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs + pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]); +} + +void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs + l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE; + l2capoutbuf[1] = transactionIDHigh; + l2capoutbuf[2] = transactionIDLow; + l2capoutbuf[3] = 0x00; // MSB Parameter Length + l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5 + l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount + l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2 + + /* Attribute ID/Value Sequence: */ + l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte + l2capoutbuf[8] = 0x00; // Length = 0 + l2capoutbuf[9] = 0x00; // No continuation state + + SDP_Command(l2capoutbuf, 10); +} + void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) { l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE; l2capoutbuf[1] = transactionIDHigh; diff --git a/XBOXONESBT.h b/XBOXONESBT.h new file mode 100644 index 00000000..82b17d24 --- /dev/null +++ b/XBOXONESBT.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2020 Kristian Sloth Lauszus. 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 Sloth Lauszus + Web : https://lauszus.com + e-mail : lauszus@gmail.com + */ + +#ifndef _xboxonesbt_h_ +#define _xboxonesbt_h_ + +#include "BTHID.h" +#include "XBOXONESParser.h" + +/** + * This class implements support for the Xbox One S controller via Bluetooth. + * It uses the BTHID class for all the Bluetooth communication. + */ +class XBOXONESBT : public BTHID, public XBOXONESParser { +public: + /** + * Constructor for the XBOXONESBT 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. + */ + XBOXONESBT(BTD *p, bool pair = false) : + BTHID(p, pair) { + XBOXONESParser::Reset(); + }; + + /** + * Used to check if a Xbox One S controller is connected. + * @return Returns true if it is connected. + */ + bool connected() { + return BTHID::connected; + }; + +protected: + /** @name BTHID implementation */ + /** + * Used to parse Bluetooth HID data. + * @param len The length of the incoming data. + * @param buf Pointer to the data buffer. + */ + virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) { + XBOXONESParser::Parse(len, buf); + }; + + /** + * Called when a device 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. + */ + virtual void OnInitBTHID() { + XBOXONESParser::Reset(); + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + }; + + /** Used to reset the different buffers to there default values */ + virtual void ResetBTHID() { + XBOXONESParser::Reset(); + }; + /**@}*/ + +#if 0 + /** @name XBOXONESParser implementation */ + virtual void sendOutputReport(uint8_t *data, uint8_t nbytes) { + // See: https://lore.kernel.org/patchwork/patch/973394/ + uint8_t buf[nbytes + 2]; + + buf[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02) + buf[1] = 0x03; // Report ID + + memcpy(buf + 2, data, nbytes); + + Notify(PSTR("\r\n"), 0x80); + for (uint8_t i = 0; i < sizeof(buf); i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); + + //pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); + pBtd->L2CAP_Command(hci_handle, buf, sizeof(buf), control_scid[0], control_scid[1]); + }; + /**@}*/ +#endif +}; +#endif diff --git a/XBOXONESParser.cpp b/XBOXONESParser.cpp new file mode 100644 index 00000000..e8f0064f --- /dev/null +++ b/XBOXONESParser.cpp @@ -0,0 +1,200 @@ +/* Copyright (C) 2020 Kristian Sloth Lauszus. 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 Sloth Lauszus + Web : https://lauszus.com + e-mail : lauszus@gmail.com + */ + +#include "XBOXONESParser.h" + +// To enable serial debugging see "settings.h" +//#define PRINTREPORT // Uncomment to print the report send by the Xbox One S Controller + +/** Buttons on the controller */ +const uint8_t XBOX_ONE_S_BUTTONS[] PROGMEM = { + UP, // UP + RIGHT, // RIGHT + DOWN, // DOWN + LEFT, // LEFT + + 0x0E, // VIEW + 0x0F, // MENU + 0x10, // L3 + 0x11, // R3 + + 0, 0, // Skip L2 and R2 as these are analog buttons + 0x0C, // L1 + 0x0D, // R1 + + 0x09, // B + 0x08, // A + 0x0A, // X + 0x0B, // Y +}; + +enum DPADEnum { + DPAD_OFF = 0x0, + DPAD_UP = 0x1, + DPAD_UP_RIGHT = 0x2, + DPAD_RIGHT = 0x3, + DPAD_RIGHT_DOWN = 0x4, + DPAD_DOWN = 0x5, + DPAD_DOWN_LEFT = 0x6, + DPAD_LEFT = 0x7, + DPAD_LEFT_UP = 0x8, +}; + +bool XBOXONESParser::checkDpad(ButtonEnum b) { + switch (b) { + case UP: + return xboxOneSData.btn.dpad == DPAD_LEFT_UP || xboxOneSData.btn.dpad == DPAD_UP || xboxOneSData.btn.dpad == DPAD_UP_RIGHT; + case RIGHT: + return xboxOneSData.btn.dpad == DPAD_UP_RIGHT || xboxOneSData.btn.dpad == DPAD_RIGHT || xboxOneSData.btn.dpad == DPAD_RIGHT_DOWN; + case DOWN: + return xboxOneSData.btn.dpad == DPAD_RIGHT_DOWN || xboxOneSData.btn.dpad == DPAD_DOWN || xboxOneSData.btn.dpad == DPAD_DOWN_LEFT; + case LEFT: + return xboxOneSData.btn.dpad == DPAD_DOWN_LEFT || xboxOneSData.btn.dpad == DPAD_LEFT || xboxOneSData.btn.dpad == DPAD_LEFT_UP; + default: + return false; + } +} + +uint16_t XBOXONESParser::getButtonPress(ButtonEnum b) { + if (b == L2) + return xboxOneSData.trigger[0]; + else if (b == R2) + return xboxOneSData.trigger[1]; + else if (b <= LEFT) // Dpad + return checkDpad(b); + else if (b == XBOX) + return xboxButtonState; + return xboxOneSData.btn.val & (1UL << pgm_read_byte(&XBOX_ONE_S_BUTTONS[(uint8_t)b])); +} + +bool XBOXONESParser::getButtonClick(ButtonEnum b) { + if(b == L2) { + if(L2Clicked) { + L2Clicked = false; + return true; + } + return false; + } else if(b == R2) { + if(R2Clicked) { + R2Clicked = false; + return true; + } + return false; + } else if (b == XBOX) { + bool click = xboxbuttonClickState; + xboxbuttonClickState = 0; // Clear "click" event + return click; + } + uint32_t mask = 1UL << pgm_read_byte(&XBOX_ONE_S_BUTTONS[(uint8_t)b]); + bool click = buttonClickState.val & mask; + buttonClickState.val &= ~mask; // Clear "click" event + return click; +} + +int16_t XBOXONESParser::getAnalogHat(AnalogHatEnum a) { + return xboxOneSData.hatValue[(uint8_t)a] - 32768; // Convert to signed integer +} + +void XBOXONESParser::Parse(uint8_t len, uint8_t *buf) { + if (len > 1 && buf) { +#ifdef PRINTREPORT + Notify(PSTR("\r\n"), 0x80); + for (uint8_t i = 0; i < len; i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } +#endif + + if (buf[0] == 0x01) // Check report ID + memcpy(&xboxOneSData, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(xboxOneSData))); + else if (buf[0] == 0x02) { // This report contains the Xbox button + xboxButtonState = buf[1]; + if(xboxButtonState != xboxOldButtonState) { + xboxbuttonClickState = xboxButtonState & ~xboxOldButtonState; // Update click state variable + xboxOldButtonState = xboxButtonState; + } + return; + } else if (buf[0] == 0x04) // Heartbeat + return; + else { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nUnknown report id: "), 0x80); + D_PrintHex (buf[0], 0x80); +#endif + return; + } + + if (xboxOneSData.btn.val != oldButtonState.val) { // Check if anything has changed + buttonClickState.val = xboxOneSData.btn.val & ~oldButtonState.val; // Update click state variable + oldButtonState.val = xboxOneSData.btn.val; + + // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself + uint8_t newDpad = 0; + if (checkDpad(UP)) + newDpad |= 1 << UP; + if (checkDpad(RIGHT)) + newDpad |= 1 << RIGHT; + if (checkDpad(DOWN)) + newDpad |= 1 << DOWN; + if (checkDpad(LEFT)) + newDpad |= 1 << LEFT; + if (newDpad != oldDpad) { + buttonClickState.dpad = newDpad & ~oldDpad; // Override values + oldDpad = newDpad; + } + } + + // Handle click detection for triggers + if(xboxOneSData.trigger[0] != 0 && triggerOld[0] == 0) + L2Clicked = true; + triggerOld[0] = xboxOneSData.trigger[0]; + if(xboxOneSData.trigger[1] != 0 && triggerOld[1] == 0) + R2Clicked = true; + triggerOld[1] = xboxOneSData.trigger[1]; + } +} + +void XBOXONESParser::Reset() { + uint8_t i; + for (i = 0; i < sizeof(xboxOneSData.hatValue) / sizeof(xboxOneSData.hatValue[0]); i++) + xboxOneSData.hatValue[i] = 32768; // Center value + xboxOneSData.btn.val = 0; + oldButtonState.val = 0; + for (i = 0; i < sizeof(xboxOneSData.trigger) / sizeof(xboxOneSData.trigger[0]); i++) + xboxOneSData.trigger[i] = 0; + + xboxOneSData.btn.dpad = DPAD_OFF; + oldButtonState.dpad = DPAD_OFF; + buttonClickState.dpad = 0; + oldDpad = 0; +}; + +#if 0 +void XBOXONESParser::setRumbleOn(uint8_t leftTrigger, uint8_t rightTrigger, uint8_t leftMotor, uint8_t rightMotor) { + // See: https://lore.kernel.org/patchwork/patch/973394/ + uint8_t buf[8]; + buf[0] = 0x0F;//1 << 1 | 1 << 0; // Enable weak and strong feedback + buf[1] = leftTrigger; + buf[2] = rightTrigger; + buf[3] = leftMotor; + buf[4] = rightMotor; + buf[5] = 255; // Duration of effect in 10 ms + buf[6] = 0; // Start delay in 10 ms + buf[7] = 255; // Loop count + sendOutputReport(buf, sizeof(buf)); +} +#endif diff --git a/XBOXONESParser.h b/XBOXONESParser.h new file mode 100644 index 00000000..41dc30b2 --- /dev/null +++ b/XBOXONESParser.h @@ -0,0 +1,127 @@ +/* Copyright (C) 2020 Kristian Sloth Lauszus. 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 Sloth Lauszus + Web : https://lauszus.com + e-mail : lauszus@gmail.com + */ + +#ifndef _xboxonesparser_h_ +#define _xboxonesparser_h_ + +#include "Usb.h" +#include "controllerEnums.h" + +union XboxOneSButtons { + struct { + uint8_t dpad : 4; + uint8_t reserved : 4; + + uint8_t a : 1; + uint8_t b : 1; + uint8_t x : 1; + uint8_t y : 1; + + uint8_t l1 : 1; + uint8_t r1 : 1; + uint8_t view : 1; + uint8_t menu : 1; + + uint8_t l3 : 1; + uint8_t r3 : 1; + uint8_t reserved2 : 6; + } __attribute__((packed)); + uint32_t val : 24; +} __attribute__((packed)); + +struct XboxOneSData { + /* Button and joystick values */ + uint16_t hatValue[4]; + uint16_t trigger[2]; + XboxOneSButtons btn; +} __attribute__((packed)); + +/** This class parses all the data sent by the Xbox One S controller */ +class XBOXONESParser { +public: + /** Constructor for the XBOXONESParser class. */ + XBOXONESParser() { + Reset(); + }; + + /** @name Xbox One S Controller functions */ + /** + * getButtonPress(ButtonEnum b) will return true as long as the button is held down. + * + * While getButtonClick(ButtonEnum b) will only return it once. + * + * So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b), + * but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b). + * @param b ::ButtonEnum to read. + * @return getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press. + */ + uint16_t getButtonPress(ButtonEnum b); + bool getButtonClick(ButtonEnum b); + /**@}*/ + + /** + * Used to read the analog joystick. + * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. + * @return Return the analog value as a 16-bit signed integer. + */ + int16_t getAnalogHat(AnalogHatEnum a); + + /** Used to set the rumble off. */ + //void setRumbleOff(); + + /** + * Used to turn on rumble continuously. + * @param leftTrigger Left trigger force. + * @param rightTrigger Right trigger force. + * @param leftMotor Left motor force. + * @param rightMotor Right motor force. + */ + //void setRumbleOn(uint8_t leftTrigger, uint8_t rightTrigger, uint8_t leftMotor, uint8_t rightMotor); + +protected: + /** + * Used to parse data sent from the Xbox One S controller. + * @param len Length of the data. + * @param buf Pointer to the data buffer. + */ + void Parse(uint8_t len, uint8_t *buf); + + /** Used to reset the different buffers to their default values */ + void Reset(); + + /** + * Send the output to the Xbox One S controller. This is implemented in XBOXONESBT.h. + * @param output Pointer to data buffer. + * @param nbytes Bytes to send. + */ + //virtual void sendOutputReport(uint8_t *data, uint8_t nbytes) = 0; + +private: + bool checkDpad(ButtonEnum b); // Used to check Xbox One S DPAD buttons + + XboxOneSData xboxOneSData; + XboxOneSButtons oldButtonState, buttonClickState; + uint8_t oldDpad; + + // The Xbox button is sent in a separate report + uint8_t xboxButtonState, xboxOldButtonState, xboxbuttonClickState; + + uint16_t triggerOld[2]; + bool L2Clicked; // These buttons are analog, so we use we use these bools to check if they where clicked or not + bool R2Clicked; +}; +#endif diff --git a/controllerEnums.h b/controllerEnums.h index 631825b2..c1a5a497 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -144,6 +144,12 @@ enum ButtonEnum { WHITE = 9, // Available on the original Xbox controller /**@}*/ + /**@{*/ + /** Xbox One S buttons */ + VIEW = 4, + MENU = 5, + /**@}*/ + /** PS Buzz controllers */ RED = 0, YELLOW = 1, diff --git a/examples/Xbox/XBOXONESBT/XBOXONESBT.ino b/examples/Xbox/XBOXONESBT/XBOXONESBT.ino new file mode 100644 index 00000000..c691e9bf --- /dev/null +++ b/examples/Xbox/XBOXONESBT/XBOXONESBT.ino @@ -0,0 +1,135 @@ +/* + Example sketch for the Xbox One S Bluetooth library - developed by Kristian Sloth Lauszus + For more information visit the Github repository: github.com/felis/USB_Host_Shield_2.0 or + send me an e-mail: lauszus@gmail.com + */ + +#include +#include + +// Satisfy the IDE, which needs to see the include statement in the ino too. +#ifdef dobogusinclude +#include +#endif +#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 XBOXONESBT class in two ways */ +// This will start an inquiry and then pair with the Xbox One S controller - you only have to do this once +// You will need to hold down the Sync and Xbox button at the same time, the Xbox One S controller will then start to blink rapidly indicating that it is in pairing mode +XBOXONESBT Xbox(&Btd, PAIR); + +// After that you can simply create the instance like so and then press the Xbox button on the device +//XBOXONESBT Xbox(&Btd); + +void setup() { + Serial.begin(115200); +#if !defined(__MIPSEL__) + while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection +#endif + if (Usb.Init() == -1) { + Serial.print(F("\r\nOSC did not start")); + while (1); //halt + } + Serial.print(F("\r\nXbox One S Bluetooth Library Started")); +} +void loop() { + Usb.Task(); + + if (Xbox.connected()) { + if (Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500 || Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500 || Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500 || Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) { + if (Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500) { + Serial.print(F("LeftHatX: ")); + Serial.print(Xbox.getAnalogHat(LeftHatX)); + Serial.print("\t"); + } + if (Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500) { + Serial.print(F("LeftHatY: ")); + Serial.print(Xbox.getAnalogHat(LeftHatY)); + Serial.print("\t"); + } + if (Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500) { + Serial.print(F("RightHatX: ")); + Serial.print(Xbox.getAnalogHat(RightHatX)); + Serial.print("\t"); + } + if (Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) { + Serial.print(F("RightHatY: ")); + Serial.print(Xbox.getAnalogHat(RightHatY)); + } + Serial.println(); + } + + if (Xbox.getButtonPress(L2) > 0 || Xbox.getButtonPress(R2) > 0) { + if (Xbox.getButtonPress(L2) > 0) { + Serial.print(F("L2: ")); + Serial.print(Xbox.getButtonPress(L2)); + Serial.print("\t"); + } + if (Xbox.getButtonPress(R2) > 0) { + Serial.print(F("R2: ")); + Serial.print(Xbox.getButtonPress(R2)); + Serial.print("\t"); + } + Serial.println(); + } + +#if 0 // This is currently not working + // Set rumble effect + static uint16_t oldL2Value, oldR2Value; + if (Xbox.getButtonPress(L2) != oldL2Value || Xbox.getButtonPress(R2) != oldR2Value) { + oldL2Value = Xbox.getButtonPress(L2); + oldR2Value = Xbox.getButtonPress(R2); + uint8_t leftRumble = map(oldL2Value, 0, 1023, 0, 255); // Map the trigger values into a byte + uint8_t rightRumble = map(oldR2Value, 0, 1023, 0, 255); + if (leftRumble > 0 || rightRumble > 0) + Xbox.setRumbleOn(leftRumble, rightRumble, leftRumble, rightRumble); + else + Xbox.setRumbleOff(); + } +#endif + + if (Xbox.getButtonClick(UP)) + Serial.println(F("Up")); + if (Xbox.getButtonClick(DOWN)) + Serial.println(F("Down")); + if (Xbox.getButtonClick(LEFT)) + Serial.println(F("Left")); + if (Xbox.getButtonClick(RIGHT)) + Serial.println(F("Right")); + + if (Xbox.getButtonClick(VIEW)) + Serial.println(F("View")); + if (Xbox.getButtonClick(MENU)) + Serial.println(F("Menu")); + if (Xbox.getButtonClick(XBOX)) { + Serial.println(F("Xbox")); + Xbox.disconnect(); + } + + if (Xbox.getButtonClick(L1)) + Serial.println(F("L1")); + if (Xbox.getButtonClick(R1)) + Serial.println(F("R1")); + if (Xbox.getButtonClick(L2)) + Serial.println(F("L2")); + if (Xbox.getButtonClick(R2)) + Serial.println(F("R2")); + if (Xbox.getButtonClick(L3)) + Serial.println(F("L3")); + if (Xbox.getButtonClick(R3)) + Serial.println(F("R3")); + + if (Xbox.getButtonClick(A)) + Serial.println(F("A")); + if (Xbox.getButtonClick(B)) + Serial.println(F("B")); + if (Xbox.getButtonClick(X)) + Serial.println(F("X")); + if (Xbox.getButtonClick(Y)) + Serial.println(F("Y")); + } +} diff --git a/keywords.txt b/keywords.txt index eed0eb5c..2513e98e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -196,6 +196,7 @@ XBOXUSB KEYWORD1 XBOXONE KEYWORD1 XBOXOLD KEYWORD1 XBOXRECV KEYWORD1 +XBOXONESBT KEYWORD1 #################################################### # Methods and Functions (KEYWORD2) @@ -227,6 +228,9 @@ BACK LITERAL1 XBOX LITERAL1 SYNC LITERAL1 +VIEW LITERAL1 +MENU LITERAL1 + BLACK LITERAL1 WHITE LITERAL1 diff --git a/settings.h b/settings.h index 63be1770..2d176053 100644 --- a/settings.h +++ b/settings.h @@ -39,7 +39,7 @@ e-mail : support@circuitsathome.com //////////////////////////////////////////////////////////////////////////////// /* Set this to 1 to activate serial debugging */ -#define ENABLE_UHS_DEBUGGING 1 +#define ENABLE_UHS_DEBUGGING 0 /* This can be used to select which serial port to use for debugging if * multiple serial ports are available. From f500cc9b4c639ed90502bb52fe87be1185b9347f Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 19:02:54 +0100 Subject: [PATCH 07/12] Only use simple pairing with the Xbox One S controller, as it did not work with the PS4 --- BTD.cpp | 17 +++++++++++------ BTD.h | 3 +++ BTHID.cpp | 6 ++++-- XBOXONESBT.h | 1 + 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index bd2d2587..32efeb86 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -29,6 +29,7 @@ connectToWii(false), pairWithWii(false), connectToHIDDevice(false), pairWithHIDDevice(false), +useSimplePairing(false), pUsb(p), // Pointer to USB class instance - mandatory bAddress(0), // Device address - mandatory bNumEP(1), // If config descriptor needs to be parsed @@ -658,7 +659,7 @@ void BTD::HCI_event_task() { #endif connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device } else { -#ifdef DEBUG_USB_HOST +#ifdef EXTRADEBUG Notify(PSTR("\r\nPairing was successful"), 0x80); #endif } @@ -823,11 +824,12 @@ void BTD::HCI_task() { if(btdName != NULL) { hci_write_local_name(btdName); hci_state = HCI_WRITE_NAME_STATE; - } else { + } else if(useSimplePairing) { hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" //hci_read_local_extended_features(1); // Read page 1 hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; - } + } else + hci_state = HCI_CHECK_DEVICE_SERVICE; } break; @@ -837,9 +839,12 @@ void BTD::HCI_task() { Notify(PSTR("\r\nThe name was set to: "), 0x80); NotifyStr(btdName, 0x80); #endif - hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" - //hci_read_local_extended_features(1); // Read page 1 - hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; + if(useSimplePairing) { + hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features" + //hci_read_local_extended_features(1); // Read page 1 + hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE; + } else + hci_state = HCI_CHECK_DEVICE_SERVICE; } break; diff --git a/BTD.h b/BTD.h index e0b3a46d..5337dea9 100644 --- a/BTD.h +++ b/BTD.h @@ -530,6 +530,9 @@ public: return pollInterval; }; + /** Used by the drivers to enable simple pairing */ + bool useSimplePairing; + protected: /** Pointer to USB class instance. */ USB *pUsb; diff --git a/BTHID.cpp b/BTHID.cpp index ad2a0ac2..dc5ab207 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -258,8 +258,9 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { #endif } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP if(l2capinbuf[8] == SDP_SERVICE_SEARCH_REQUEST) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nSDP_SERVICE_SEARCH_REQUEST"), 0x80); - +#endif // Send response l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE; l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; @@ -278,8 +279,9 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { SDP_Command(l2capoutbuf, 10); } else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) { +#ifdef EXTRADEBUG Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80); - +#endif // Send response l2capoutbuf[0] = SDP_SERVICE_ATTRIBUTE_RESPONSE; l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh; diff --git a/XBOXONESBT.h b/XBOXONESBT.h index 82b17d24..58395790 100644 --- a/XBOXONESBT.h +++ b/XBOXONESBT.h @@ -35,6 +35,7 @@ public: XBOXONESBT(BTD *p, bool pair = false) : BTHID(p, pair) { XBOXONESParser::Reset(); + pBtd->useSimplePairing = true; // The Xbox One S controller only works via simple pairing }; /** From e101482478c40410e09df76ebcf39e9dfa986620 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 19:29:54 +0100 Subject: [PATCH 08/12] Updated Travis to use Python 3.9 and added the 'XBOXONESBT.ino' example --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3dc25114..6a105b8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: python python: - - "2.7" + - "3.9" # Cache PlatformIO packages using Travis CI container-based infrastructure sudo: false @@ -69,6 +69,7 @@ env: - PLATFORMIO_CI_SRC=examples/USBH_MIDI/USBH_MIDI_dump - PLATFORMIO_CI_SRC=examples/Xbox/XBOXOLD - PLATFORMIO_CI_SRC=examples/Xbox/XBOXONE + - PLATFORMIO_CI_SRC=examples/Xbox/XBOXONESBT - PLATFORMIO_CI_SRC=examples/Xbox/XBOXRECV - PLATFORMIO_CI_SRC=examples/Xbox/XBOXUSB From edc5198976fafe323e52d4818ce8f105000598d1 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 23:27:08 +0100 Subject: [PATCH 09/12] Fix 'warning: this statement may fall through [-Wimplicit-fallthrough=]' Closes #532 --- confdescparser.h | 4 ++++ hidescriptorparser.cpp | 6 ++++++ parsetools.cpp | 3 +++ parsetools.h | 1 + usbh_midi.cpp | 1 + 5 files changed, 15 insertions(+) diff --git a/confdescparser.h b/confdescparser.h index 54053545..5991182a 100644 --- a/confdescparser.h +++ b/confdescparser.h @@ -108,12 +108,14 @@ bool ConfigDescParser::ParseDescriptor theBuffer.valueSize = 2; valParser.Initialize(&theBuffer); stateParseDescr = 1; + // fall through case 1: if(!valParser.Parse(pp, pcntdn)) return false; dscrLen = *((uint8_t*)theBuffer.pValue); dscrType = *((uint8_t*)theBuffer.pValue + 1); stateParseDescr = 2; + // fall through case 2: // This is a sort of hack. Assuming that two bytes are all ready in the buffer // the pointer is positioned two bytes ahead in order for the rest of descriptor @@ -122,6 +124,7 @@ bool ConfigDescParser::ParseDescriptor // in the buffer. theBuffer.pValue = varBuffer + 2; stateParseDescr = 3; + // fall through case 3: switch(dscrType) { case USB_DESCRIPTOR_INTERFACE: @@ -135,6 +138,7 @@ bool ConfigDescParser::ParseDescriptor theBuffer.valueSize = dscrLen - 2; valParser.Initialize(&theBuffer); stateParseDescr = 4; + // fall through case 4: switch(dscrType) { case USB_DESCRIPTOR_CONFIGURATION: diff --git a/hidescriptorparser.cpp b/hidescriptorparser.cpp index 43e3f7d6..42e3103b 100644 --- a/hidescriptorparser.cpp +++ b/hidescriptorparser.cpp @@ -1113,16 +1113,19 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) { if(!pcntdn) return enErrorIncomplete; + // fall through case 1: //USBTRACE2("\r\niSz:",itemSize); theBuffer.valueSize = itemSize; valParser.Initialize(&theBuffer); itemParseState = 2; + // fall through case 2: if(!valParser.Parse(pp, pcntdn)) return enErrorIncomplete; itemParseState = 3; + // fall through case 3: { uint8_t data = *((uint8_t*)varBuffer); @@ -1448,14 +1451,17 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) { if(!pcntdn) return enErrorIncomplete; + // fall through case 1: theBuffer.valueSize = itemSize; valParser.Initialize(&theBuffer); itemParseState = 2; + // fall through case 2: if(!valParser.Parse(pp, pcntdn)) return enErrorIncomplete; itemParseState = 3; + // fall through case 3: { uint8_t data = *((uint8_t*)varBuffer); diff --git a/parsetools.cpp b/parsetools.cpp index 1b5efaf3..47c0d2a1 100644 --- a/parsetools.cpp +++ b/parsetools.cpp @@ -44,6 +44,7 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, pBuf->valueSize = lenSize; theParser.Initialize(pBuf); nStage = 1; + // fall through case 1: if(!theParser.Parse(pp, pcntdn)) @@ -53,11 +54,13 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue)); arLenCntdn = arLen; nStage = 2; + // fall through case 2: pBuf->valueSize = valSize; theParser.Initialize(pBuf); nStage = 3; + // fall through case 3: for(; arLenCntdn; arLenCntdn--) { diff --git a/parsetools.h b/parsetools.h index f7525369..7812e938 100644 --- a/parsetools.h +++ b/parsetools.h @@ -79,6 +79,7 @@ public: case 0: countDown = bytes_to_skip; nStage++; + // fall through case 1: for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--); diff --git a/usbh_midi.cpp b/usbh_midi.cpp index 104eb816..a9f0f719 100644 --- a/usbh_midi.cpp +++ b/usbh_midi.cpp @@ -589,6 +589,7 @@ uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable break; case 3 : buf[wptr] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes. + // fall through default : wptr++; buf[wptr++] = *(dataptr++); From 1121d8d9ad85f7ac55fb47de4e322a0f2614e506 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 23:29:05 +0100 Subject: [PATCH 10/12] Updated my email and full name --- README.md | 6 +++--- library.json | 6 +++--- library.properties | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3329278a..cac71f6e 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,10 @@ For more information about the hardware see the [Hardware Manual](https://chome. # Developed By -* __Oleg Mazurov - -* __Alexei Glushchenko, Circuits@Home__ - +* __Oleg Mazurov__ - +* __Alexei Glushchenko__ - * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries -* __Kristian Sloth Lauszus__ - +* __Kristian Sloth Lauszus__ - * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries * __Andrew Kroll__ - * Major contributor to mass storage code diff --git a/library.json b/library.json index 5baffe60..76e1069f 100644 --- a/library.json +++ b/library.json @@ -15,9 +15,9 @@ "email": "alex-gl@mail.ru" }, { - "name": "Kristian Lauszus", - "email": "kristianl@tkjelectronics.com", - "url": "http://tkjelectronics.com", + "name": "Kristian Sloth Lauszus", + "email": "lauszus@gmail.com", + "url": "https://lauszus.com", "maintainer": true }, { diff --git a/library.properties b/library.properties index 2dd60a44..179a515c 100644 --- a/library.properties +++ b/library.properties @@ -1,7 +1,7 @@ name=USB Host Shield Library 2.0 version=1.3.2 -author=Oleg Mazurov (Circuits@Home) , Kristian Lauszus (TKJ Electronics) , Andrew Kroll , Alexei Glushchenko (Circuits@Home) -maintainer=Oleg Mazurov (Circuits@Home) , Kristian Lauszus (TKJ Electronics) , Andrew Kroll +author=Oleg Mazurov (Circuits@Home) , Kristian Sloth Lauszus , Andrew Kroll , Alexei Glushchenko (Circuits@Home) +maintainer=Oleg Mazurov (Circuits@Home) , Kristian Sloth Lauszus , Andrew Kroll sentence=Revision 2.0 of MAX3421E-based USB Host Shield Library. paragraph=Supports HID devices, FTDI, ADK, ACM, PL2303, Bluetooth HID devices, SPP communication and mass storage devices. Furthermore it supports PS3, PS4, PS Buzz, Wii and Xbox controllers. category=Other From 96aae6667b6d7fd2d6dbd0ce7793af34080a9c1c Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 23:31:27 +0100 Subject: [PATCH 11/12] Do not compile the Wii.ino example on the Arduino Uno, as it will not fit --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd20ffa6..89b32847 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ env: - PLATFORMIO_CI_SRC=examples/Bluetooth/PS4BT - PLATFORMIO_CI_SRC=examples/Bluetooth/SPP - PLATFORMIO_CI_SRC=examples/Bluetooth/SPPMulti - - PLATFORMIO_CI_SRC=examples/Bluetooth/Wii + - PLATFORMIO_CI_SRC=examples/Bluetooth/Wii SKIP_UNO=true - PLATFORMIO_CI_SRC=examples/Bluetooth/WiiBalanceBoard SKIP_UNO=true - PLATFORMIO_CI_SRC=examples/Bluetooth/WiiIRCamera PLATFORMIO_BUILD_FLAGS="-DWIICAMERA" SKIP_UNO=true - PLATFORMIO_CI_SRC=examples/Bluetooth/WiiMulti SKIP_UNO=true From 0519b43456b16228e284207fe79a39c7d4d688a3 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sun, 15 Nov 2020 23:32:30 +0100 Subject: [PATCH 12/12] Do not compile the bidirectional_converter.ino for Teensy 3.5 and 3.6, as there is some conflict with the MIDI library See: https://travis-ci.org/github/felis/USB_Host_Shield_2.0/jobs/743787235 --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 89b32847..1b1f1378 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,7 +62,8 @@ env: - PLATFORMIO_CI_SRC=examples/PSBuzz # - PLATFORMIO_CI_SRC=examples/testusbhostFAT - PLATFORMIO_CI_SRC=examples/USB_desc - - PLATFORMIO_CI_SRC=examples/USBH_MIDI/bidirectional_converter + # See: https://travis-ci.org/github/felis/USB_Host_Shield_2.0/jobs/743787235 + - PLATFORMIO_CI_SRC=examples/USBH_MIDI/bidirectional_converter SKIP_TEENSY35=true SKIP_TEENSY36=true - PLATFORMIO_CI_SRC=examples/USBH_MIDI/eVY1_sample - PLATFORMIO_CI_SRC=examples/USBH_MIDI/USB_MIDI_converter - PLATFORMIO_CI_SRC=examples/USBH_MIDI/USB_MIDI_converter_multi @@ -87,7 +88,9 @@ install: script: - if [[ -z "$SKIP_UNO" ]]; then UNO="--board=uno"; fi - - platformio ci --lib="." $UNO --board=genuino101 --board=teensy30 --board=teensy31 --board=teensy35 --board=teensy36 --board=teensylc --board=esp12e --board=nodemcu --board=esp32dev + - if [[ -z "$SKIP_TEENSY35" ]]; then TEENSY35="--board=teensy35"; fi + - if [[ -z "$SKIP_TEENSY36" ]]; then TEENSY36="--board=teensy36"; fi + - platformio ci --lib="." $UNO --board=genuino101 --board=teensy30 --board=teensy31 $TEENSY35 $TEENSY36 --board=teensylc --board=esp12e --board=nodemcu --board=esp32dev - platformio ci --lib="." --board=due --project-option="build_flags=-Wno-misleading-indentation" # Workaround https://travis-ci.org/felis/USB_Host_Shield_2.0/jobs/569237654 and https://github.com/arduino/ArduinoCore-sam/issues/69 before_deploy: