mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Xbox One S controller support is now finally working
This commit is contained in:
parent
ad9360b865
commit
102746ef6b
12 changed files with 726 additions and 307 deletions
186
BTD.cpp
186
BTD.cpp
|
@ -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;
|
||||||
|
@ -542,7 +542,6 @@ void BTD::HCI_event_task() {
|
||||||
if(classOfDevice[0] & 0x08)
|
if(classOfDevice[0] & 0x08)
|
||||||
Notify(PSTR("\r\nGamepad found"), 0x80);
|
Notify(PSTR("\r\nGamepad found"), 0x80);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(uint8_t j = 0; j < 6; j++)
|
for(uint8_t j = 0; j < 6; j++)
|
||||||
disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
|
disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
|
||||||
|
|
||||||
|
@ -673,62 +672,49 @@ void BTD::HCI_event_task() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE:
|
case EV_IO_CAPABILITY_REQUEST:
|
||||||
if(!hcibuf[2]) { // Check if connected OK
|
#ifdef DEBUG_USB_HOST
|
||||||
if(!hci_check_flag(HCI_FLAG_REMOTE_EXTENDED_FEATURES)) {
|
Notify(PSTR("\r\nReceived IO Capability Request"), 0x80);
|
||||||
|
#endif
|
||||||
|
hci_io_capability_request_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_IO_CAPABILITY_RESPONSE:
|
||||||
#ifdef EXTRADEBUG
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nPage number: "), 0x80);
|
Notify(PSTR("\r\nReceived IO Capability Response: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[5], 0x80);
|
Notify(PSTR("\r\nIO capability: "), 0x80);
|
||||||
Notify(PSTR("\r\nMaximum page number: "), 0x80);
|
D_PrintHex<uint8_t > (hcibuf[8], 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[6], 0x80);
|
Notify(PSTR("\r\nOOB data present: "), 0x80);
|
||||||
Notify(PSTR("\r\nExtended LMP features:"), 0x80);
|
D_PrintHex<uint8_t > (hcibuf[9], 0x80);
|
||||||
for(uint8_t i = 0; i < 8; i++) {
|
Notify(PSTR("\r\nAuthentication request: "), 0x80);
|
||||||
Notify(PSTR(" "), 0x80);
|
D_PrintHex<uint8_t > (hcibuf[10], 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[7 + i], 0x80);
|
|
||||||
}
|
|
||||||
#endif
|
#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<uint8_t > (hcibuf[2], 0x80);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_USER_CONFIRMATION_REQUEST:
|
case EV_USER_CONFIRMATION_REQUEST:
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(PSTR("\r\nUser confirmation Request: "), 0x80);
|
Notify(PSTR("\r\nUser confirmation Request"), 0x80);
|
||||||
#endif
|
|
||||||
#ifdef EXTRADEBUG
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nNumeric value: "), 0x80);
|
Notify(PSTR(": \r\nNumeric value: "), 0x80);
|
||||||
for(uint8_t i = 0; i < 4; i++) {
|
for(uint8_t i = 0; i < 4; i++) {
|
||||||
Notify(PSTR(" "), 0x80);
|
Notify(PSTR(" "), 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
|
D_PrintHex<uint8_t > (hcibuf[8 + i], 0x80);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
// Simply confirm the connection, as the host has no "NoInputNoOutput" capabilities
|
||||||
hci_user_confirmation_request_reply();
|
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<uint8_t > (hcibuf[2], 0x80);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* We will just ignore the following events */
|
/* We will just ignore the following events */
|
||||||
|
@ -756,7 +742,6 @@ void BTD::HCI_event_task() {
|
||||||
if(hcibuf[0] != 0x00) {
|
if(hcibuf[0] != 0x00) {
|
||||||
Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
|
Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
|
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
|
||||||
|
|
||||||
Notify(PSTR(", data: "), 0x80);
|
Notify(PSTR(", data: "), 0x80);
|
||||||
for(uint16_t i = 0; i < hcibuf[1]; i++) {
|
for(uint16_t i = 0; i < hcibuf[1]; i++) {
|
||||||
D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
|
D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
|
||||||
|
@ -872,6 +857,16 @@ void BTD::HCI_task() {
|
||||||
if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) {
|
if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(PSTR("\r\nSimple pairing was enabled"), 0x80);
|
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
|
#endif
|
||||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||||
}
|
}
|
||||||
|
@ -943,9 +938,8 @@ 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_read_remote_extended_features(0); // "Requests the normal LMP features as returned by the HCI_Read_Remote_Supported_Features command"
|
hci_authentication_request(); // This will start the pairing with the device
|
||||||
//hci_read_remote_extended_features(1); // Read page 1
|
hci_state = HCI_SCANNING_STATE;
|
||||||
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);
|
||||||
|
@ -955,19 +949,6 @@ void BTD::HCI_task() {
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case HCI_SCANNING_STATE:
|
||||||
if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) {
|
if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
|
@ -1218,18 +1199,6 @@ 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_write_local_name(const char* name) {
|
void BTD::hci_write_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
|
||||||
|
@ -1242,6 +1211,24 @@ void BTD::hci_write_local_name(const char* name) {
|
||||||
HCI_Command(hcibuf, 4 + strlen(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) {
|
void BTD::hci_write_simple_pairing_mode(bool enable) {
|
||||||
hcibuf[0] = 0x56; // HCI OCF = 56
|
hcibuf[0] = 0x56; // HCI OCF = 56
|
||||||
hcibuf[1] = 0x03 << 2; // HCI OGF = 3
|
hcibuf[1] = 0x03 << 2; // HCI OGF = 3
|
||||||
|
@ -1299,40 +1286,6 @@ void BTD::hci_connect(uint8_t *bdaddr) {
|
||||||
HCI_Command(hcibuf, 16);
|
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() {
|
void BTD::hci_pin_code_request_reply() {
|
||||||
hcibuf[0] = 0x0D; // HCI OCF = 0D
|
hcibuf[0] = 0x0D; // HCI OCF = 0D
|
||||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||||
|
@ -1397,6 +1350,23 @@ void BTD::hci_link_key_request_negative_reply() {
|
||||||
HCI_Command(hcibuf, 9);
|
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() {
|
void BTD::hci_user_confirmation_request_reply() {
|
||||||
hcibuf[0] = 0x2C; // HCI OCF = 2C
|
hcibuf[0] = 0x2C; // HCI OCF = 2C
|
||||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||||
|
|
34
BTD.h
34
BTD.h
|
@ -61,7 +61,7 @@
|
||||||
#define HCI_DISCONNECT_STATE 16
|
#define HCI_DISCONNECT_STATE 16
|
||||||
#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
|
#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
|
||||||
#define HCI_WRITE_SIMPLE_PAIRING_STATE 18
|
#define HCI_WRITE_SIMPLE_PAIRING_STATE 18
|
||||||
#define HCI_REMOTE_EXTENDED_FEATURES_STATE 19
|
#define HCI_SET_EVENT_MASK_STATE 19
|
||||||
|
|
||||||
/* HCI event flags*/
|
/* HCI event flags*/
|
||||||
#define HCI_FLAG_CMD_COMPLETE (1UL << 0)
|
#define HCI_FLAG_CMD_COMPLETE (1UL << 0)
|
||||||
|
@ -74,7 +74,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_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))
|
||||||
|
@ -91,6 +90,10 @@
|
||||||
#define EV_REMOTE_NAME_COMPLETE 0x07
|
#define EV_REMOTE_NAME_COMPLETE 0x07
|
||||||
#define EV_ENCRYPTION_CHANGE 0x08
|
#define EV_ENCRYPTION_CHANGE 0x08
|
||||||
#define EV_CHANGE_CONNECTION_LINK 0x09
|
#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_ROLE_CHANGED 0x12
|
||||||
#define EV_NUM_COMPLETE_PKT 0x13
|
#define EV_NUM_COMPLETE_PKT 0x13
|
||||||
#define EV_PIN_CODE_REQUEST 0x16
|
#define EV_PIN_CODE_REQUEST 0x16
|
||||||
|
@ -98,15 +101,13 @@
|
||||||
#define EV_LINK_KEY_NOTIFICATION 0x18
|
#define EV_LINK_KEY_NOTIFICATION 0x18
|
||||||
#define EV_DATA_BUFFER_OVERFLOW 0x1A
|
#define EV_DATA_BUFFER_OVERFLOW 0x1A
|
||||||
#define EV_MAX_SLOTS_CHANGE 0x1B
|
#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_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_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_USER_CONFIRMATION_REQUEST 0x33
|
||||||
|
#define EV_SIMPLE_PAIRING_COMPLETE 0x36
|
||||||
|
|
||||||
/* Bluetooth states for the different Bluetooth drivers */
|
/* Bluetooth states for the different Bluetooth drivers */
|
||||||
#define L2CAP_WAIT 0
|
#define L2CAP_WAIT 0
|
||||||
|
@ -339,23 +340,23 @@ 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();
|
||||||
|
/** Used to check if the dongle supports simple paring */
|
||||||
void hci_read_local_extended_features(uint8_t page_number);
|
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.
|
||||||
*/
|
*/
|
||||||
void hci_write_local_name(const char* 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);
|
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. */
|
/** Enable visibility to other Bluetooth devices. */
|
||||||
void hci_write_scan_enable();
|
void hci_write_scan_enable();
|
||||||
/** Disable visibility to other Bluetooth devices. */
|
/** Disable visibility to other Bluetooth devices. */
|
||||||
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();
|
||||||
/**
|
/**
|
||||||
|
@ -376,7 +377,7 @@ 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();
|
||||||
|
/** Used to during simple paring to confirm that the we want to connect */
|
||||||
void hci_user_confirmation_request_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();
|
||||||
|
@ -386,13 +387,8 @@ public:
|
||||||
void hci_inquiry_cancel();
|
void hci_inquiry_cancel();
|
||||||
/** Connect to last device communicated with. */
|
/** Connect to last device communicated with. */
|
||||||
void hci_connect();
|
void hci_connect();
|
||||||
|
/** Used during simple paring to reply to a IO capability request */
|
||||||
void hci_read_remote_version_information();
|
void hci_io_capability_request_reply();
|
||||||
|
|
||||||
void hci_change_connection_packet_type_command();
|
|
||||||
|
|
||||||
void hci_write_link_policy_settings();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to device.
|
* Connect to device.
|
||||||
* @param bdaddr Bluetooth address of the device.
|
* @param bdaddr Bluetooth address of the device.
|
||||||
|
|
207
BTHID.cpp
207
BTHID.cpp
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "BTHID.h"
|
#include "BTHID.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
|
||||||
//#define PRINTREPORT // Uncomment to print the report send by the HID device
|
//#define PRINTREPORT // Uncomment to print the report send by the HID device
|
||||||
|
|
||||||
BTHID::BTHID(BTD *p, bool pair, const char *pin) :
|
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) {
|
void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
/*
|
|
||||||
Notify(PSTR("\r\nL2CAP Data - Channel ID: "), 0x80);
|
|
||||||
D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
|
|
||||||
Notify(PSTR(" "), 0x80);
|
|
||||||
D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
|
|
||||||
|
|
||||||
Notify(PSTR(", data: "), 0x80);
|
|
||||||
for(uint16_t i = 0; i < ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); i++) {
|
|
||||||
D_PrintHex<uint8_t > (l2capinbuf[i + 8], 0x80);
|
|
||||||
Notify(PSTR(" "), 0x80);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(!connected) {
|
if(!connected) {
|
||||||
if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||||
if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
|
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) {
|
} else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
|
||||||
if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
|
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]) {
|
if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
|
Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
|
||||||
|
#endif
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
sdp_scid[0] = l2capinbuf[12];
|
sdp_scid[0] = l2capinbuf[12];
|
||||||
sdp_scid[1] = l2capinbuf[13];
|
sdp_scid[1] = l2capinbuf[13];
|
||||||
|
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
|
Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
|
||||||
#endif
|
#endif
|
||||||
identifier++;
|
identifier++;
|
||||||
pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
|
pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
|
||||||
} else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
|
} else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
|
Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
|
||||||
|
#endif
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
control_scid[0] = l2capinbuf[12];
|
control_scid[0] = l2capinbuf[12];
|
||||||
control_scid[1] = l2capinbuf[13];
|
control_scid[1] = l2capinbuf[13];
|
||||||
l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
|
l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
|
||||||
} else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
|
} else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
|
Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
|
||||||
|
#endif
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
interrupt_scid[0] = l2capinbuf[12];
|
interrupt_scid[0] = l2capinbuf[12];
|
||||||
interrupt_scid[1] = l2capinbuf[13];
|
interrupt_scid[1] = l2capinbuf[13];
|
||||||
|
@ -172,28 +164,40 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
|
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
|
||||||
if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
|
if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
|
||||||
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
|
Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
|
||||||
|
#endif
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS);
|
l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS);
|
||||||
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
|
Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
|
||||||
|
#endif
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
|
l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
|
||||||
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
|
Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
|
||||||
|
#endif
|
||||||
identifier = l2capinbuf[9];
|
identifier = l2capinbuf[9];
|
||||||
l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
|
l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
|
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
|
||||||
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
|
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
|
||||||
|
#endif
|
||||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
|
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
|
||||||
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
|
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
|
||||||
|
#endif
|
||||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
|
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
|
||||||
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||||
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
|
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
|
||||||
|
#endif
|
||||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
|
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
|
||||||
}
|
}
|
||||||
} else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
|
} 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) {
|
} else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
|
||||||
if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
|
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];
|
identifier = l2capinbuf[9];
|
||||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
|
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
|
||||||
} else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
|
} 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];
|
identifier = l2capinbuf[9];
|
||||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE);
|
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE);
|
||||||
} else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
|
} 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];
|
identifier = l2capinbuf[9];
|
||||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE);
|
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[0] = SDP_SERVICE_SEARCH_RESPONSE;
|
||||||
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
|
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
|
||||||
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
|
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
|
||||||
#if 1
|
|
||||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||||
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
||||||
|
|
||||||
|
@ -267,29 +277,6 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
l2capoutbuf[9] = 0x00; // No continuation state
|
l2capoutbuf[9] = 0x00; // No continuation state
|
||||||
|
|
||||||
SDP_Command(l2capoutbuf, 10);
|
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) {
|
} else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) {
|
||||||
Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
|
Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
|
||||||
|
|
||||||
|
@ -298,7 +285,6 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
|
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
|
||||||
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
|
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
|
||||||
|
|
||||||
#if 1
|
|
||||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||||
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
||||||
|
|
||||||
|
@ -312,141 +298,9 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
l2capoutbuf[9] = 0x00; // No continuation state
|
l2capoutbuf[9] = 0x00; // No continuation state
|
||||||
|
|
||||||
SDP_Command(l2capoutbuf, 10);
|
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) {
|
} else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
|
||||||
Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
|
|
||||||
|
|
||||||
#ifdef EXTRADEBUG
|
#ifdef EXTRADEBUG
|
||||||
|
Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
|
||||||
Notify(PSTR("\r\nUUID: "), 0x80);
|
Notify(PSTR("\r\nUUID: "), 0x80);
|
||||||
uint16_t uuid;
|
uint16_t uuid;
|
||||||
if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit 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);
|
Notify(PSTR(" "), 0x80);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
|
serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
|
||||||
}
|
}
|
||||||
#ifdef EXTRADEBUG
|
#ifdef EXTRADEBUG
|
||||||
|
|
11
README.md
11
README.md
|
@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir
|
||||||
* __Oleg Mazurov, Circuits@Home__ - <mazurov@circuitsathome.com>
|
* __Oleg Mazurov, Circuits@Home__ - <mazurov@circuitsathome.com>
|
||||||
* __Alexei Glushchenko, Circuits@Home__ - <alex-gl@mail.ru>
|
* __Alexei Glushchenko, Circuits@Home__ - <alex-gl@mail.ru>
|
||||||
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
||||||
* __Kristian Lauszus, TKJ Electronics__ - <kristianl@tkjelectronics.com>
|
* __Kristian Sloth Lauszus__ - <kristianl@tkjelectronics.com>
|
||||||
* 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
|
* 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__ - <xxxajk@gmail.com>
|
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
||||||
* Major contributor to mass storage code
|
* 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 library](#xbox-library)
|
||||||
* [Xbox 360 Library](#xbox-360-library)
|
* [Xbox 360 Library](#xbox-360-library)
|
||||||
* [Xbox ONE Library](#xbox-one-library)
|
* [Xbox ONE Library](#xbox-one-library)
|
||||||
|
* [Xbox ONE S Library](#xbox-one-s-library)
|
||||||
* [Wii library](#wii-library)
|
* [Wii library](#wii-library)
|
||||||
* [PS Buzz Library](#ps-buzz-library)
|
* [PS Buzz Library](#ps-buzz-library)
|
||||||
* [HID Libraries](#hid-libraries)
|
* [HID Libraries](#hid-libraries)
|
||||||
|
@ -262,12 +263,18 @@ All the information regarding the Xbox 360 controller protocol are form these si
|
||||||
|
|
||||||
#### Xbox ONE Library
|
#### 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:
|
||||||
|
|
||||||
* <https://github.com/quantus/xbox-one-controller-protocol>
|
* <https://github.com/quantus/xbox-one-controller-protocol>
|
||||||
* <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
|
* <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
|
||||||
* <https://github.com/kylelemons/xbox/blob/master/xbox.go>
|
* <https://github.com/kylelemons/xbox/blob/master/xbox.go>
|
||||||
|
|
||||||
|
#### 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: <https://github.com/felis/USB_Host_Shield_2.0/issues/252#issuecomment-716912362>.
|
||||||
|
|
||||||
### [Wii library](Wii.cpp)
|
### [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.
|
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.
|
||||||
|
|
21
SPP.cpp
21
SPP.cpp
|
@ -531,6 +531,27 @@ void SPP::RFCOMM_task() {
|
||||||
/* SDP Commands */
|
/* 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) {
|
void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
|
||||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
|
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
|
||||||
l2capoutbuf[1] = transactionIDHigh;
|
l2capoutbuf[1] = transactionIDHigh;
|
||||||
|
|
100
XBOXONESBT.h
Normal file
100
XBOXONESBT.h
Normal file
|
@ -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<uint8_t > (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
|
200
XBOXONESParser.cpp
Normal file
200
XBOXONESParser.cpp
Normal file
|
@ -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<uint8_t > (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<uint8_t > (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
|
127
XBOXONESParser.h
Normal file
127
XBOXONESParser.h
Normal file
|
@ -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
|
|
@ -144,6 +144,12 @@ enum ButtonEnum {
|
||||||
WHITE = 9, // Available on the original Xbox controller
|
WHITE = 9, // Available on the original Xbox controller
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
/**@{*/
|
||||||
|
/** Xbox One S buttons */
|
||||||
|
VIEW = 4,
|
||||||
|
MENU = 5,
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
/** PS Buzz controllers */
|
/** PS Buzz controllers */
|
||||||
RED = 0,
|
RED = 0,
|
||||||
YELLOW = 1,
|
YELLOW = 1,
|
||||||
|
|
135
examples/Xbox/XBOXONESBT/XBOXONESBT.ino
Normal file
135
examples/Xbox/XBOXONESBT/XBOXONESBT.ino
Normal file
|
@ -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 <XBOXONESBT.h>
|
||||||
|
#include <usbhub.h>
|
||||||
|
|
||||||
|
// Satisfy the IDE, which needs to see the include statement in the ino too.
|
||||||
|
#ifdef dobogusinclude
|
||||||
|
#include <spi4teensy3.h>
|
||||||
|
#endif
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
USB Usb;
|
||||||
|
//USBHub Hub1(&Usb); // Some dongles have a hub inside
|
||||||
|
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||||
|
|
||||||
|
/* You can create the instance of the 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"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -196,6 +196,7 @@ XBOXUSB KEYWORD1
|
||||||
XBOXONE KEYWORD1
|
XBOXONE KEYWORD1
|
||||||
XBOXOLD KEYWORD1
|
XBOXOLD KEYWORD1
|
||||||
XBOXRECV KEYWORD1
|
XBOXRECV KEYWORD1
|
||||||
|
XBOXONESBT KEYWORD1
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
@ -227,6 +228,9 @@ BACK LITERAL1
|
||||||
XBOX LITERAL1
|
XBOX LITERAL1
|
||||||
SYNC LITERAL1
|
SYNC LITERAL1
|
||||||
|
|
||||||
|
VIEW LITERAL1
|
||||||
|
MENU LITERAL1
|
||||||
|
|
||||||
BLACK LITERAL1
|
BLACK LITERAL1
|
||||||
WHITE LITERAL1
|
WHITE LITERAL1
|
||||||
|
|
||||||
|
|
|
@ -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 1
|
#define ENABLE_UHS_DEBUGGING 0
|
||||||
|
|
||||||
/* 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.
|
||||||
|
|
Loading…
Reference in a new issue