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"
// 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<uint8_t > (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<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
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<uint8_t > (classOfDevice[2], 0x80);
Notify(PSTR(" "), 0x80);
@ -465,7 +504,7 @@ void BTD::HCI_event_task() {
D_PrintHex<uint8_t > (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<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 */
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<uint8_t > (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

13
BTD.h
View file

@ -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. */

View file

@ -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;

View file

@ -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.