XBox One S Wireless Controller Possibly Invalid HID Descriptor - bluetooth
I have been trying to connect my ESP-32 microcontroller to an XBox One S Wireless controller via classic bluetooth using this BTStack implemented by Bluekitchen. I have managed to connect the two devices (with the ESP-32 as the host) and can read all the values from the controller on the ESP-32. I am now trying to work out how to send valid reports to the controller. The descriptor reported by the controller upon connection is this:
05 01 09 05 A1 01 85 01 09 01 A1 00 09 30 09 31 15 00 27 FF FF 00 00 95 02 75 10 81 02 C0 09 01 A1 00 09 33 09 34 15 00 27 FF FF 00 00 95 02 75 10 81 02 C0 05 01 09 32 15 00 26 FF 03 95 01 75 0A 81 02 15 00 25 00 75 06 95 01 81 03 05 01 09 35 15 00 26 FF 03 95 01 75 0A 81 02 15 00 25 00 75 06 95 01 81 03 05 01 09 39 15 01 25 08 35 00 46 3B 01 66 14 00 75 04 95 01 81 42 75 04 95 01 15 00 25 00 35 00 45 00 65 00 81 03 05 09 19 01 29 0A 15 00 25 01 75 01 95 0A 81 02 15 00 25 00 75 06 95 01 81 03 05 01 09 80 85 02 A1 00 09 85 15 00 25 01 95 01 75 01 81 02 15 00 25 00 75 07 95 01 81 03 C0 05 0F 09 21 85 03 A1 02 09 97 15 00 25 01 75 04 95 01 91 02 15 00 25 00 75 04 95 01 91 03 09 70 15 00 25 64 75 08 95 04 91 02 09 50 66 01 10 55 0E 15 00 26 FF 00 75 08 95 01 91 02 09 A7 15 00 26 FF 00 75 08 95 01 91 02 65 00 55 00 09 7C 15 00 26 FF 00 75 08 95 01 91 02 C0 85 04 05 06 09 20 15 00 26 FF 00 75 08 95 01 81 02 C0
When I run this dump through this translator, I get a readable output that is included at the end of the question since it is quite long. Only the output report format of the HID descriptor is listed here:
0x05, 0x0F, // Usage Page (PID Page)
0x09, 0x21, // Usage (0x21)
0x85, 0x03, // Report ID (3)
0xA1, 0x02, // Collection (Logical)
0x09, 0x97, // Usage (0x97)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x70, // Usage (0x70)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x64, // Logical Maximum (100)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x50, // Usage (0x50)
0x66, 0x01, 0x10, // Unit (System: SI Linear, Time: Seconds)
0x55, 0x0E, // Unit Exponent (-2)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0xA7, // Usage (0xA7)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x65, 0x00, // Unit (None)
0x55, 0x00, // Unit Exponent (0)
0x09, 0x7C, // Usage (0x7C)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
My understanding of the HID standard would indicate that this part of the descriptor is invalid, since Usage (0x70) is followed by Report Count (4), the btstack parser that I am using to debug why this isn't working then has to try to match 4 bytes to a single usage and isn't able to do this as far as I am aware. Currently the report I am trying to send to the controller (and to the parser, while I am debugging) is 0x03, 0xF0, 0x64, 0x64, 0x64, 0x64, 0xFF, 0x10, 0x05, where the 0x03 indicates the report ID, and the following values indicate parameters I am sending to control rumble motors. The 4 0x64 values are the 4 bytes that should be mapped to 4 usages, however only correspond to 1 usage 0x70 according to the HID Descriptor. At the moment the parser stops after finding the first 0x64 and claims to be finished.
Am I wrong in thinking this HID Descriptor is invalid? If I am, does anyone know what report I should be sending to match this HID Descriptor template. Sorry for the messiness/length of this question.
Thanks in advance,
Richard
Full Readable HID Descriptor Output:
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x00, // Logical Minimum (0)
0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534)
0x95, 0x02, // Report Count (2)
0x75, 0x10, // Report Size (16)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534)
0x95, 0x02, // Report Count (2)
0x75, 0x10, // Report Size (16)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x32, // Usage (Z)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x95, 0x01, // Report Count (1)
0x75, 0x0A, // Report Size (10)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x35, // Usage (Rz)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x95, 0x01, // Report Count (1)
0x75, 0x0A, // Report Size (10)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x01, // Logical Minimum (1)
0x25, 0x08, // Logical Maximum (8)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x66, 0x14, 0x00, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x00, // Physical Maximum (0)
0x65, 0x00, // Unit (None)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0A, // Usage Maximum (0x0A)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0A, // Report Count (10)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x80, // Usage (Sys Control)
0x85, 0x02, // Report ID (2)
0xA1, 0x00, // Collection (Physical)
0x09, 0x85, // Usage (Sys Main Menu)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x01, // Report Count (1)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x07, // Report Size (7)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x0F, // Usage Page (PID Page)
0x09, 0x21, // Usage (0x21)
0x85, 0x03, // Report ID (3)
0xA1, 0x02, // Collection (Logical)
0x09, 0x97, // Usage (0x97)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x00, // Logical Maximum (0)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x70, // Usage (0x70)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x64, // Logical Maximum (100)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x50, // Usage (0x50)
0x66, 0x01, 0x10, // Unit (System: SI Linear, Time: Seconds)
0x55, 0x0E, // Unit Exponent (-2)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0xA7, // Usage (0xA7)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x65, 0x00, // Unit (None)
0x55, 0x00, // Unit Exponent (0)
0x09, 0x7C, // Usage (0x7C)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0x85, 0x04, // Report ID (4)
0x05, 0x06, // Usage Page (Generic Dev Ctrls)
0x09, 0x20, // Usage (Battery Strength)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
I know you've found the issue, but this may be of interest to others. I decoded the HID descriptor with hidrdd (which points out errors and suggests improvements). The result is as follows:
//--------------------------------------------------------------------------------
// Report descriptor data in hex (length 306 bytes)
//--------------------------------------------------------------------------------
// 05010905 A1018501 0901A100 09300931 150027FF FF000095 02751081 02C00901
// A1000933 09341500 27FFFF00 00950275 108102C0 05010932 150026FF 03950175
// 0A810215 00250075 06950181 03050109 35150026 FF039501 750A8102 15002500
// 75069501 81030501 09391501 25083500 463B0166 14007504 95018142 75049501
// 15002500 35004500 65008103 05091901 290A1500 25017501 950A8102 15002500
// 75069501 81030501 09808502 A1000985 15002501 95017501 81021500 25007507
// 95018103 C0050F09 218503A1 02099715 00250175 04950191 02150025 00750495
// 01910309 70150025 64750895 04910209 50660110 550E1500 26FF0075 08950191
// 0209A715 0026FF00 75089501 91026500 5500097C 150026FF 00750895 019102C0
// 85040506 09201500 26FF0075 08950181 02C0
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
09 05 (LOCAL) USAGE 0x00010005 Game Pad (Application Collection)
A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0x00010005: Page=Generic Desktop Page, Usage=Game Pad, Type=Application Collection)
85 01 (GLOBAL) REPORT_ID 0x01 (1)
09 01 (LOCAL) USAGE 0x00010001 Pointer (Physical Collection)
A1 00 (MAIN) COLLECTION 0x00 Physical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=Physical Collection)
09 30 (LOCAL) USAGE 0x00010030 X (Dynamic Value)
09 31 (LOCAL) USAGE 0x00010031 Y (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
27 FFFF0000 (GLOBAL) LOGICAL_MAXIMUM 0x0000FFFF (65535)
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields
75 10 (GLOBAL) REPORT_SIZE 0x10 (16) Number of bits per field
81 02 (MAIN) INPUT 0x00000002 (2 fields x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
09 01 (LOCAL) USAGE 0x00010001 Pointer (Physical Collection)
A1 00 (MAIN) COLLECTION 0x00 Physical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=Physical Collection)
09 33 (LOCAL) USAGE 0x00010033 Rx (Dynamic Value)
09 34 (LOCAL) USAGE 0x00010034 Ry (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
27 FFFF0000 (GLOBAL) LOGICAL_MAXIMUM 0x0000FFFF (65535) <-- Redundant: LOGICAL_MAXIMUM is already 65535
95 02 (GLOBAL) REPORT_COUNT 0x02 (2) Number of fields <-- Redundant: REPORT_COUNT is already 2
75 10 (GLOBAL) REPORT_SIZE 0x10 (16) Number of bits per field <-- Redundant: REPORT_SIZE is already 16
81 02 (MAIN) INPUT 0x00000002 (2 fields x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page <-- Redundant: USAGE_PAGE is already 0x0001
09 32 (LOCAL) USAGE 0x00010032 Z (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF03 (GLOBAL) LOGICAL_MAXIMUM 0x03FF (1023)
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
75 0A (GLOBAL) REPORT_SIZE 0x0A (10) Number of bits per field
81 02 (MAIN) INPUT 0x00000002 (1 field x 10 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 00 (GLOBAL) LOGICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 25 00 with 24
75 06 (GLOBAL) REPORT_SIZE 0x06 (6) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
81 03 (MAIN) INPUT 0x00000003 (1 field x 6 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page <-- Redundant: USAGE_PAGE is already 0x0001
09 35 (LOCAL) USAGE 0x00010035 Rz (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF03 (GLOBAL) LOGICAL_MAXIMUM 0x03FF (1023)
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
75 0A (GLOBAL) REPORT_SIZE 0x0A (10) Number of bits per field
81 02 (MAIN) INPUT 0x00000002 (1 field x 10 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 00 (GLOBAL) LOGICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 25 00 with 24
75 06 (GLOBAL) REPORT_SIZE 0x06 (6) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
81 03 (MAIN) INPUT 0x00000003 (1 field x 6 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page <-- Redundant: USAGE_PAGE is already 0x0001
09 39 (LOCAL) USAGE 0x00010039 Hat switch (Dynamic Value)
15 01 (GLOBAL) LOGICAL_MINIMUM 0x01 (1)
25 08 (GLOBAL) LOGICAL_MAXIMUM 0x08 (8)
35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 35 00 with 34
46 3B01 (GLOBAL) PHYSICAL_MAXIMUM 0x013B (315)
66 1400 (GLOBAL) UNIT 0x0014 Rotation in degrees [1° units] (4=System=English Rotation, 1=Rotation=Degrees) <-- Info: Consider replacing 66 1400 with 65 14
75 04 (GLOBAL) REPORT_SIZE 0x04 (4) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
81 42 (MAIN) INPUT 0x00000042 (1 field x 4 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 1=Null 0=NonVolatile 0=Bitmap
75 04 (GLOBAL) REPORT_SIZE 0x04 (4) Number of bits per field <-- Redundant: REPORT_SIZE is already 4
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
25 00 (GLOBAL) LOGICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 25 00 with 24
35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Redundant: PHYSICAL_MINIMUM is already 0 <-- Info: Consider replacing 35 00 with 34
45 00 (GLOBAL) PHYSICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 45 00 with 44
65 00 (GLOBAL) UNIT 0x00 No unit (0=None) <-- Info: Consider replacing 65 00 with 64
81 03 (MAIN) INPUT 0x00000003 (1 field x 4 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 09 (GLOBAL) USAGE_PAGE 0x0009 Button Page
19 01 (LOCAL) USAGE_MINIMUM 0x00090001 Button 1 Primary/trigger (Selector, On/Off Control, Momentary Control, or One Shot Control)
29 0A (LOCAL) USAGE_MAXIMUM 0x0009000A Button 10 (Selector, On/Off Control, Momentary Control, or One Shot Control)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 0A (GLOBAL) REPORT_COUNT 0x0A (10) Number of fields
81 02 (MAIN) INPUT 0x00000002 (10 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 00 (GLOBAL) LOGICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 25 00 with 24
75 06 (GLOBAL) REPORT_SIZE 0x06 (6) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
81 03 (MAIN) INPUT 0x00000003 (1 field x 6 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page
09 80 (LOCAL) USAGE 0x00010080 System Control (Application Collection)
85 02 (GLOBAL) REPORT_ID 0x02 (2)
A1 00 (MAIN) COLLECTION 0x00 Physical (Usage=0x00010080: Page=Generic Desktop Page, Usage=System Control, Type=Application Collection) <-- Warning: USAGE type should be CP (Physical Collection)
09 85 (LOCAL) USAGE 0x00010085 System Main Menu (One Shot Control)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
81 02 (MAIN) INPUT 0x00000002 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 00 (GLOBAL) LOGICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 25 00 with 24
75 07 (GLOBAL) REPORT_SIZE 0x07 (7) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
81 03 (MAIN) INPUT 0x00000003 (1 field x 7 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Physical
05 0F (GLOBAL) USAGE_PAGE 0x000F Physical Interface Device Page
09 21 (LOCAL) USAGE 0x000F0021 Set Effect Report (Logical Collection)
85 03 (GLOBAL) REPORT_ID 0x03 (3)
A1 02 (MAIN) COLLECTION 0x02 Logical (Usage=0x000F0021: Page=Physical Interface Device Page, Usage=Set Effect Report, Type=Logical Collection)
09 97 (LOCAL) USAGE 0x000F0097 DC Enable Actuators (Selector)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
75 04 (GLOBAL) REPORT_SIZE 0x04 (4) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
91 02 (MAIN) OUTPUT 0x00000002 (1 field x 4 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 00 (GLOBAL) LOGICAL_MAXIMUM 0x00 (0) <-- Info: Consider replacing 25 00 with 24
75 04 (GLOBAL) REPORT_SIZE 0x04 (4) Number of bits per field <-- Redundant: REPORT_SIZE is already 4
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
91 03 (MAIN) OUTPUT 0x00000003 (1 field x 4 bits) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 70 (LOCAL) USAGE 0x000F0070 Magnitude (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 64 (GLOBAL) LOGICAL_MAXIMUM 0x64 (100)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 04 (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields
91 02 (MAIN) OUTPUT 0x00000002 (4 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 50 (LOCAL) USAGE 0x000F0050 Duration (Dynamic Value)
66 0110 (GLOBAL) UNIT 0x1001 Time in seconds [1 s units] (1=System=SI Linear, 1=Time=Seconds)
55 0E (GLOBAL) UNIT_EXPONENT 0x0E (Unit Value x 10⁻²)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
91 02 (MAIN) OUTPUT 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 A7 (LOCAL) USAGE 0x000F00A7 Start Delay (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) <-- Redundant: LOGICAL_MAXIMUM is already 255
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
91 02 (MAIN) OUTPUT 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
65 00 (GLOBAL) UNIT 0x00 No unit (0=None) <-- Info: Consider replacing 65 00 with 64
55 00 (GLOBAL) UNIT_EXPONENT 0x00 (Unit Value x 10⁰) <-- Info: Consider replacing 55 00 with 54
09 7C (LOCAL) USAGE 0x000F007C Loop Count (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) <-- Redundant: LOGICAL_MAXIMUM is already 255
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
91 02 (MAIN) OUTPUT 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Logical
85 04 (GLOBAL) REPORT_ID 0x04 (4)
05 06 (GLOBAL) USAGE_PAGE 0x0006 Generic Device Controls Page
09 20 (LOCAL) USAGE 0x00060020 Battery Strength (Dynamic Value)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) <-- Redundant: LOGICAL_MAXIMUM is already 255
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
81 02 (MAIN) INPUT 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Generic Desktop Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: CA:GamePad CP:Pointer
uint16_t GD_GamePadPointerX; // Usage 0x00010030: X, Value = 0 to 65535
uint16_t GD_GamePadPointerY; // Usage 0x00010031: Y, Value = 0 to 65535
uint16_t GD_GamePadPointerRx; // Usage 0x00010033: Rx, Value = 0 to 65535
uint16_t GD_GamePadPointerRy; // Usage 0x00010034: Ry, Value = 0 to 65535
// Collection: CA:GamePad
uint16_t GD_GamePadZ : 10; // Usage 0x00010032: Z, Value = 0 to 1023
uint8_t : 6; // Pad
uint16_t GD_GamePadRz : 10; // Usage 0x00010035: Rz, Value = 0 to 1023
uint8_t : 6; // Pad
uint8_t GD_GamePadHatSwitch : 4; // Usage 0x00010039: Hat switch, Value = 1 to 8, Physical = (Value - 1) x 45 in degrees
uint8_t : 4; // Pad
uint8_t BTN_GamePadButton1 : 1; // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1
uint8_t BTN_GamePadButton2 : 1; // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1
uint8_t BTN_GamePadButton3 : 1; // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1
uint8_t BTN_GamePadButton4 : 1; // Usage 0x00090004: Button 4, Value = 0 to 1
uint8_t BTN_GamePadButton5 : 1; // Usage 0x00090005: Button 5, Value = 0 to 1
uint8_t BTN_GamePadButton6 : 1; // Usage 0x00090006: Button 6, Value = 0 to 1
uint8_t BTN_GamePadButton7 : 1; // Usage 0x00090007: Button 7, Value = 0 to 1
uint8_t BTN_GamePadButton8 : 1; // Usage 0x00090008: Button 8, Value = 0 to 1
uint8_t BTN_GamePadButton9 : 1; // Usage 0x00090009: Button 9, Value = 0 to 1
uint8_t BTN_GamePadButton10 : 1; // Usage 0x0009000A: Button 10, Value = 0 to 1
uint8_t : 6; // Pad
} inputReport01_t;
//--------------------------------------------------------------------------------
// Generic Desktop Page inputReport 02 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x02 (2)
// Collection: CA:GamePad CP:SystemControl
uint8_t GD_GamePadSystemControlSystemMainMenu : 1; // Usage 0x00010085: System Main Menu, Value = 0 to 1
uint8_t : 7; // Pad
} inputReport02_t;
//--------------------------------------------------------------------------------
// Generic Device Controls Page inputReport 04 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x04 (4)
// Collection: CA:GamePad
uint8_t GEN_GamePadBatteryStrength; // Usage 0x00060020: Battery Strength, Value = 0 to 255
} inputReport04_t;
//--------------------------------------------------------------------------------
// Physical Interface Device Page outputReport 03 (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x03 (3)
// Collection: CA:GamePad CL:SetEffectReport
uint8_t PID_GamePadSetEffectReportDcEnableActuators : 4; // Usage 0x000F0097: DC Enable Actuators, Value = 0 to 1
uint8_t : 4; // Pad
uint8_t PID_GamePadSetEffectReportMagnitude[4]; // Usage 0x000F0070: Magnitude, Value = 0 to 100
uint8_t PID_GamePadSetEffectReportDuration; // Usage 0x000F0050: Duration, Value = 0 to 255, Physical = Value in 10⁻² s units
uint8_t PID_GamePadSetEffectReportStartDelay; // Usage 0x000F00A7: Start Delay, Value = 0 to 255, Physical = Value in 10⁻² s units
uint8_t PID_GamePadSetEffectReportLoopCount; // Usage 0x000F007C: Loop Count, Value = 0 to 255
} outputReport03_t;
The report descriptor seems to be generally OK. I could optimise it down from 306 bytes to just 191 bytes - representing exactly the same data flows (see below).
As for the 0x70 usage, it looks to me like there are 4 actuators which can be enabled using the 4-bit DcEnableActuators usage (0x97). So I would guess that you should be sending:
0x03, 0x0F, 0x64, 0x64, 0x64, 0x64, 0xFF, 0x10, 0x05
in order to enable all 4 of them instead of:
0x03, 0xF0, 0x64, 0x64, 0x64, 0x64, 0xFF, 0x10, 0x05
Just for fun, here is an optimised version of the report descriptor that they could have used instead:
//--------------------------------------------------------------------------------
// Report descriptor data in hex (length 191 bytes)
//--------------------------------------------------------------------------------
// 05010905 A1018501 0901A100 09300931 09330934 1427FFFF 00009504 75108102
// C0093226 FF039501 750A8102 24750681 03093526 FF03750A 81022475 06810309
// 39150125 0834463B 01651475 04814214 24446481 03050919 01290A25 01750195
// 0A810224 75069501 81030501 09808502 A1000985 25017501 81022475 078103C0
// 050F0921 8503A102 09972501 75049102 24910309 70256475 08950491 02095066
// 0110550E 26FF0095 01910209 A7910264 54097C91 02C08504 05060920 8102C0
It turns out the controller had disabled the vibration motors since the battery was "low", and sending the report described in the question (with a 0xA2 at the start) worked as I intended it to when I had replaced the batteries. I'm still not sure if the HID Descriptor is actually syntactically valid, but the controller does what I want it to now at least!
Related
What's the difference between the Keyboard HID page and the Generic HID page with the Keyboard ID?
The HID usages specification defines a Generic Desktop Usage Page (0x01) which contains a Keyboard Usage ID (0x06). It also defines a Keyboard Usage Page (0x09) with Usage IDs corresponding to individual keyboard keys. The entry for the former just says to refer to the latter for details. Why does this distinction exist? Is there any practical difference between defining a device as DesktopGeneric/Keyboard vs. just Keyboard?
For background, each USB usage code is a 4-byte number comprising two parts: a 2-byte usage page, followed by a 2-byte usage id. The Generic Desktop page is 0x0001 and the Keyboard/Keypad usage page is 0x0007. A reasonably complete list of known usages can be found at https://github.com/abend0c1/hidrdd/blob/master/rd.conf The Keyboard usage id (0x0006) within the Generic Desktop page (i.e. usage 0x00010006) has the type "CA" and is meant to be used to identify a keyboard Application Collection. That identifies a collection of usages - usually from the Keyboard/Keypad page (0x0007) and LED Indicator page (0x0008) - that are to be associated with a Keyboard device. This way of identifying a collection of usages may be used by device drivers to direct USB HID reports to the appropriate device handler. Note that HID report descriptors are formed by specifying GLOBAL and/or LOCAL items first, and then specifying MAIN items that use those GLOBAL/LOCAL items (kind of like Reverse Polish Notation: the operands come first, followed by the operations). To illustrate, below is the example from "Appendix E.6 Report Descriptor (Keyboard)" of the HID Device Class Definition 1.11 that I have reformatted for clarity. The Generic Desktop Page is specified, then the Keyboard usage within that page, then an Application Collection MAIN item is begun for that usage (0x00010006). 05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page 09 06 (LOCAL) USAGE 0x00010006 Keyboard (CA=Application Collection) A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0x00010006: Page=Generic Desktop Page, Usage=Keyboard, Type=CA) 05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page 19 E0 (LOCAL) USAGE_MINIMUM 0x000700E0 Keyboard Left Control (DV=Dynamic Value) 29 E7 (LOCAL) USAGE_MAXIMUM 0x000700E7 Keyboard Right GUI (DV=Dynamic Value) 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) 75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field 95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields 81 02 (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields 75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field 81 01 (MAIN) INPUT 0x00000001 (1 field x 8 bits) 1=Constant 0=Array 0=Absolute 0=Ignored 0=Ignored 0=PrefState 0=NoNull 95 05 (GLOBAL) REPORT_COUNT 0x05 (5) Number of fields 75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field 05 08 (GLOBAL) USAGE_PAGE 0x0008 LED Indicator Page 19 01 (LOCAL) USAGE_MINIMUM 0x00080001 Num Lock (OOC=On/Off Control) 29 05 (LOCAL) USAGE_MAXIMUM 0x00080005 Kana (OOC=On/Off Control) 91 02 (MAIN) OUTPUT 0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields 75 03 (GLOBAL) REPORT_SIZE 0x03 (3) Number of bits per field 91 01 (MAIN) OUTPUT 0x00000001 (1 field x 3 bits) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields 75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 25 65 (GLOBAL) LOGICAL_MAXIMUM 0x65 (101) 05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page 19 00 (LOCAL) USAGE_MINIMUM 0x00070000 Keyboard No event indicated (Sel=Selector) <-- Redundant: USAGE_MINIMUM is already 0x0000 29 65 (LOCAL) USAGE_MAXIMUM 0x00070065 Keyboard Application (Sel=Selector) 81 00 (MAIN) INPUT 0x00000000 (6 fields x 8 bits) 0=Data 0=Array 0=Absolute 0=Ignored 0=Ignored 0=PrefState 0=NoNull C0 (MAIN) END_COLLECTION Application
How do I convert a byte array in NodeJS to binary output
I have a byte array I've created in NodeJS that displays like so: <Buffer 0a 0d 42 69 67 20 42 6f 62 20 53 6d 69 74 68 10 1e 1a 12 62 69 67 62 6f 62 40 65 78 61 6d 70 6c 65 2e 63 6f 6d>. I want to write some code in NodeJS that will display the byte array as binary, like so: 1010000011010100001001101001011001110010000001000010011011110110001000100000010100110110110101101001011101000110100000010000000111100001101000010010011000100110100101100111011000100110111101100010010000000110010101111000011000010110110101110000011011000110010100101110011000110110111101101101 I've been looking around for a package on NPM, but have come up short. Thanks in advance for any help.
If you want to get the binary version of your buffer's data, here is an example : const buffer = Buffer.from([0x0a, 0x0d, 0x42, 0x69, 0x67, 0x20, 0x42, 0x6f, 0x62, 0x20, 0x53, 0x6d, 0x69, 0x74, 0x68, 0x10, 0x1e, 0x1a, 0x12, 0x62, 0x69, 0x67, 0x62, 0x6f, 0x62, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d]); const paddedBin = BigInt('0x' + buffer.toString('hex')).toString(2).padStart(buffer.length * 8, '0') console.log(paddedBin); // output => 00001010000011010100001001101001011001110010000001000010011011110110001000100000010100110110110101101001011101000110100000010000000111100001101000010010011000100110100101100111011000100110111101100010010000000110010101111000011000010110110101110000011011000110010100101110011000110110111101101101
When reprogramming memory / Key for a SHE module, a correct M3 is not generated from M1||M2
I need to generate M1, M2, and M3 in order to reprogram a security key within a SHE module. I have verified that both my AES_128_ECB function, as well as my CMAC function are working properly against NIST test vectors. I am also able to generate M1 and M2 correctly without issue, however, when I input M1||M2 into my CMAC function, the result I am getting is not the result for M3 that I should be getting according to the SHE test vector for memory reprogramming in the SHE documentation. Here are all of the inputs and results for each of the steps of the M1,M2,M3 generating process: New Key: 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 Auth Key: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f M1: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 4 1 KDF result 1 K1: 7a cb d da b8 d3 ea 7b 97 9e 4c 6d 1a eb ac 8d KDF result 1 K2: 7a cb d da b8 d3 ea 7b 97 9e 4c 6d 1a eb ac 8d KDF result 2 K1: 6a 40 18 d6 87 a4 67 fc 15 14 25 af 38 9 7d 43 KDF result 2 K2: 55 72 74 af 5b fe d7 1f 26 15 ea 24 24 74 12 1f K1: 11 8a 46 44 7a 77 d 87 82 8a 69 c2 22 e2 d1 7e K2: 2e bb 2a 3d a6 2d bd 64 b1 8b a6 49 3e 9f be 22 input 1 M2: 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 output 1 M2: 2b 11 1e 2d 93 f4 86 56 6b cb ba 1d 7f 7a 97 97 output 1 xor input 2 M2: 24 1f 13 21 98 fe 8f 5e 6c cd bf 19 7c 78 96 97 output 2 M2: c9 46 43 b0 50 fc 5d 4d 7d e1 4c ff 68 22 3 c3 M2: 2b 11 1e 2d 93 f4 86 56 6b cb ba 1d 7f 7a 97 97 c9 46 43 b0 50 fc 5d 4d 7d e1 4c ff 68 22 3 c3 input M3: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 4 1 2b 11 1e 2d 93 f4 86 56 6b cb ba 1d 7f 7a 97 97 c9 46 43 b0 50 fc 5d 4d 7d e1 4c ff 68 22 3 c3 M3: c 12 41 48 ff d6 fa f7 e4 25 6a 84 53 b2 81 8d This is driving me crazy. The input data to the generation algorithm were taken directly from the SHE test vector. According to the algorithm all I should have to do to get M3 is to run a CMAC over M1||M2, but my result does not match what it should be. I can only assume I am missing some extra step that is needed for M3, beyond just running the CMAC over M1||M2. Does anybody here have any experience with SHE modules and generating the data to reprogram a key? Tried rearranging the order of M1||M2 with no luck byte KEY_UPDATE_ENC_C[16] = { 0x01, 0x01, 0x53, 0x48, 0x45, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0 }; byte KEY_UPDATE_MAC_C[16] = { 0x01, 0x02, 0x53, 0x48, 0x45, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0 }; byte keyAuth[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; byte keyNew[16] = { 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 } ; byte iniVec[16]; byte k1_o1[16]; byte k1[16]; byte k2_o1[16]; byte k2[16]; byte m1[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01 } byte m2_i1[16] = { 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte m2_o1[16]; byte m2_o2[16]; byte m2[32]; byte m3_i[48]; byte m3[16]; qword i; ... // Generate K1, K2 encrypt( KEY_LEN_128, iniVec, BLOCK_LEN_128, keyAuth, k2_o1 ); for( i = 0; i < BLOCK_LEN_128; i++ ) k1_o1[i] = k2_o1[i] ^= keyAuth[i]; encrypt( KEY_LEN_128, k1_o1, BLOCK_LEN_128, KEY_UPDATE_ENC_C, k1 ); encrypt( KEY_LEN_128, k2_o1, BLOCK_LEN_128, KEY_UPDATE_MAC_C, k2 ); for( i = 0; i < BLOCK_LEN_128; i++ ) { k1[i] ^= k1_o1[i] ^ KEY_UPDATE_ENC_C[i]; k2[i] ^= k2_o1[i] ^ KEY_UPDATE_MAC_C[i]; } // Generate M2 encrypt( KEY_LEN_128, k1, BLOCK_LEN_128, m2_i1, m2_o1 ); for( i = 0; i < BLOCK_LEN_128; i++ ) keyNew[i] ^= m2_o1[i]; encrypt( KEY_LEN_128, k1, BLOCK_LEN_128, keyNew, m2_o2 ); for( i = 0; i < 32; i++ ) { if( i < 16 ) m2[i] = m2_o1[i]; else m2[i] = m2_o2[i-16]; } // Generate M3 for( i = 0; i < 48; i++ ) { if( i < 16 ) m3_i[i] = m1[i]; else m3_i[i] = m2[i-16]; } LocalSecurityGenerateCMAC( k2, KEY_LEN_128, m3_i, 48, m3, BLOCK_LEN_128 ); M3 / CMAC result should be: b9 d7 45 e5 ac e7 d4 18 60 bc 63 c2 b9 f5 bb 46
HID (Human Interface Device) - send keys CMD+SPACE
I want to use HID to send the keyboard shortcut CMD+SPACE to the mac, which opens Spotlight. So I need the CMD to be a hold key, and the space to trigger the shortcut. How do I do this? I am using the LightBlue bean, which communicates via Bluetooth to the mac using HID protocol. An example that is working for me elsewhere is: BeanHid.sendKeys("/dnd "); //turn do not disturb off if it is on BeanHid.sendKeys("\r\n"); //return / newline The reference for the lightblue bean's HID class is here: https://punchthrough.com/files/bean/arduino-core-docs/1.8.0-beta1/class_bean_hid__.html#a40083ffe2f60453c9988419b083a26ad I'm guessing I need the holdKey, sendKey, and releaseKey methods. But what I need is whatever keycodes signify a cmd and space.
The Apple "Command" key, the Windows "Windows" key and the Linux "Super" key are all represented by the USB "GUI" key modifier bits. There are two of these: Left GUI and Right GUI. The space key is simply the USB "Spacebar" usage. So you would need to build and send, for example, the "Left GUI" modifier + "Spacebar" in your buffer. The exact contents of that buffer depends on the HID report descriptor you are using, but for the following fairly typical keyboard report descriptor: 05 01 (GLOBAL) USAGE_PAGE 0x0001 Generic Desktop Page 09 06 (LOCAL) USAGE 0x00010006 Keyboard (CA=Application Collection) A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x00010006: Page=Generic Desktop Page, Usage=Keyboard, Type=CA) 05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page 19 E0 (LOCAL) USAGE_MINIMUM 0x000700E0 Keyboard Left Control (DV=Dynamic Value) 29 E7 (LOCAL) USAGE_MAXIMUM 0x000700E7 Keyboard Right GUI (DV=Dynamic Value) 15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) 25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) 75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field 95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields 81 02 (MAIN) INPUT 0x00000002 (8 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields 75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field 81 01 (MAIN) INPUT 0x00000001 (1 field x 8 bits) 1=Constant 0=Array 0=Absolute 95 05 (GLOBAL) REPORT_COUNT 0x05 (5) Number of fields 75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field 05 08 (GLOBAL) USAGE_PAGE 0x0008 LED Indicator Page 19 01 (LOCAL) USAGE_MINIMUM 0x00080001 Num Lock (OOC=On/Off Control) 29 05 (LOCAL) USAGE_MAXIMUM 0x00080005 Kana (OOC=On/Off Control) 91 02 (MAIN) OUTPUT 0x00000002 (5 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields 75 03 (GLOBAL) REPORT_SIZE 0x03 (3) Number of bits per field 91 01 (MAIN) OUTPUT 0x00000001 (1 field x 3 bits) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields 75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field 25 65 (GLOBAL) LOGICAL_MAXIMUM 0x65 (101) 05 07 (GLOBAL) USAGE_PAGE 0x0007 Keyboard/Keypad Page 19 00 (LOCAL) USAGE_MINIMUM 0x00070000 Keyboard No event indicated (Sel=Selector) 29 65 (LOCAL) USAGE_MAXIMUM 0x00070065 Keyboard Application (Sel=Selector) 81 00 (MAIN) INPUT 0x00000000 (6 fields x 8 bits) 0=Data 0=Array 0=Absolute C0 (MAIN) END_COLLECTION Application ...the buffer representing LeftGUI modifier + Spacebar would be (in hex): 08 2C Alternatively, you could send RightGUI modifier + Spacebar: 80 2C After sending one of the above, you need to indicate that no keys are pressed by then sending a "no keys pressed" buffer: 00 00 It's worth noting that the 2C is an index (between LOGICAL_MINIMUM 0x00 to LOGICAL_MAXIMUM 0x65) into the array of USAGES from USAGE_MINIMUM (0x00) to USAGE_MAXIMUM (0x65) that you defined in your HID Report Descriptor and not the actual usage code within the keyboard usage page (which is 0x0007002C). If you only ever want to indicate that the spacebar is pressed you could code USAGE 0007002C, LOGICAL_MINIMUM 1, LOGICAL_MAXIMUM 1 in your HID Report Descriptor and then send: 80 01 ...to indiate that the spacebar (and GUI modifier) are currently pressed, followed by: 00 00 ...to indicate that no keys are currently pressed.
CC2540 USB - make discoverable: Not ready to perform task
I am using the TI CC2540 USB dongle in peripheral mode and want to enable advertising, using BTool, but the device is answering: Not Ready To Perform Task I know that it's possible to set initial advertising enable in the application code, but I want to set advertising manually, can someone help out? Here is the log of BTool: [1] : <Tx> - 04:52:52.802 -Type : 0x01 (Command) -Opcode : 0xFE00 (GAP_DeviceInit) -Data Length : 0x26 (38) byte(s) ProfileRole : 0x04 (Peripheral) MaxScanRsps : 0x05 (5) IRK : 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 CSRK : 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 SignCounter : 0x00000001 (1) [2] : <Rx> - 04:52:52.878 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x00 (Success) OpCode : 0xFE00 (GAP_DeviceInit) DataLength : 0x00 (0) [3] : <Rx> - 04:52:52.950 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x2C (44) bytes(s) Event : 0x0600 (GAP_DeviceInitDone) Status : 0x00 (Success) DevAddr : C0:FF:EE:C0:FF:EE DataPktLen : 0x001B (27) NumDataPkts : 0x04 (4) IRK : 67:76:7D:A8:78:A1:A8:61:71:BD:58:24:92:39:0E:EC CSRK : 4E:EA:B7:B5:14:34:66:8C:2D:6B:29:9D:C9:1E:4F:16 [4] : <Tx> - 04:53:00.375 -Type : 0x01 (Command) -Opcode : 0xFE06 (GAP_MakeDiscoverable) -Data Length : 0x0F (15) byte(s) EventType : 0x00 (Connectable Undirect Advertisement) InitAddrType : 0x00 (Public) InitAddrs : 00:00:00:00:00:00 ChannelMap : 0x07 (Channel 37 Channel 38 Channel 39) FilterPolicy : 0x00 (Allow Scan Requests From Any, Allow Connect Request From Any.) [5] : <Rx> - 04:53:00.455 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x10 (Not Ready To Perform Task) OpCode : 0xFE06 (GAP_MakeDiscoverable) DataLength : 0x00 (0)
With this sequence is detectable. [12] : <Tx> - 08:30:57.212 -Type : 0x01 (Command) -Opcode : 0xFE00 (GAP_DeviceInit) -Data Length : 0x26 (38) byte(s) ProfileRole : 0x04 (Peripheral) MaxScanRsps : 0x05 (5) IRK : 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 CSRK : 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 SignCounter : 0x00000001 (1) Dump(Tx): 01 00 FE 26 04 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 [13] : <Rx> - 08:30:57.291 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x00 (Success) OpCode : 0xFE00 (GAP_DeviceInit) DataLength : 0x00 (0) Dump(Rx): 04 FF 06 7F 06 00 00 FE 00 [14] : <Rx> - 08:30:57.356 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x2C (44) bytes(s) Event : 0x0600 (GAP_DeviceInitDone) Status : 0x00 (Success) DevAddr : 00:18:30:EA:9C:1B DataPktLen : 0x001B (27) NumDataPkts : 0x04 (4) IRK : E2:7D:76:4B:9B:24:8D:EA:F8:A6:E3:82:16:C8:C5:0C CSRK : EE:68:E6:8E:F6:48:43:04:C4:F0:5C:D3:D1:39:A9:9F Dump(Rx): 04 FF 2C 00 06 00 1B 9C EA 30 18 00 1B 00 04 E2 7D 76 4B 9B 24 8D EA F8 A6 E3 82 16 C8 C5 0C EE 68 E6 8E F6 48 43 04 C4 F0 5C D3 D1 39 A9 9F [15] : <Tx> - 08:31:04.155 -Type : 0x01 (Command) -Opcode : 0xFE07 (GAP_UpdateAdvertisingData) -Data Length : 0x05 (5) byte(s) AdType : 0x01 (Advertisement data) DataLength : 0x03 (3) AdvertData : 02:01:06 Dump(Tx): 01 07 FE 05 01 03 02 01 06 [16] : <Rx> - 08:31:04.231 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x00 (Success) OpCode : 0xFE07 (GAP_UpdateAdvertisingData) DataLength : 0x00 (0) Dump(Rx): 04 FF 06 7F 06 00 07 FE 00 [17] : <Rx> - 08:31:04.296 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x04 (4) bytes(s) Event : 0x0602 (GAP_AdvertDataUpdate) Status : 0x00 (Success) AdType : 0x01 (Advertisement data) Dump(Rx): 04 FF 04 02 06 00 01 [18] : <Tx> - 08:31:06.786 -Type : 0x01 (Command) -Opcode : 0xFE06 (GAP_MakeDiscoverable) -Data Length : 0x0F (15) byte(s) EventType : 0x00 (Connectable Undirect Advertisement) InitAddrType : 0x00 (Public) InitAddrs : 00:00:00:00:00:00 ChannelMap : 0x07 (Channel 37 Channel 38 Channel 39) FilterPolicy : 0x00 (Allow Scan Requests From Any, Allow Connect Request From Any.) Dump(Tx): 01 06 FE 0F 00 00 00 00 00 00 00 00 07 00 00 00 00 00 00 [19] : <Rx> - 08:31:06.858 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x00 (Success) OpCode : 0xFE06 (GAP_MakeDiscoverable) DataLength : 0x00 (0) Dump(Rx): 04 FF 06 7F 06 00 06 FE 00 [20] : <Rx> - 08:31:06.923 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x05 (5) bytes(s) Event : 0x0603 (GAP_MakeDiscoverable) Status : 0x00 (Success) Dump(Rx): 04 FF 05 03 06 00 E8 01
using prebuilt HostTestRelease project on dongle and setting it to peripheral mode, I got after several trials the following success code: [73] : - 02:13:30.416 -Type : 0x01 (Command) -Opcode : 0xFE07 (GAP_UpdateAdvertisingData) -Data Length : 0x05 (5) byte(s) AdType : 0x01 (Advertisement data) DataLength : 0x03 (3) AdvertData : 02:01:06 Dump(Tx): 01 07 FE 05 01 03 02 01 06 [74] : - 02:13:30.493 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x00 (Success) OpCode : 0xFE07 (GAP_UpdateAdvertisingData) DataLength : 0x00 (0) Dump(Rx): 04 FF 06 7F 06 00 07 FE 00 [75] : - 02:13:30.566 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x04 (4) bytes(s) Event : 0x0602 (GAP_AdvertDataUpdate) Status : 0x00 (Success) AdType : 0x01 (Advertisement data) Dump(Rx): 04 FF 04 02 06 00 01 [76] : - 02:14:04.382 -Type : 0x01 (Command) -Opcode : 0xFE06 (GAP_MakeDiscoverable) -Data Length : 0x0F (15) byte(s) EventType : 0x04 (Scan Response) InitAddrType : 0x00 (Public) InitAddrs : 00:00:00:00:00:00 ChannelMap : 0x07 (Channel 37 Channel 38 Channel 39) FilterPolicy : 0x00 (Allow Scan Requests From Any, Allow Connect Request From Any.) Dump(Tx): 01 06 FE 0F 04 00 00 00 00 00 00 00 07 00 00 00 00 00 00 [77] : - 02:14:04.456 -Type : 0x04 (Event) -EventCode : 0xFF (HCI_LE_ExtEvent) -Data Length : 0x06 (6) bytes(s) Event : 0x067F (GAP_HCI_ExtentionCommandStatus) Status : 0x00 (Success) OpCode : 0xFE06 (GAP_MakeDiscoverable) DataLength : 0x00 (0) Dump(Rx): 04 FF 06 7F 06 00 06 FE 00 Hope it'll be useful!