Беспроводной контроллер XBox One S Возможно, неверный HID дескриптор
Я пытался подключить свой микроконтроллер ESP-32 к контроллеру XBox One S Wireless через классический Bluetooth, используя этот BTStack, реализованный Bluekitchen. Мне удалось соединить два устройства (с ESP-32 в качестве хоста) и я могу прочитать все значения с контроллера на ESP-32. Я сейчас пытаюсь выяснить, как отправить действительные отчеты на контроллер. Дескриптор, сообщаемый контроллером при подключении:
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
Когда я запускаю этот дамп через этот переводчик, я получаю читаемый вывод, который включен в конец вопроса, так как он довольно длинный. Здесь указан только выходной формат отчета дескриптора HID:
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
Мое понимание стандарта HID указывает на то, что эта часть дескриптора недопустима, поскольку Usage (0x70)
сопровождается Report Count (4)
анализатор btstack, который я использую для отладки, почему это не работает, должен попытаться сопоставить 4 байта с одним использованием и, насколько я знаю, не может этого сделать. В настоящее время отчет, который я пытаюсь отправить контроллеру (и парсеру во время отладки) 0x03, 0xF0, 0x64, 0x64, 0x64, 0x64, 0xFF, 0x10, 0x05
, где 0x03
указывает идентификатор отчета, а следующие значения указывают параметры, которые я отправляю для управления грохотом двигателей. 4 0x64
значения - это 4 байта, которые должны отображаться на 4 использования, однако соответствуют только 1 использованию 0x70
согласно дескриптору HID. На данный момент парсер останавливается после нахождения первого 0x64
и утверждает, что будет закончено.
Я ошибаюсь, считая этот HID дескриптор недействительным? Если я, кто-нибудь знает, какой отчет я должен отправить, чтобы соответствовать этому шаблону дескриптора HID. Извините за беспорядок / длительность этого вопроса.
Заранее спасибо Ричард
Полный читаемый вывод дескриптора HID:
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
2 ответа
Я знаю, что вы нашли проблему, но это может заинтересовать других. Я расшифровал дескриптор HID с помощью hidrdd (который указывает на ошибки и предлагает улучшения). Результат выглядит следующим образом:
//--------------------------------------------------------------------------------
// 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;
Дескриптор отчета, как правило, в порядке. Я мог бы оптимизировать его с 306 байтов до всего лишь 191 байта - представляя точно такие же потоки данных (см. Ниже).
Что касается использования 0x70, мне кажется, что есть 4 исполнительных механизма, которые можно включить с помощью 4-битного использования DcEnableActuators (0x97). Поэтому я думаю, что вы должны отправить:
0x03, 0x0F, 0x64, 0x64, 0x64, 0x64, 0xFF, 0x10, 0x05
чтобы включить все 4 из них вместо:
0x03, 0xF0, 0x64, 0x64, 0x64, 0x64, 0xFF, 0x10, 0x05
Просто для удовольствия, вот оптимизированная версия дескриптора отчета, которую они могли бы использовать вместо:
//--------------------------------------------------------------------------------
// 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
Оказывается, контроллер отключил вибрационные двигатели, поскольку батарея разряжена, и отправка отчета, описанного в вопросе (с 0xA2 в начале), работала так, как я и предполагал, когда заменил батареи. Я до сих пор не уверен, что дескриптор HID действительно синтаксически действителен, но контроллер делает то, что я хочу, по крайней мере сейчас!