Initial code for Xbox One S controller support

I lack a dongle that support simply paring, so it has been confirmed working yet
This commit is contained in:
Kristian Sloth Lauszus 2019-06-30 20:44:12 +02:00
parent 49421b6ce4
commit 30ac619331
4 changed files with 185 additions and 13 deletions

181
BTD.cpp
View file

@ -17,7 +17,7 @@
#include "BTD.h" #include "BTD.h"
// To enable serial debugging see "settings.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_CONTROL_PIPE = 0;
const uint8_t BTD::BTD_EVENT_PIPE = 1; 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 hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag
if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information 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 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<uint8_t > (hci_version, 0x80);
}
#endif
hci_set_flag(HCI_FLAG_READ_VERSION); 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<uint8_t > (hcibuf[6], 0x80);
Notify(PSTR("\r\nMaximum page number: "), 0x80);
D_PrintHex<uint8_t > (hcibuf[7], 0x80);
Notify(PSTR("\r\nExtended LMP features:"), 0x80);
for(uint8_t i = 0; i < 8; i++) {
Notify(PSTR(" "), 0x80);
D_PrintHex<uint8_t > (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 } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address
for(uint8_t i = 0; i < 6; i++) for(uint8_t i = 0; i < 6; i++)
my_bdaddr[i] = hcibuf[6 + i]; my_bdaddr[i] = hcibuf[6 + i];
@ -446,7 +485,7 @@ void BTD::HCI_event_task() {
case EV_INQUIRY_RESULT: case EV_INQUIRY_RESULT:
if(hcibuf[2]) { // Check that there is more than zero responses 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(PSTR("\r\nNumber of responses: "), 0x80);
Notify(hcibuf[2], 0x80); Notify(hcibuf[2], 0x80);
#endif #endif
@ -456,7 +495,7 @@ void BTD::HCI_event_task() {
for(uint8_t j = 0; j < 3; j++) for(uint8_t j = 0; j < 3; j++)
classOfDevice[j] = hcibuf[j + 4 + offset]; classOfDevice[j] = hcibuf[j + 4 + offset];
#ifdef EXTRADEBUG #if defined(EXTRADEBUG) && 0
Notify(PSTR("\r\nClass of device: "), 0x80); Notify(PSTR("\r\nClass of device: "), 0x80);
D_PrintHex<uint8_t > (classOfDevice[2], 0x80); D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
Notify(PSTR(" "), 0x80); Notify(PSTR(" "), 0x80);
@ -465,7 +504,7 @@ void BTD::HCI_event_task() {
D_PrintHex<uint8_t > (classOfDevice[0], 0x80); D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
#endif #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 checkRemoteName = true; // Check remote name to distinguish between the different controllers
for(uint8_t j = 0; j < 6; j++) for(uint8_t j = 0; j < 6; j++)
@ -473,8 +512,10 @@ void BTD::HCI_event_task() {
hci_set_flag(HCI_FLAG_DEVICE_FOUND); hci_set_flag(HCI_FLAG_DEVICE_FOUND);
break; 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 #ifdef DEBUG_USB_HOST
checkRemoteName = true; // Used to print name in the serial monitor if serial debugging is enabled
if(classOfDevice[0] & 0x80) if(classOfDevice[0] & 0x80)
Notify(PSTR("\r\nMouse found"), 0x80); Notify(PSTR("\r\nMouse found"), 0x80);
if(classOfDevice[0] & 0x40) if(classOfDevice[0] & 0x40)
@ -524,7 +565,7 @@ void BTD::HCI_event_task() {
if(remote_name[i] == '\0') // End of string if(remote_name[i] == '\0') // End of string
break; break;
} }
// TODO: Altid sæt '\0' i remote name! // TODO: Always set '\0' in remote name!
hci_set_flag(HCI_FLAG_REMOTE_NAME_COMPLETE); hci_set_flag(HCI_FLAG_REMOTE_NAME_COMPLETE);
} }
break; break;
@ -536,7 +577,7 @@ void BTD::HCI_event_task() {
for(uint8_t i = 0; i < 3; i++) for(uint8_t i = 0; i < 3; i++)
classOfDevice[i] = hcibuf[i + 8]; 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 #ifdef DEBUG_USB_HOST
if(classOfDevice[0] & 0x80) if(classOfDevice[0] & 0x80)
Notify(PSTR("\r\nMouse is connecting"), 0x80); Notify(PSTR("\r\nMouse is connecting"), 0x80);
@ -608,18 +649,84 @@ void BTD::HCI_event_task() {
hci_state = HCI_DISCONNECT_STATE; hci_state = HCI_DISCONNECT_STATE;
} }
break; 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<uint8_t > (hcibuf[5], 0x80);
Notify(PSTR("\r\nMaximum page number: "), 0x80);
D_PrintHex<uint8_t > (hcibuf[6], 0x80);
Notify(PSTR("\r\nExtended LMP features:"), 0x80);
for(uint8_t i = 0; i < 8; i++) {
Notify(PSTR(" "), 0x80);
D_PrintHex<uint8_t > (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<uint8_t > (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<uint8_t > (hcibuf[8 + i], 0x80);
}
#endif
hci_user_confirmation_request_reply();
hci_state = HCI_SCANNING_STATE;
break;
/* We will just ignore the following events */ /* We will just ignore the following events */
case EV_MAX_SLOTS_CHANGE:
break;
case EV_NUM_COMPLETE_PKT: case EV_NUM_COMPLETE_PKT:
case EV_ROLE_CHANGED: case EV_ROLE_CHANGED:
case EV_PAGE_SCAN_REP_MODE: case EV_PAGE_SCAN_REP_MODE:
case EV_LOOPBACK_COMMAND: case EV_LOOPBACK_COMMAND:
case EV_DATA_BUFFER_OVERFLOW: case EV_DATA_BUFFER_OVERFLOW:
case EV_CHANGE_CONNECTION_LINK: case EV_CHANGE_CONNECTION_LINK:
case EV_MAX_SLOTS_CHANGE:
case EV_QOS_SETUP_COMPLETE: case EV_QOS_SETUP_COMPLETE:
case EV_LINK_KEY_NOTIFICATION: case EV_LINK_KEY_NOTIFICATION:
case EV_ENCRYPTION_CHANGE: case EV_ENCRYPTION_CHANGE:
case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE: case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE:
#ifdef EXTRADEBUG
if(hcibuf[0] != 0x00) {
Notify(PSTR("\r\nIgnore HCI Event: "), 0x80);
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
}
#endif
break; break;
#ifdef EXTRADEBUG #ifdef EXTRADEBUG
default: default:
@ -699,6 +806,14 @@ void BTD::HCI_task() {
case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class
if(hci_check_flag(HCI_FLAG_READ_VERSION)) { 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) { if(btdName != NULL) {
hci_set_local_name(btdName); hci_set_local_name(btdName);
hci_state = HCI_SET_NAME_STATE; hci_state = HCI_SET_NAME_STATE;
@ -783,8 +898,9 @@ void BTD::HCI_task() {
else else
Notify(PSTR("\r\nConnected to HID device"), 0x80); Notify(PSTR("\r\nConnected to HID device"), 0x80);
#endif #endif
hci_authentication_request(); // This will start the pairing with the Wiimote hci_read_remote_extended_features(0); // "Requests the normal LMP features as returned by the HCI_Read_Remote_Supported_Features command"
hci_state = HCI_SCANNING_STATE; //hci_read_remote_extended_features(1); // Read page 1
hci_state = HCI_REMOTE_EXTENDED_FEATURES_STATE;
} else { } else {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nTrying to connect one more time..."), 0x80); Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
@ -794,6 +910,13 @@ void BTD::HCI_task() {
} }
break; 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: case HCI_SCANNING_STATE:
if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) { if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
@ -855,7 +978,7 @@ void BTD::HCI_task() {
#endif #endif
incomingPS4 = true; incomingPS4 = true;
} }
if(pairWithWii && checkRemoteName) if((pairWithWii || pairWithHIDDevice) && checkRemoteName)
hci_state = HCI_CONNECT_DEVICE_STATE; hci_state = HCI_CONNECT_DEVICE_STATE;
else { else {
hci_accept_connection(); hci_accept_connection();
@ -999,6 +1122,16 @@ void BTD::hci_read_local_version_information() {
HCI_Command(hcibuf, 3); 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() { void BTD::hci_accept_connection() {
hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE);
hcibuf[0] = 0x09; // HCI OCF = 9 hcibuf[0] = 0x09; // HCI OCF = 9
@ -1034,6 +1167,18 @@ void BTD::hci_remote_name() {
HCI_Command(hcibuf, 13); 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) { void BTD::hci_set_local_name(const char* name) {
hcibuf[0] = 0x13; // HCI OCF = 13 hcibuf[0] = 0x13; // HCI OCF = 13
hcibuf[1] = 0x03 << 2; // HCI OGF = 3 hcibuf[1] = 0x03 << 2; // HCI OGF = 3
@ -1158,6 +1303,20 @@ void BTD::hci_link_key_request_negative_reply() {
HCI_Command(hcibuf, 9); 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() { void BTD::hci_authentication_request() {
hcibuf[0] = 0x11; // HCI OCF = 11 hcibuf[0] = 0x11; // HCI OCF = 11
hcibuf[1] = 0x01 << 2; // HCI OGF = 1 hcibuf[1] = 0x01 << 2; // HCI OGF = 1

13
BTD.h
View file

@ -59,6 +59,8 @@
#define HCI_DISABLE_SCAN_STATE 14 #define HCI_DISABLE_SCAN_STATE 14
#define HCI_DONE_STATE 15 #define HCI_DONE_STATE 15
#define HCI_DISCONNECT_STATE 16 #define HCI_DISCONNECT_STATE 16
#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
#define HCI_REMOTE_EXTENDED_FEATURES_STATE 18
/* HCI event flags*/ /* HCI event flags*/
#define HCI_FLAG_CMD_COMPLETE (1UL << 0) #define HCI_FLAG_CMD_COMPLETE (1UL << 0)
@ -70,6 +72,8 @@
#define HCI_FLAG_READ_VERSION (1UL << 6) #define HCI_FLAG_READ_VERSION (1UL << 6)
#define HCI_FLAG_DEVICE_FOUND (1UL << 7) #define HCI_FLAG_DEVICE_FOUND (1UL << 7)
#define HCI_FLAG_CONNECT_EVENT (1UL << 8) #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 */ /* Macros for HCI event flag tests */
#define hci_check_flag(flag) (hci_event_flag & (flag)) #define hci_check_flag(flag) (hci_event_flag & (flag))
@ -99,6 +103,9 @@
#define EV_COMMAND_STATUS 0x0F #define EV_COMMAND_STATUS 0x0F
#define EV_LOOPBACK_COMMAND 0x19 #define EV_LOOPBACK_COMMAND 0x19
#define EV_PAGE_SCAN_REP_MODE 0x20 #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 */ /* Bluetooth states for the different Bluetooth drivers */
#define L2CAP_WAIT 0 #define L2CAP_WAIT 0
@ -320,6 +327,8 @@ public:
void hci_read_bdaddr(); void hci_read_bdaddr();
/** Read the HCI Version of the Bluetooth dongle. */ /** Read the HCI Version of the Bluetooth dongle. */
void hci_read_local_version_information(); void hci_read_local_version_information();
void hci_read_local_extended_features(uint8_t page_number);
/** /**
* Set the local name of the Bluetooth dongle. * Set the local name of the Bluetooth dongle.
* @param name Desired name. * @param name Desired name.
@ -331,6 +340,8 @@ public:
void hci_write_scan_disable(); void hci_write_scan_disable();
/** Read the remote devices name. */ /** Read the remote devices name. */
void hci_remote_name(); void hci_remote_name();
void hci_read_remote_extended_features(uint8_t page_number);
/** Accept the connection with the Bluetooth device. */ /** Accept the connection with the Bluetooth device. */
void hci_accept_connection(); void hci_accept_connection();
/** /**
@ -351,6 +362,8 @@ public:
* if the Host does not have a stored Link Key for the connection. * if the Host does not have a stored Link Key for the connection.
*/ */
void hci_link_key_request_negative_reply(); void hci_link_key_request_negative_reply();
void hci_user_confirmation_request_reply();
/** Used to try to authenticate with the remote device. */ /** Used to try to authenticate with the remote device. */
void hci_authentication_request(); void hci_authentication_request();
/** Start a HCI inquiry. */ /** Start a HCI inquiry. */

View file

@ -25,7 +25,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
BTHID bthid(&Btd, PAIR, "0000"); BTHID bthid(&Btd, PAIR, "0000");
// After that you can simply create the instance like so and then press any button on the device // 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; KbdRptParser keyboardPrs;
MouseRptParser mousePrs; MouseRptParser mousePrs;

View file

@ -39,7 +39,7 @@ e-mail : support@circuitsathome.com
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* Set this to 1 to activate serial debugging */ /* 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 /* This can be used to select which serial port to use for debugging if
* multiple serial ports are available. * multiple serial ports are available.