mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Merge pull request #471 from felis/XBOXONES
Xbox One S controller support
This commit is contained in:
commit
1399dbf639
22 changed files with 1144 additions and 58 deletions
12
.travis.yml
12
.travis.yml
|
@ -1,6 +1,6 @@
|
|||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.9"
|
||||
|
||||
# Cache PlatformIO packages using Travis CI container-based infrastructure
|
||||
sudo: false
|
||||
|
@ -31,7 +31,7 @@ env:
|
|||
- PLATFORMIO_CI_SRC=examples/Bluetooth/PS4BT
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/SPP
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/SPPMulti
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/Wii
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/Wii SKIP_UNO=true
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/WiiBalanceBoard SKIP_UNO=true
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/WiiIRCamera PLATFORMIO_BUILD_FLAGS="-DWIICAMERA" SKIP_UNO=true
|
||||
- PLATFORMIO_CI_SRC=examples/Bluetooth/WiiMulti SKIP_UNO=true
|
||||
|
@ -62,13 +62,15 @@ env:
|
|||
- PLATFORMIO_CI_SRC=examples/PSBuzz
|
||||
# - PLATFORMIO_CI_SRC=examples/testusbhostFAT
|
||||
- PLATFORMIO_CI_SRC=examples/USB_desc
|
||||
- PLATFORMIO_CI_SRC=examples/USBH_MIDI/bidirectional_converter
|
||||
# See: https://travis-ci.org/github/felis/USB_Host_Shield_2.0/jobs/743787235
|
||||
- PLATFORMIO_CI_SRC=examples/USBH_MIDI/bidirectional_converter SKIP_TEENSY35=true SKIP_TEENSY36=true
|
||||
- PLATFORMIO_CI_SRC=examples/USBH_MIDI/eVY1_sample
|
||||
- PLATFORMIO_CI_SRC=examples/USBH_MIDI/USB_MIDI_converter
|
||||
- PLATFORMIO_CI_SRC=examples/USBH_MIDI/USB_MIDI_converter_multi
|
||||
- PLATFORMIO_CI_SRC=examples/USBH_MIDI/USBH_MIDI_dump
|
||||
- PLATFORMIO_CI_SRC=examples/Xbox/XBOXOLD
|
||||
- PLATFORMIO_CI_SRC=examples/Xbox/XBOXONE
|
||||
- PLATFORMIO_CI_SRC=examples/Xbox/XBOXONESBT
|
||||
- PLATFORMIO_CI_SRC=examples/Xbox/XBOXRECV
|
||||
- PLATFORMIO_CI_SRC=examples/Xbox/XBOXUSB
|
||||
|
||||
|
@ -86,7 +88,9 @@ install:
|
|||
|
||||
script:
|
||||
- if [[ -z "$SKIP_UNO" ]]; then UNO="--board=uno"; fi
|
||||
- platformio ci --lib="." $UNO --board=genuino101 --board=teensy30 --board=teensy31 --board=teensy35 --board=teensy36 --board=teensylc --board=esp12e --board=nodemcu --board=esp32dev
|
||||
- if [[ -z "$SKIP_TEENSY35" ]]; then TEENSY35="--board=teensy35"; fi
|
||||
- if [[ -z "$SKIP_TEENSY36" ]]; then TEENSY36="--board=teensy36"; fi
|
||||
- platformio ci --lib="." $UNO --board=genuino101 --board=teensy30 --board=teensy31 $TEENSY35 $TEENSY36 --board=teensylc --board=esp12e --board=nodemcu --board=esp32dev
|
||||
- platformio ci --lib="." --board=due --project-option="build_flags=-Wno-misleading-indentation" # Workaround https://travis-ci.org/felis/USB_Host_Shield_2.0/jobs/569237654 and https://github.com/arduino/ArduinoCore-sam/issues/69
|
||||
|
||||
before_deploy:
|
||||
|
|
256
BTD.cpp
256
BTD.cpp
|
@ -29,11 +29,13 @@ connectToWii(false),
|
|||
pairWithWii(false),
|
||||
connectToHIDDevice(false),
|
||||
pairWithHIDDevice(false),
|
||||
useSimplePairing(false),
|
||||
pUsb(p), // Pointer to USB class instance - mandatory
|
||||
bAddress(0), // Device address - mandatory
|
||||
bNumEP(1), // If config descriptor needs to be parsed
|
||||
qNextPollTime(0), // Reset NextPollTime
|
||||
pollInterval(0),
|
||||
simple_pairing_supported(false),
|
||||
bPollEnable(false) // Don't start polling before dongle is connected
|
||||
{
|
||||
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
|
||||
|
@ -321,6 +323,7 @@ void BTD::Initialize() {
|
|||
qNextPollTime = 0; // Reset next poll time
|
||||
pollInterval = 0;
|
||||
bPollEnable = false; // Don't start polling before dongle is connected
|
||||
simple_pairing_supported = false;
|
||||
}
|
||||
|
||||
/* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
|
||||
|
@ -408,7 +411,57 @@ 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
|
||||
if(hcibuf[6] == 0) { // Page 0
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDongle "), 0x80);
|
||||
#endif
|
||||
if(hcibuf[8 + 6] & (1U << 3)) {
|
||||
simple_pairing_supported = true;
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("supports"), 0x80);
|
||||
#endif
|
||||
} else {
|
||||
simple_pairing_supported = false;
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("does NOT support"), 0x80);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR(" secure simple pairing (controller support)"), 0x80);
|
||||
#endif
|
||||
} else if(hcibuf[6] == 1) { // Page 1
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDongle "), 0x80);
|
||||
if(hcibuf[8 + 0] & (1U << 0))
|
||||
Notify(PSTR("supports"), 0x80);
|
||||
else
|
||||
Notify(PSTR("does NOT support"), 0x80);
|
||||
Notify(PSTR(" secure simple pairing (host support)"), 0x80);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
hci_set_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES);
|
||||
} 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];
|
||||
|
@ -422,6 +475,12 @@ void BTD::HCI_event_task() {
|
|||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[2], 0x80);
|
||||
Notify(PSTR("\r\nNum HCI Command Packets: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[3], 0x80);
|
||||
Notify(PSTR("\r\nCommand Opcode: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[4], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[5], 0x80);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -465,7 +524,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 +532,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)
|
||||
|
@ -482,7 +543,6 @@ void BTD::HCI_event_task() {
|
|||
if(classOfDevice[0] & 0x08)
|
||||
Notify(PSTR("\r\nGamepad found"), 0x80);
|
||||
#endif
|
||||
|
||||
for(uint8_t j = 0; j < 6; j++)
|
||||
disc_bdaddr[j] = hcibuf[j + 3 + 6 * i];
|
||||
|
||||
|
@ -524,7 +584,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 +596,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);
|
||||
|
@ -598,6 +658,10 @@ void BTD::HCI_event_task() {
|
|||
Notify(PSTR("\r\nPairing successful with HID device"), 0x80);
|
||||
#endif
|
||||
connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device
|
||||
} else {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nPairing was successful"), 0x80);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
|
@ -608,24 +672,82 @@ void BTD::HCI_event_task() {
|
|||
hci_state = HCI_DISCONNECT_STATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_IO_CAPABILITY_REQUEST:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived IO Capability Request"), 0x80);
|
||||
#endif
|
||||
hci_io_capability_request_reply();
|
||||
break;
|
||||
|
||||
case EV_IO_CAPABILITY_RESPONSE:
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nReceived IO Capability Response: "), 0x80);
|
||||
Notify(PSTR("\r\nIO capability: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[8], 0x80);
|
||||
Notify(PSTR("\r\nOOB data present: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[9], 0x80);
|
||||
Notify(PSTR("\r\nAuthentication request: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[10], 0x80);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case EV_USER_CONFIRMATION_REQUEST:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nUser confirmation Request"), 0x80);
|
||||
#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
|
||||
#endif
|
||||
// Simply confirm the connection, as the host has no "NoInputNoOutput" capabilities
|
||||
hci_user_confirmation_request_reply();
|
||||
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;
|
||||
|
||||
/* We will just ignore the following events */
|
||||
case EV_MAX_SLOTS_CHANGE:
|
||||
case EV_NUM_COMPLETE_PKT:
|
||||
break;
|
||||
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:
|
||||
if(hcibuf[0] != 0x00) {
|
||||
Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
|
||||
Notify(PSTR(", data: "), 0x80);
|
||||
for(uint16_t i = 0; i < hcibuf[1]; i++) {
|
||||
D_PrintHex<uint8_t > (hcibuf[2 + i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
@ -700,18 +822,56 @@ 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)) {
|
||||
if(btdName != NULL) {
|
||||
hci_set_local_name(btdName);
|
||||
hci_state = HCI_SET_NAME_STATE;
|
||||
hci_write_local_name(btdName);
|
||||
hci_state = HCI_WRITE_NAME_STATE;
|
||||
} else if(useSimplePairing) {
|
||||
hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
|
||||
//hci_read_local_extended_features(1); // Read page 1
|
||||
hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE;
|
||||
} else
|
||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_SET_NAME_STATE:
|
||||
case HCI_WRITE_NAME_STATE:
|
||||
if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nThe name is set to: "), 0x80);
|
||||
Notify(PSTR("\r\nThe name was set to: "), 0x80);
|
||||
NotifyStr(btdName, 0x80);
|
||||
#endif
|
||||
if(useSimplePairing) {
|
||||
hci_read_local_extended_features(0); // "Requests the normal LMP features as returned by Read_Local_Supported_Features"
|
||||
//hci_read_local_extended_features(1); // Read page 1
|
||||
hci_state = HCI_LOCAL_EXTENDED_FEATURES_STATE;
|
||||
} else
|
||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_LOCAL_EXTENDED_FEATURES_STATE:
|
||||
if(hci_check_flag(HCI_FLAG_LOCAL_EXTENDED_FEATURES)) {
|
||||
if(simple_pairing_supported) {
|
||||
hci_write_simple_pairing_mode(true);
|
||||
hci_state = HCI_WRITE_SIMPLE_PAIRING_STATE;
|
||||
} else
|
||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_WRITE_SIMPLE_PAIRING_STATE:
|
||||
if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSimple pairing was enabled"), 0x80);
|
||||
#endif
|
||||
hci_set_event_mask();
|
||||
hci_state = HCI_SET_EVENT_MASK_STATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_SET_EVENT_MASK_STATE:
|
||||
if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSet event mask completed"), 0x80);
|
||||
#endif
|
||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||
}
|
||||
|
@ -783,7 +943,7 @@ 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_authentication_request(); // This will start the pairing with the device
|
||||
hci_state = HCI_SCANNING_STATE;
|
||||
} else {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
|
@ -855,7 +1015,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 +1159,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,7 +1204,7 @@ void BTD::hci_remote_name() {
|
|||
HCI_Command(hcibuf, 13);
|
||||
}
|
||||
|
||||
void BTD::hci_set_local_name(const char* name) {
|
||||
void BTD::hci_write_local_name(const char* name) {
|
||||
hcibuf[0] = 0x13; // HCI OCF = 13
|
||||
hcibuf[1] = 0x03 << 2; // HCI OGF = 3
|
||||
hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte
|
||||
|
@ -1046,6 +1216,33 @@ void BTD::hci_set_local_name(const char* name) {
|
|||
HCI_Command(hcibuf, 4 + strlen(name));
|
||||
}
|
||||
|
||||
void BTD::hci_set_event_mask() {
|
||||
hcibuf[0] = 0x01; // HCI OCF = 01
|
||||
hcibuf[1] = 0x03 << 2; // HCI OGF = 3
|
||||
hcibuf[2] = 0x08;
|
||||
// The first 6 bytes are the default of 1FFF FFFF FFFF
|
||||
// However we need to set bits 48-55 for simple pairing to work
|
||||
hcibuf[3] = 0xFF;
|
||||
hcibuf[4] = 0xFF;
|
||||
hcibuf[5] = 0xFF;
|
||||
hcibuf[6] = 0xFF;
|
||||
hcibuf[7] = 0xFF;
|
||||
hcibuf[8] = 0x1F;
|
||||
hcibuf[9] = 0xFF; // Enable bits 48-55 used for simple pairing
|
||||
hcibuf[10] = 0x00;
|
||||
|
||||
HCI_Command(hcibuf, 11);
|
||||
}
|
||||
|
||||
void BTD::hci_write_simple_pairing_mode(bool enable) {
|
||||
hcibuf[0] = 0x56; // HCI OCF = 56
|
||||
hcibuf[1] = 0x03 << 2; // HCI OGF = 3
|
||||
hcibuf[2] = 1; // parameter length = 1
|
||||
hcibuf[3] = enable ? 1 : 0;
|
||||
|
||||
HCI_Command(hcibuf, 4);
|
||||
}
|
||||
|
||||
void BTD::hci_inquiry() {
|
||||
hci_clear_flag(HCI_FLAG_DEVICE_FOUND);
|
||||
hcibuf[0] = 0x01;
|
||||
|
@ -1074,7 +1271,7 @@ void BTD::hci_connect() {
|
|||
|
||||
void BTD::hci_connect(uint8_t *bdaddr) {
|
||||
hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE | HCI_FLAG_CONNECT_EVENT);
|
||||
hcibuf[0] = 0x05;
|
||||
hcibuf[0] = 0x05; // HCI OCF = 5
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
hcibuf[2] = 0x0D; // parameter Total Length = 13
|
||||
hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB)
|
||||
|
@ -1158,6 +1355,37 @@ void BTD::hci_link_key_request_negative_reply() {
|
|||
HCI_Command(hcibuf, 9);
|
||||
}
|
||||
|
||||
void BTD::hci_io_capability_request_reply() {
|
||||
hcibuf[0] = 0x2B; // HCI OCF = 2B
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
hcibuf[2] = 0x09;
|
||||
hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
|
||||
hcibuf[4] = disc_bdaddr[1];
|
||||
hcibuf[5] = disc_bdaddr[2];
|
||||
hcibuf[6] = disc_bdaddr[3];
|
||||
hcibuf[7] = disc_bdaddr[4];
|
||||
hcibuf[8] = disc_bdaddr[5];
|
||||
hcibuf[9] = 0x03; // NoInputNoOutput
|
||||
hcibuf[10] = 0x00; // OOB authentication data not present
|
||||
hcibuf[11] = 0x00; // MITM Protection Not Required – No Bonding. Numeric comparison with automatic accept allowed
|
||||
|
||||
HCI_Command(hcibuf, 12);
|
||||
}
|
||||
|
||||
void BTD::hci_user_confirmation_request_reply() {
|
||||
hcibuf[0] = 0x2C; // HCI OCF = 2C
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
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
|
||||
|
|
46
BTD.h
46
BTD.h
|
@ -45,7 +45,7 @@
|
|||
#define HCI_CLASS_STATE 2
|
||||
#define HCI_BDADDR_STATE 3
|
||||
#define HCI_LOCAL_VERSION_STATE 4
|
||||
#define HCI_SET_NAME_STATE 5
|
||||
#define HCI_WRITE_NAME_STATE 5
|
||||
#define HCI_CHECK_DEVICE_SERVICE 6
|
||||
|
||||
#define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a device
|
||||
|
@ -59,6 +59,9 @@
|
|||
#define HCI_DISABLE_SCAN_STATE 14
|
||||
#define HCI_DONE_STATE 15
|
||||
#define HCI_DISCONNECT_STATE 16
|
||||
#define HCI_LOCAL_EXTENDED_FEATURES_STATE 17
|
||||
#define HCI_WRITE_SIMPLE_PAIRING_STATE 18
|
||||
#define HCI_SET_EVENT_MASK_STATE 19
|
||||
|
||||
/* HCI event flags*/
|
||||
#define HCI_FLAG_CMD_COMPLETE (1UL << 0)
|
||||
|
@ -70,6 +73,7 @@
|
|||
#define HCI_FLAG_READ_VERSION (1UL << 6)
|
||||
#define HCI_FLAG_DEVICE_FOUND (1UL << 7)
|
||||
#define HCI_FLAG_CONNECT_EVENT (1UL << 8)
|
||||
#define HCI_FLAG_LOCAL_EXTENDED_FEATURES (1UL << 9)
|
||||
|
||||
/* Macros for HCI event flag tests */
|
||||
#define hci_check_flag(flag) (hci_event_flag & (flag))
|
||||
|
@ -86,6 +90,10 @@
|
|||
#define EV_REMOTE_NAME_COMPLETE 0x07
|
||||
#define EV_ENCRYPTION_CHANGE 0x08
|
||||
#define EV_CHANGE_CONNECTION_LINK 0x09
|
||||
#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
|
||||
#define EV_QOS_SETUP_COMPLETE 0x0D
|
||||
#define EV_COMMAND_COMPLETE 0x0E
|
||||
#define EV_COMMAND_STATUS 0x0F
|
||||
#define EV_ROLE_CHANGED 0x12
|
||||
#define EV_NUM_COMPLETE_PKT 0x13
|
||||
#define EV_PIN_CODE_REQUEST 0x16
|
||||
|
@ -93,12 +101,13 @@
|
|||
#define EV_LINK_KEY_NOTIFICATION 0x18
|
||||
#define EV_DATA_BUFFER_OVERFLOW 0x1A
|
||||
#define EV_MAX_SLOTS_CHANGE 0x1B
|
||||
#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
|
||||
#define EV_QOS_SETUP_COMPLETE 0x0D
|
||||
#define EV_COMMAND_COMPLETE 0x0E
|
||||
#define EV_COMMAND_STATUS 0x0F
|
||||
#define EV_LOOPBACK_COMMAND 0x19
|
||||
#define EV_PAGE_SCAN_REP_MODE 0x20
|
||||
#define EV_READ_REMOTE_EXTENDED_FEATURES_COMPLETE 0x23
|
||||
#define EV_IO_CAPABILITY_REQUEST 0x31
|
||||
#define EV_IO_CAPABILITY_RESPONSE 0x32
|
||||
#define EV_USER_CONFIRMATION_REQUEST 0x33
|
||||
#define EV_SIMPLE_PAIRING_COMPLETE 0x36
|
||||
|
||||
/* Bluetooth states for the different Bluetooth drivers */
|
||||
#define L2CAP_WAIT 0
|
||||
|
@ -183,6 +192,17 @@
|
|||
#define HID_CTRL_PSM 0x11 // HID_Control PSM Value
|
||||
#define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
|
||||
|
||||
/* Used for SDP */
|
||||
#define SDP_SERVICE_SEARCH_REQUEST 0x02
|
||||
#define SDP_SERVICE_SEARCH_RESPONSE 0x03
|
||||
#define SDP_SERVICE_ATTRIBUTE_REQUEST 0x04
|
||||
#define SDP_SERVICE_ATTRIBUTE_RESPONSE 0x05
|
||||
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 // See the RFCOMM specs
|
||||
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 // See the RFCOMM specs
|
||||
#define PNP_INFORMATION_UUID 0x1200
|
||||
#define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
|
||||
#define L2CAP_UUID 0x0100
|
||||
|
||||
// Used to determine if it is a Bluetooth dongle
|
||||
#define WI_SUBCLASS_RF 0x01 // RF Controller
|
||||
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
||||
|
@ -320,11 +340,17 @@ public:
|
|||
void hci_read_bdaddr();
|
||||
/** Read the HCI Version of the Bluetooth dongle. */
|
||||
void hci_read_local_version_information();
|
||||
/** Used to check if the dongle supports simple paring */
|
||||
void hci_read_local_extended_features(uint8_t page_number);
|
||||
/**
|
||||
* Set the local name of the Bluetooth dongle.
|
||||
* @param name Desired name.
|
||||
*/
|
||||
void hci_set_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);
|
||||
/** Used to enable events related to simple paring */
|
||||
void hci_set_event_mask();
|
||||
/** Enable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_enable();
|
||||
/** Disable visibility to other Bluetooth devices. */
|
||||
|
@ -351,6 +377,8 @@ public:
|
|||
* if the Host does not have a stored Link Key for the connection.
|
||||
*/
|
||||
void hci_link_key_request_negative_reply();
|
||||
/** Used to during simple paring to confirm that the we want to connect */
|
||||
void hci_user_confirmation_request_reply();
|
||||
/** Used to try to authenticate with the remote device. */
|
||||
void hci_authentication_request();
|
||||
/** Start a HCI inquiry. */
|
||||
|
@ -359,6 +387,8 @@ public:
|
|||
void hci_inquiry_cancel();
|
||||
/** Connect to last device communicated with. */
|
||||
void hci_connect();
|
||||
/** Used during simple paring to reply to a IO capability request */
|
||||
void hci_io_capability_request_reply();
|
||||
/**
|
||||
* Connect to device.
|
||||
* @param bdaddr Bluetooth address of the device.
|
||||
|
@ -500,6 +530,9 @@ public:
|
|||
return pollInterval;
|
||||
};
|
||||
|
||||
/** Used by the drivers to enable simple pairing */
|
||||
bool useSimplePairing;
|
||||
|
||||
protected:
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
|
@ -537,6 +570,7 @@ private:
|
|||
uint16_t PID, VID; // PID and VID of device connected
|
||||
|
||||
uint8_t pollInterval;
|
||||
bool simple_pairing_supported;
|
||||
bool bPollEnable;
|
||||
|
||||
bool pairWiiUsingSync; // True if pairing was done using the Wii SYNC button.
|
||||
|
|
249
BTHID.cpp
249
BTHID.cpp
|
@ -30,6 +30,8 @@ protocolMode(USB_HID_BOOT_PROTOCOL) {
|
|||
pBtd->btdPin = pin;
|
||||
|
||||
/* Set device cid for the control and intterrupt channelse - LSB */
|
||||
sdp_dcid[0] = 0x50; // 0x0050
|
||||
sdp_dcid[1] = 0x00;
|
||||
control_dcid[0] = 0x70; // 0x0070
|
||||
control_dcid[1] = 0x00;
|
||||
interrupt_dcid[0] = 0x71; // 0x0071
|
||||
|
@ -41,19 +43,34 @@ protocolMode(USB_HID_BOOT_PROTOCOL) {
|
|||
void BTHID::Reset() {
|
||||
connected = false;
|
||||
activeConnection = false;
|
||||
SDPConnected = false;
|
||||
l2cap_event_flag = 0; // Reset flags
|
||||
l2cap_sdp_state = L2CAP_SDP_WAIT;
|
||||
l2cap_state = L2CAP_WAIT;
|
||||
ResetBTHID();
|
||||
}
|
||||
|
||||
void BTHID::disconnect() { // Use this void to disconnect the device
|
||||
if(SDPConnected)
|
||||
pBtd->l2cap_disconnection_request(hci_handle, ++identifier, sdp_scid, sdp_dcid);
|
||||
// First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
|
||||
pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid);
|
||||
Reset();
|
||||
l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE;
|
||||
l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
|
||||
}
|
||||
|
||||
void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||
if(!connected) {
|
||||
if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||
if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
|
||||
pBtd->sdpConnectionClaimed = true;
|
||||
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
|
||||
l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!pBtd->l2capConnectionClaimed && pBtd->incomingHIDDevice && !connected && !activeConnection) {
|
||||
if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||
if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
|
||||
|
@ -85,14 +102,30 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
|||
#endif
|
||||
} else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
|
||||
if(((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
|
||||
if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
|
||||
//Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
|
||||
if(l2capinbuf[14] == sdp_dcid[0] && l2capinbuf[15] == sdp_dcid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nSDP Connection Complete"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
sdp_scid[0] = l2capinbuf[12];
|
||||
sdp_scid[1] = l2capinbuf[13];
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend SDP Config Request"), 0x80);
|
||||
#endif
|
||||
identifier++;
|
||||
pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
|
||||
} else if(l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nHID Control Connection Complete"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
control_scid[0] = l2capinbuf[12];
|
||||
control_scid[1] = l2capinbuf[13];
|
||||
l2cap_set_flag(L2CAP_FLAG_CONTROL_CONNECTED);
|
||||
} else if(l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
|
||||
//Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nHID Interrupt Connection Complete"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
interrupt_scid[0] = l2capinbuf[12];
|
||||
interrupt_scid[1] = l2capinbuf[13];
|
||||
|
@ -112,7 +145,12 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
|||
Notify(PSTR(" Identifier: "), 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
#endif
|
||||
if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
|
||||
if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) {
|
||||
identifier = l2capinbuf[9];
|
||||
sdp_scid[0] = l2capinbuf[14];
|
||||
sdp_scid[1] = l2capinbuf[15];
|
||||
l2cap_set_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST);
|
||||
} else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
|
||||
identifier = l2capinbuf[9];
|
||||
control_scid[0] = l2capinbuf[14];
|
||||
control_scid[1] = l2capinbuf[15];
|
||||
|
@ -125,26 +163,51 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
|||
}
|
||||
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
|
||||
if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
|
||||
if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
//Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
|
||||
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS);
|
||||
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS);
|
||||
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
//Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS);
|
||||
}
|
||||
}
|
||||
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
|
||||
if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
//Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
|
||||
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
|
||||
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
|
||||
} else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
//Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
|
||||
}
|
||||
} else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
|
||||
if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST);
|
||||
} else if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
|
||||
#endif
|
||||
|
@ -160,15 +223,31 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
|||
Reset();
|
||||
}
|
||||
} else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
|
||||
if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
|
||||
//Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
|
||||
if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
|
||||
} else if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE);
|
||||
} else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
|
||||
//Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE);
|
||||
}
|
||||
} else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nInformation request"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
|
@ -176,6 +255,78 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
|||
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
}
|
||||
#endif
|
||||
} else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
|
||||
if(l2capinbuf[8] == SDP_SERVICE_SEARCH_REQUEST) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nSDP_SERVICE_SEARCH_REQUEST"), 0x80);
|
||||
#endif
|
||||
// Send response
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_RESPONSE;
|
||||
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
|
||||
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
|
||||
|
||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
||||
|
||||
l2capoutbuf[5] = 0x00; // MSB TotalServiceRecordCount
|
||||
l2capoutbuf[6] = 0x00; // LSB TotalServiceRecordCount = 0
|
||||
|
||||
l2capoutbuf[7] = 0x00; // MSB CurrentServiceRecordCount
|
||||
l2capoutbuf[8] = 0x00; // LSB CurrentServiceRecordCount = 0
|
||||
|
||||
l2capoutbuf[9] = 0x00; // No continuation state
|
||||
|
||||
SDP_Command(l2capoutbuf, 10);
|
||||
} else if(l2capinbuf[8] == SDP_SERVICE_ATTRIBUTE_REQUEST) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nSDP_SERVICE_ATTRIBUTE_REQUEST"), 0x80);
|
||||
#endif
|
||||
// Send response
|
||||
l2capoutbuf[0] = SDP_SERVICE_ATTRIBUTE_RESPONSE;
|
||||
l2capoutbuf[1] = l2capinbuf[9];//transactionIDHigh;
|
||||
l2capoutbuf[2] = l2capinbuf[10];//transactionIDLow;
|
||||
|
||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
||||
|
||||
l2capoutbuf[5] = 0x00; // MSB AttributeListByteCount
|
||||
l2capoutbuf[6] = 0x02; // LSB AttributeListByteCount = 2
|
||||
|
||||
// TODO: What to send?
|
||||
l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
|
||||
l2capoutbuf[8] = 0x00; // Length = 0
|
||||
|
||||
l2capoutbuf[9] = 0x00; // No continuation state
|
||||
|
||||
SDP_Command(l2capoutbuf, 10);
|
||||
} else if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nSDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST"), 0x80);
|
||||
Notify(PSTR("\r\nUUID: "), 0x80);
|
||||
uint16_t uuid;
|
||||
if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
|
||||
uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
|
||||
else // Short UUID
|
||||
uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
|
||||
D_PrintHex<uint16_t > (uuid, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nLength: "), 0x80);
|
||||
uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
|
||||
D_PrintHex<uint16_t > (length, 0x80);
|
||||
Notify(PSTR("\r\nData: "), 0x80);
|
||||
for(uint8_t i = 0; i < length; i++) {
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
#endif
|
||||
serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nUnknown PDU: "), 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
}
|
||||
#endif
|
||||
} else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
|
||||
#ifdef PRINTREPORT
|
||||
|
@ -231,10 +382,59 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
SDP_task();
|
||||
L2CAP_task();
|
||||
}
|
||||
}
|
||||
|
||||
void BTHID::SDP_task() {
|
||||
switch(l2cap_sdp_state) {
|
||||
case L2CAP_SDP_WAIT:
|
||||
if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST)) {
|
||||
l2cap_clear_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST); // Clear flag
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING);
|
||||
delay(1);
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, SUCCESSFUL);
|
||||
identifier++;
|
||||
delay(1);
|
||||
pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
|
||||
l2cap_sdp_state = L2CAP_SDP_SUCCESS;
|
||||
} else if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST)) {
|
||||
l2cap_clear_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST); // Clear flag
|
||||
SDPConnected = false;
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid);
|
||||
}
|
||||
break;
|
||||
case L2CAP_SDP_SUCCESS:
|
||||
if(l2cap_check_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS)) {
|
||||
l2cap_clear_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); // Clear flag
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
|
||||
#endif
|
||||
SDPConnected = true;
|
||||
l2cap_sdp_state = L2CAP_SDP_WAIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
|
||||
if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_RESPONSE)) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
|
||||
#endif
|
||||
pBtd->hci_disconnect(hci_handle);
|
||||
hci_handle = -1; // Reset handle
|
||||
Reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BTHID::L2CAP_task() {
|
||||
switch(l2cap_state) {
|
||||
/* These states are used if the HID device is the host */
|
||||
|
@ -371,6 +571,27 @@ void BTHID::Run() {
|
|||
}
|
||||
}
|
||||
|
||||
void BTHID::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
|
||||
pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
|
||||
}
|
||||
|
||||
void BTHID::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
|
||||
l2capoutbuf[1] = transactionIDHigh;
|
||||
l2capoutbuf[2] = transactionIDLow;
|
||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||
l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
|
||||
l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
|
||||
l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
|
||||
|
||||
/* Attribute ID/Value Sequence: */
|
||||
l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
|
||||
l2capoutbuf[8] = 0x00; // Length = 0
|
||||
l2capoutbuf[9] = 0x00; // No continuation state
|
||||
|
||||
SDP_Command(l2capoutbuf, 10);
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* HID Commands */
|
||||
|
||||
|
|
10
BTHID.h
10
BTHID.h
|
@ -141,20 +141,30 @@ protected:
|
|||
/** L2CAP source CID for HID_Interrupt */
|
||||
uint8_t interrupt_scid[2];
|
||||
|
||||
uint8_t l2cap_sdp_state;
|
||||
uint8_t sdp_scid[2]; // L2CAP source CID for SDP
|
||||
|
||||
private:
|
||||
HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
|
||||
|
||||
uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data
|
||||
void SDP_Command(uint8_t* data, uint8_t nbytes);
|
||||
void serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow);
|
||||
|
||||
/** Set report protocol. */
|
||||
void setProtocol();
|
||||
uint8_t protocolMode;
|
||||
|
||||
void SDP_task();
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
|
||||
bool activeConnection; // Used to indicate if it already has established a connection
|
||||
bool SDPConnected;
|
||||
|
||||
/* Variables used for L2CAP communication */
|
||||
uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070
|
||||
uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071
|
||||
uint8_t sdp_dcid[2];
|
||||
uint8_t l2cap_state;
|
||||
};
|
||||
#endif
|
||||
|
|
15
README.md
15
README.md
|
@ -19,10 +19,10 @@ For more information about the hardware see the [Hardware Manual](https://chome.
|
|||
|
||||
# Developed By
|
||||
|
||||
* __Oleg Mazurov - <mazurov@gmail.com>
|
||||
* __Alexei Glushchenko, Circuits@Home__ - <alex-gl@mail.ru>
|
||||
* __Oleg Mazurov__ - <mazurov@gmail.com>
|
||||
* __Alexei Glushchenko__ - <alex-gl@mail.ru>
|
||||
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
||||
* __Kristian Lauszus, TKJ Electronics__ - <kristianl@tkjelectronics.com>
|
||||
* __Kristian Sloth Lauszus__ - <lauszus@gmail.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
|
||||
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
||||
* Major contributor to mass storage code
|
||||
|
@ -50,6 +50,7 @@ For more information about the hardware see the [Hardware Manual](https://chome.
|
|||
* [Xbox library](#xbox-library)
|
||||
* [Xbox 360 Library](#xbox-360-library)
|
||||
* [Xbox ONE Library](#xbox-one-library)
|
||||
* [Xbox ONE S Library](#xbox-one-s-library)
|
||||
* [Wii library](#wii-library)
|
||||
* [PS Buzz Library](#ps-buzz-library)
|
||||
* [HID Libraries](#hid-libraries)
|
||||
|
@ -257,12 +258,18 @@ All the information regarding the Xbox 360 controller protocol are form these si
|
|||
|
||||
#### Xbox ONE Library
|
||||
|
||||
An Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at:
|
||||
A Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at:
|
||||
|
||||
* <https://github.com/quantus/xbox-one-controller-protocol>
|
||||
* <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
|
||||
* <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)
|
||||
|
||||
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.
|
||||
|
|
8
SPP.cpp
8
SPP.cpp
|
@ -189,7 +189,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
}
|
||||
#endif
|
||||
} else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
|
||||
if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) {
|
||||
if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
|
||||
if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == SERIALPORT_UUID)) { // Check if it's sending the full UUID, see: https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm, we will just check the first four bytes
|
||||
if(firstMessage) {
|
||||
serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
|
||||
|
@ -536,7 +536,7 @@ void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bl
|
|||
}
|
||||
|
||||
void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
|
||||
l2capoutbuf[1] = transactionIDHigh;
|
||||
l2capoutbuf[2] = transactionIDLow;
|
||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||
|
@ -553,7 +553,7 @@ void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLo
|
|||
}
|
||||
|
||||
void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
|
||||
l2capoutbuf[1] = transactionIDHigh;
|
||||
l2capoutbuf[2] = transactionIDLow;
|
||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||
|
@ -615,7 +615,7 @@ void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLo
|
|||
}
|
||||
|
||||
void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
|
||||
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
|
||||
l2capoutbuf[1] = transactionIDHigh;
|
||||
l2capoutbuf[2] = transactionIDLow;
|
||||
l2capoutbuf[3] = 0x00; // MSB Parameter Length
|
||||
|
|
6
SPP.h
6
SPP.h
|
@ -20,12 +20,6 @@
|
|||
|
||||
#include "BTD.h"
|
||||
|
||||
/* Used for SDP */
|
||||
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs
|
||||
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs
|
||||
#define SERIALPORT_UUID 0x1101 // See http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
|
||||
#define L2CAP_UUID 0x0100
|
||||
|
||||
/* Used for RFCOMM */
|
||||
#define RFCOMM_SABM 0x2F
|
||||
#define RFCOMM_UA 0x63
|
||||
|
|
101
XBOXONESBT.h
Normal file
101
XBOXONESBT.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* 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();
|
||||
pBtd->useSimplePairing = true; // The Xbox One S controller only works via simple pairing
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
|
@ -108,12 +108,14 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
|
|||
theBuffer.valueSize = 2;
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 1;
|
||||
// fall through
|
||||
case 1:
|
||||
if(!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
dscrLen = *((uint8_t*)theBuffer.pValue);
|
||||
dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
||||
stateParseDescr = 2;
|
||||
// fall through
|
||||
case 2:
|
||||
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
|
||||
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
||||
|
@ -122,6 +124,7 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
|
|||
// in the buffer.
|
||||
theBuffer.pValue = varBuffer + 2;
|
||||
stateParseDescr = 3;
|
||||
// fall through
|
||||
case 3:
|
||||
switch(dscrType) {
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
|
@ -135,6 +138,7 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
|
|||
theBuffer.valueSize = dscrLen - 2;
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 4;
|
||||
// fall through
|
||||
case 4:
|
||||
switch(dscrType) {
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
|
|
|
@ -144,6 +144,12 @@ enum ButtonEnum {
|
|||
WHITE = 9, // Available on the original Xbox controller
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/** Xbox One S buttons */
|
||||
VIEW = 4,
|
||||
MENU = 5,
|
||||
/**@}*/
|
||||
|
||||
/** PS Buzz controllers */
|
||||
RED = 0,
|
||||
YELLOW = 1,
|
||||
|
|
|
@ -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;
|
||||
|
|
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"));
|
||||
}
|
||||
}
|
|
@ -1113,16 +1113,19 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
|
|||
|
||||
if(!pcntdn)
|
||||
return enErrorIncomplete;
|
||||
// fall through
|
||||
case 1:
|
||||
//USBTRACE2("\r\niSz:",itemSize);
|
||||
|
||||
theBuffer.valueSize = itemSize;
|
||||
valParser.Initialize(&theBuffer);
|
||||
itemParseState = 2;
|
||||
// fall through
|
||||
case 2:
|
||||
if(!valParser.Parse(pp, pcntdn))
|
||||
return enErrorIncomplete;
|
||||
itemParseState = 3;
|
||||
// fall through
|
||||
case 3:
|
||||
{
|
||||
uint8_t data = *((uint8_t*)varBuffer);
|
||||
|
@ -1448,14 +1451,17 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
|
|||
|
||||
if(!pcntdn)
|
||||
return enErrorIncomplete;
|
||||
// fall through
|
||||
case 1:
|
||||
theBuffer.valueSize = itemSize;
|
||||
valParser.Initialize(&theBuffer);
|
||||
itemParseState = 2;
|
||||
// fall through
|
||||
case 2:
|
||||
if(!valParser.Parse(pp, pcntdn))
|
||||
return enErrorIncomplete;
|
||||
itemParseState = 3;
|
||||
// fall through
|
||||
case 3:
|
||||
{
|
||||
uint8_t data = *((uint8_t*)varBuffer);
|
||||
|
|
|
@ -196,6 +196,7 @@ XBOXUSB KEYWORD1
|
|||
XBOXONE KEYWORD1
|
||||
XBOXOLD KEYWORD1
|
||||
XBOXRECV KEYWORD1
|
||||
XBOXONESBT KEYWORD1
|
||||
|
||||
####################################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
|
@ -227,6 +228,9 @@ BACK LITERAL1
|
|||
XBOX LITERAL1
|
||||
SYNC LITERAL1
|
||||
|
||||
VIEW LITERAL1
|
||||
MENU LITERAL1
|
||||
|
||||
BLACK LITERAL1
|
||||
WHITE LITERAL1
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
"email": "alex-gl@mail.ru"
|
||||
},
|
||||
{
|
||||
"name": "Kristian Lauszus",
|
||||
"email": "kristianl@tkjelectronics.com",
|
||||
"url": "http://tkjelectronics.com",
|
||||
"name": "Kristian Sloth Lauszus",
|
||||
"email": "lauszus@gmail.com",
|
||||
"url": "https://lauszus.com",
|
||||
"maintainer": true
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
name=USB Host Shield Library 2.0
|
||||
version=1.3.2
|
||||
author=Oleg Mazurov (Circuits@Home) <mazurov@circuitsathome.com>, Kristian Lauszus (TKJ Electronics) <kristianl@tkjelectronics.com>, Andrew Kroll <xxxajk@gmail.com>, Alexei Glushchenko (Circuits@Home) <alex-gl@mail.ru>
|
||||
maintainer=Oleg Mazurov (Circuits@Home) <mazurov@circuitsathome.com>, Kristian Lauszus (TKJ Electronics) <kristianl@tkjelectronics.com>, Andrew Kroll <xxxajk@gmail.com>
|
||||
author=Oleg Mazurov (Circuits@Home) <mazurov@circuitsathome.com>, Kristian Sloth Lauszus <lauszus@gmail.com>, Andrew Kroll <xxxajk@gmail.com>, Alexei Glushchenko (Circuits@Home) <alex-gl@mail.ru>
|
||||
maintainer=Oleg Mazurov (Circuits@Home) <mazurov@circuitsathome.com>, Kristian Sloth Lauszus <lauszus@gmail.com>, Andrew Kroll <xxxajk@gmail.com>
|
||||
sentence=Revision 2.0 of MAX3421E-based USB Host Shield Library.
|
||||
paragraph=Supports HID devices, FTDI, ADK, ACM, PL2303, Bluetooth HID devices, SPP communication and mass storage devices. Furthermore it supports PS3, PS4, PS Buzz, Wii and Xbox controllers.
|
||||
category=Other
|
||||
|
|
|
@ -44,6 +44,7 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf,
|
|||
pBuf->valueSize = lenSize;
|
||||
theParser.Initialize(pBuf);
|
||||
nStage = 1;
|
||||
// fall through
|
||||
|
||||
case 1:
|
||||
if(!theParser.Parse(pp, pcntdn))
|
||||
|
@ -53,11 +54,13 @@ bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf,
|
|||
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
||||
arLenCntdn = arLen;
|
||||
nStage = 2;
|
||||
// fall through
|
||||
|
||||
case 2:
|
||||
pBuf->valueSize = valSize;
|
||||
theParser.Initialize(pBuf);
|
||||
nStage = 3;
|
||||
// fall through
|
||||
|
||||
case 3:
|
||||
for(; arLenCntdn; arLenCntdn--) {
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
case 0:
|
||||
countDown = bytes_to_skip;
|
||||
nStage++;
|
||||
// fall through
|
||||
case 1:
|
||||
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
||||
|
||||
|
|
|
@ -589,6 +589,7 @@ uint8_t USBH_MIDI::SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable
|
|||
break;
|
||||
case 3 :
|
||||
buf[wptr] = (nCable << 4) | 0x7; //x7 SysEx ends with following three bytes.
|
||||
// fall through
|
||||
default :
|
||||
wptr++;
|
||||
buf[wptr++] = *(dataptr++);
|
||||
|
|
Loading…
Reference in a new issue