xref: /btstack/test/hid_parser/hid_parser_test.cpp (revision caeaa206eb51459f9342b4042b1af2ec395bf0ac)
1 
2 // *****************************************************************************
3 //
4 // HID Parser Test
5 //
6 // *****************************************************************************
7 
8 
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "CppUTest/TestHarness.h"
15 #include "CppUTest/CommandLineTestRunner.h"
16 
17 #include "btstack_hid_parser.h"
18 #include "hci_dump_posix_fs.h"
19 
20 const uint8_t mouse_descriptor_without_report_id[] = {
21     0x05, 0x01, /*  Usage Page (Desktop),               */
22     0x09, 0x02, /*  Usage (Mouse),                      */
23     0xA1, 0x01, /*  Collection (Application),           */
24     0x09, 0x01, /*      Usage (Pointer),                */
25     0xA0,       /*      Collection (Physical),          */
26     0x05, 0x09, /*          Usage Page (Button),        */
27     0x19, 0x01, /*          Usage Minimum (01h),        */
28     0x29, 0x03, /*          Usage Maximum (03h),        */
29     0x14,       /*          Logical Minimum (0),        */
30     0x25, 0x01, /*          Logical Maximum (1),        */
31     0x75, 0x01, /*          Report Size (1),            */
32     0x95, 0x03, /*          Report Count (3),           */
33     0x81, 0x02, /*          Input (Variable),           */
34     0x75, 0x05, /*          Report Size (5),            */
35     0x95, 0x01, /*          Report Count (1),           */
36     0x81, 0x01, /*          Input (Constant),           */
37     0x05, 0x01, /*          Usage Page (Desktop),       */
38     0x09, 0x30, /*          Usage (X),                  */
39     0x09, 0x31, /*          Usage (Y),                  */
40     0x15, 0x81, /*          Logical Minimum (-127),     */
41     0x25, 0x7F, /*          Logical Maximum (127),      */
42     0x75, 0x08, /*          Report Size (8),            */
43     0x95, 0x02, /*          Report Count (2),           */
44     0x81, 0x06, /*          Input (Variable, Relative), */
45     0xC0,       /*      End Collection,                 */
46     0xC0        /*  End Collection                      */
47 };
48 
49 const uint8_t mouse_descriptor_with_report_id[] = {
50     0x05, 0x01, /*  Usage Page (Desktop),               */
51     0x09, 0x02, /*  Usage (Mouse),                      */
52     0xA1, 0x01, /*  Collection (Application),           */
53 
54     0x85,  0x01,                    // Report ID 1
55 
56     0x09, 0x01, /*      Usage (Pointer),                */
57     0xA0,       /*      Collection (Physical),          */
58     0x05, 0x09, /*          Usage Page (Button),        */
59     0x19, 0x01, /*          Usage Minimum (01h),        */
60     0x29, 0x03, /*          Usage Maximum (03h),        */
61     0x14,       /*          Logical Minimum (0),        */
62     0x25, 0x01, /*          Logical Maximum (1),        */
63     0x75, 0x01, /*          Report Size (1),            */
64     0x95, 0x03, /*          Report Count (3),           */
65     0x81, 0x02, /*          Input (Variable),           */
66     0x75, 0x05, /*          Report Size (5),            */
67     0x95, 0x01, /*          Report Count (1),           */
68     0x81, 0x01, /*          Input (Constant),           */
69     0x05, 0x01, /*          Usage Page (Desktop),       */
70     0x09, 0x30, /*          Usage (X),                  */
71     0x09, 0x31, /*          Usage (Y),                  */
72     0x15, 0x81, /*          Logical Minimum (-127),     */
73     0x25, 0x7F, /*          Logical Maximum (127),      */
74     0x75, 0x08, /*          Report Size (8),            */
75     0x95, 0x02, /*          Report Count (2),           */
76     0x81, 0x06, /*          Input (Variable, Relative), */
77     0xC0,       /*      End Collection,                 */
78     0xC0        /*  End Collection                      */
79 };
80 
81 // from USB HID Specification 1.1, Appendix B.1
82 const uint8_t hid_descriptor_keyboard_boot_mode[] = {
83 
84     0x05, 0x01,                    // Usage Page (Generic Desktop)
85     0x09, 0x06,                    // Usage (Keyboard)
86     0xa1, 0x01,                    // Collection (Application)
87 
88     // Modifier byte
89 
90     0x75, 0x01,                    //   Report Size (1)
91     0x95, 0x08,                    //   Report Count (8)
92     0x05, 0x07,                    //   Usage Page (Key codes)
93     0x19, 0xe0,                    //   Usage Minimum (Keyboard LeftControl)
94     0x29, 0xe7,                    //   Usage Maxium (Keyboard Right GUI)
95     0x15, 0x00,                    //   Logical Minimum (0)
96     0x25, 0x01,                    //   Logical Maximum (1)
97     0x81, 0x02,                    //   Input (Data, Variable, Absolute)
98 
99     // Reserved byte
100 
101     0x75, 0x01,                    //   Report Size (1)
102     0x95, 0x08,                    //   Report Count (8)
103     0x81, 0x03,                    //   Input (Constant, Variable, Absolute)
104 
105     // LED report + padding
106 
107     0x95, 0x05,                    //   Report Count (5)
108     0x75, 0x01,                    //   Report Size (1)
109     0x05, 0x08,                    //   Usage Page (LEDs)
110     0x19, 0x01,                    //   Usage Minimum (Num Lock)
111     0x29, 0x05,                    //   Usage Maxium (Kana)
112     0x91, 0x02,                    //   Output (Data, Variable, Absolute)
113 
114     0x95, 0x01,                    //   Report Count (1)
115     0x75, 0x03,                    //   Report Size (3)
116     0x91, 0x03,                    //   Output (Constant, Variable, Absolute)
117 
118     // Keycodes
119 
120     0x95, 0x06,                    //   Report Count (6)
121     0x75, 0x08,                    //   Report Size (8)
122     0x15, 0x00,                    //   Logical Minimum (0)
123     0x25, 0xff,                    //   Logical Maximum (1)
124     0x05, 0x07,                    //   Usage Page (Key codes)
125     0x19, 0x00,                    //   Usage Minimum (Reserved (no event indicated))
126     0x29, 0xff,                    //   Usage Maxium (Reserved)
127     0x81, 0x00,                    //   Input (Data, Array)
128 
129     0xc0,                          // End collection
130 };
131 
132 const uint8_t combo_descriptor_with_report_ids[] = {
133 
134     0x05, 0x01, /*  Usage Page (Desktop),               */
135     0x09, 0x02, /*  Usage (Mouse),                      */
136     0xA1, 0x01, /*  Collection (Application),           */
137 
138     0x85, 0x01, // Report ID 1
139 
140     0x09, 0x01, /*      Usage (Pointer),                */
141     0xA0,       /*      Collection (Physical),          */
142     0x05, 0x09, /*          Usage Page (Button),        */
143     0x19, 0x01, /*          Usage Minimum (01h),        */
144     0x29, 0x03, /*          Usage Maximum (03h),        */
145     0x14,       /*          Logical Minimum (0),        */
146     0x25, 0x01, /*          Logical Maximum (1),        */
147     0x75, 0x01, /*          Report Size (1),            */
148     0x95, 0x03, /*          Report Count (3),           */
149     0x81, 0x02, /*          Input (Variable),           */
150     0x75, 0x05, /*          Report Size (5),            */
151     0x95, 0x01, /*          Report Count (1),           */
152     0x81, 0x01, /*          Input (Constant),           */
153     0x05, 0x01, /*          Usage Page (Desktop),       */
154     0x09, 0x30, /*          Usage (X),                  */
155     0x09, 0x31, /*          Usage (Y),                  */
156     0x15, 0x81, /*          Logical Minimum (-127),     */
157     0x25, 0x7F, /*          Logical Maximum (127),      */
158     0x75, 0x08, /*          Report Size (8),            */
159     0x95, 0x02, /*          Report Count (2),           */
160     0x81, 0x06, /*          Input (Variable, Relative), */
161     0xC0,       /*      End Collection,                 */
162     0xC0,       /*  End Collection                      */
163 
164     0xa1, 0x01,                    // Collection (Application)
165 
166     0x85, 0x02, // Report ID 2
167 
168     // Modifier byte
169 
170     0x75, 0x01,                    //   Report Size (1)
171     0x95, 0x08,                    //   Report Count (8)
172     0x05, 0x07,                    //   Usage Page (Key codes)
173     0x19, 0xe0,                    //   Usage Minimum (Keyboard LeftControl)
174     0x29, 0xe7,                    //   Usage Maxium (Keyboard Right GUI)
175     0x15, 0x00,                    //   Logical Minimum (0)
176     0x25, 0x01,                    //   Logical Maximum (1)
177     0x81, 0x02,                    //   Input (Data, Variable, Absolute)
178 
179     // Reserved byte
180 
181     0x75, 0x01,                    //   Report Size (1)
182     0x95, 0x08,                    //   Report Count (8)
183     0x81, 0x03,                    //   Input (Constant, Variable, Absolute)
184 
185     // LED report + padding
186 
187     0x95, 0x05,                    //   Report Count (5)
188     0x75, 0x01,                    //   Report Size (1)
189     0x05, 0x08,                    //   Usage Page (LEDs)
190     0x19, 0x01,                    //   Usage Minimum (Num Lock)
191     0x29, 0x05,                    //   Usage Maxium (Kana)
192     0x91, 0x02,                    //   Output (Data, Variable, Absolute)
193 
194     0x95, 0x01,                    //   Report Count (1)
195     0x75, 0x03,                    //   Report Size (3)
196     0x91, 0x03,                    //   Output (Constant, Variable, Absolute)
197 
198     // Keycodes
199 
200     0x95, 0x06,                    //   Report Count (6)
201     0x75, 0x08,                    //   Report Size (8)
202     0x15, 0x00,                    //   Logical Minimum (0)
203     0x25, 0xff,                    //   Logical Maximum (1)
204     0x05, 0x07,                    //   Usage Page (Key codes)
205     0x19, 0x00,                    //   Usage Minimum (Reserved (no event indicated))
206     0x29, 0xff,                    //   Usage Maxium (Reserved)
207     0x81, 0x00,                    //   Input (Data, Array)
208 
209     0xc0,                          // En
210 
211 };
212 
213 // https://tank-mouse.com/
214 const uint8_t tank_mouse_descriptor[] = {
215     0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
216     0x09, 0x02,        // Usage (Mouse)
217     0xA1, 0x01,        // Collection (Application)
218     0x85, 0x03,        //   Report ID (3)
219     0x09, 0x01,        //   Usage (Pointer)
220     0xA1, 0x00,        //   Collection (Physical)
221     0x05, 0x09,        //     Usage Page (Button)
222     0x19, 0x01,        //     Usage Minimum (0x01)
223     0x29, 0x03,        //     Usage Maximum (0x03)
224     0x15, 0x00,        //     Logical Minimum (0)
225     0x25, 0x01,        //     Logical Maximum (1)
226     0x75, 0x01,        //     Report Size (1)
227     0x95, 0x05,        //     Report Count (5)
228     0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
229     0x75, 0x03,        //     Report Size (3)
230     0x95, 0x01,        //     Report Count (1)
231     0x81, 0x01,        //     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
232     0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
233     0x09, 0x30,        //     Usage (X)
234     0x09, 0x31,        //     Usage (Y)
235     0x16, 0x01, 0x80,  //     Logical Minimum (-32767)
236     0x26, 0xFF, 0x7F,  //     Logical Maximum (32767)
237     0x75, 0x10,        //     Report Size (16)
238     0x95, 0x02,        //     Report Count (2)
239     0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
240     0x09, 0x38,        //     Usage (Wheel)
241     0x15, 0x81,        //     Logical Minimum (-127)
242     0x25, 0x7F,        //     Logical Maximum (127)
243     0x75, 0x08,        //     Report Size (8)
244     0x95, 0x01,        //     Report Count (1)
245     0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
246     0xC0,              //   End Collection
247     0xC0,              // End Collection
248     0x06, 0x01, 0xFF,  // Usage Page (Vendor Defined 0xFF01)
249     0x09, 0x01,        // Usage (0x01)
250     0xA1, 0x01,        // Collection (Application)
251     0x85, 0x05,        //   Report ID (5)
252     0x09, 0x05,        //   Usage (0x05)
253     0x15, 0x00,        //   Logical Minimum (0)
254     0x26, 0xFF, 0x00,  //   Logical Maximum (255)
255     0x75, 0x08,        //   Report Size (8)
256     0x95, 0x04,        //   Report Count (4)
257     0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
258     0xC0,              // End Collection
259     // 89 bytes
260 };
261 
262 const uint8_t mouse_report_without_id_positive_xy[]    = {       0x03, 0x02, 0x03 };
263 const uint8_t mouse_report_without_id_negative_xy[]    = {       0x03, 0xFE, 0xFD };
264 const uint8_t mouse_report_with_id_1[]    = { 0x01, 0x03, 0x02, 0x03 };
265 
266 const uint8_t keyboard_report1[] = { 0x01, 0x00, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00 };
267 
268 const uint8_t combo_report1[]    = { 0x01, 0x03, 0x02, 0x03 };
269 const uint8_t combo_report2[]    = { 0x02, 0x01, 0x00,  0x04, 0x05, 0x06, 0x00, 0x00, 0x00 };
270 
271 const uint8_t tank_mouse_report[] = { 0x03, 0x03, 0xFD, 0xFF, 0xF6, 0xFF, 0x00};
272 
273 
274 
275 static void expect_field(btstack_hid_parser_t * parser, uint16_t expected_usage_page, uint16_t expected_usage, int32_t expected_value){
276     // printf("expected - usage page %02x, usage %04x, value %02x (bit pos %u)\n", expected_usage_page, expected_usage, expected_value, parser->report_pos_in_bit);
277     CHECK_EQUAL(1, btstack_hid_parser_has_more(parser));
278     uint16_t usage_page;
279     uint16_t usage;
280     int32_t value;
281     btstack_hid_parser_get_field(parser, &usage_page, &usage, &value);
282     CHECK_EQUAL(expected_usage_page, usage_page);
283     CHECK_EQUAL(expected_usage, usage);
284     CHECK_EQUAL(expected_value, value);
285 }
286 
287 // test
288 TEST_GROUP(HID){
289 	void setup(void){
290     }
291 };
292 
293 TEST(HID, MouseWithoutReportID){
294     static btstack_hid_parser_t hid_parser;
295     btstack_hid_parser_init(&hid_parser, mouse_descriptor_without_report_id, sizeof(mouse_descriptor_without_report_id), HID_REPORT_TYPE_INPUT, mouse_report_without_id_positive_xy, sizeof(mouse_report_without_id_positive_xy));
296     expect_field(&hid_parser, 9, 1, 1);
297     expect_field(&hid_parser, 9, 2, 1);
298     expect_field(&hid_parser, 9, 3, 0);
299     expect_field(&hid_parser, 1, 0x30, 2);
300     expect_field(&hid_parser, 1, 0x31, 3);
301     CHECK_EQUAL(24, hid_parser.report_pos_in_bit);
302     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
303 }
304 
305 TEST(HID, MouseWithoutReportIDSigned){
306     static btstack_hid_parser_t hid_parser;
307     btstack_hid_parser_init(&hid_parser, mouse_descriptor_without_report_id, sizeof(mouse_descriptor_without_report_id), HID_REPORT_TYPE_INPUT, mouse_report_without_id_negative_xy, sizeof(mouse_report_without_id_negative_xy));
308     expect_field(&hid_parser, 9, 1, 1);
309     expect_field(&hid_parser, 9, 2, 1);
310     expect_field(&hid_parser, 9, 3, 0);
311     expect_field(&hid_parser, 1, 0x30, -2);
312     expect_field(&hid_parser, 1, 0x31, -3);
313     CHECK_EQUAL(24, hid_parser.report_pos_in_bit);
314     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
315 }
316 
317 TEST(HID, MouseWithReportID){
318     static btstack_hid_parser_t hid_parser;
319     CHECK_EQUAL(3, btstack_hid_get_report_size_for_id(1, HID_REPORT_TYPE_INPUT, sizeof(mouse_descriptor_with_report_id), mouse_descriptor_with_report_id));
320     btstack_hid_parser_init(&hid_parser, mouse_descriptor_with_report_id, sizeof(mouse_descriptor_with_report_id), HID_REPORT_TYPE_INPUT, mouse_report_with_id_1, sizeof(mouse_report_with_id_1));
321     expect_field(&hid_parser, 9, 1, 1);
322     expect_field(&hid_parser, 9, 2, 1);
323     expect_field(&hid_parser, 9, 3, 0);
324     expect_field(&hid_parser, 1, 0x30, 2);
325     expect_field(&hid_parser, 1, 0x31, 3);
326     CHECK_EQUAL(32, hid_parser.report_pos_in_bit);
327     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
328 }
329 
330 TEST(HID, BootKeyboard){
331     static btstack_hid_parser_t hid_parser;
332     btstack_hid_parser_init(&hid_parser, hid_descriptor_keyboard_boot_mode, sizeof(hid_descriptor_keyboard_boot_mode), HID_REPORT_TYPE_INPUT, keyboard_report1, sizeof(keyboard_report1));
333     expect_field(&hid_parser, 7, 0xe0, 1);
334     expect_field(&hid_parser, 7, 0xe1, 0);
335     expect_field(&hid_parser, 7, 0xe2, 0);
336     expect_field(&hid_parser, 7, 0xe3, 0);
337     expect_field(&hid_parser, 7, 0xe4, 0);
338     expect_field(&hid_parser, 7, 0xe5, 0);
339     expect_field(&hid_parser, 7, 0xe6, 0);
340     expect_field(&hid_parser, 7, 0xe7, 0);
341     expect_field(&hid_parser, 7, 0x04, 1);
342     expect_field(&hid_parser, 7, 0x05, 1);
343     expect_field(&hid_parser, 7, 0x06, 1);
344     expect_field(&hid_parser, 7, 0x00, 1);
345     expect_field(&hid_parser, 7, 0x00, 1);
346     expect_field(&hid_parser, 7, 0x00, 1);
347     CHECK_EQUAL(64, hid_parser.report_pos_in_bit);
348     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
349 }
350 
351 TEST(HID, Combo1){
352     static btstack_hid_parser_t hid_parser;
353     btstack_hid_parser_init(&hid_parser, combo_descriptor_with_report_ids, sizeof(combo_descriptor_with_report_ids), HID_REPORT_TYPE_INPUT, combo_report1, sizeof(combo_report1));
354     expect_field(&hid_parser, 9, 1, 1);
355     expect_field(&hid_parser, 9, 2, 1);
356     expect_field(&hid_parser, 9, 3, 0);
357     expect_field(&hid_parser, 1, 0x30, 2);
358     expect_field(&hid_parser, 1, 0x31, 3);
359     CHECK_EQUAL(32, hid_parser.report_pos_in_bit);
360     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
361 }
362 
363 TEST(HID, Combo2){
364     static btstack_hid_parser_t hid_parser;
365     btstack_hid_parser_init(&hid_parser, combo_descriptor_with_report_ids, sizeof(combo_descriptor_with_report_ids), HID_REPORT_TYPE_INPUT, combo_report2, sizeof(combo_report2));
366     expect_field(&hid_parser, 7, 0xe0, 1);
367     expect_field(&hid_parser, 7, 0xe1, 0);
368     expect_field(&hid_parser, 7, 0xe2, 0);
369     expect_field(&hid_parser, 7, 0xe3, 0);
370     expect_field(&hid_parser, 7, 0xe4, 0);
371     expect_field(&hid_parser, 7, 0xe5, 0);
372     expect_field(&hid_parser, 7, 0xe6, 0);
373     expect_field(&hid_parser, 7, 0xe7, 0);
374     expect_field(&hid_parser, 7, 0x04, 1);
375     expect_field(&hid_parser, 7, 0x05, 1);
376     expect_field(&hid_parser, 7, 0x06, 1);
377     expect_field(&hid_parser, 7, 0x00, 1);
378     expect_field(&hid_parser, 7, 0x00, 1);
379     expect_field(&hid_parser, 7, 0x00, 1);
380     CHECK_EQUAL(72, hid_parser.report_pos_in_bit);
381     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
382 }
383 
384 TEST(HID, TankMouse){
385     static btstack_hid_parser_t hid_parser;
386     CHECK_EQUAL(6, btstack_hid_get_report_size_for_id(3, HID_REPORT_TYPE_INPUT, sizeof(tank_mouse_descriptor), tank_mouse_descriptor));
387     btstack_hid_parser_init(&hid_parser, tank_mouse_descriptor, sizeof(tank_mouse_descriptor), HID_REPORT_TYPE_INPUT, tank_mouse_report, sizeof(tank_mouse_report));
388     expect_field(&hid_parser, 9, 1, 1);
389     expect_field(&hid_parser, 9, 2, 1);
390     expect_field(&hid_parser, 9, 3, 0);
391     // no usages for 4th and 5th report as usage min..max only allows for 3 button
392     expect_field(&hid_parser, 1, 0x30, -3);
393     expect_field(&hid_parser, 1, 0x31, -10);
394     expect_field(&hid_parser, 1, 0x38, 0);
395     CHECK_EQUAL(56, hid_parser.report_pos_in_bit);
396     CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
397 }
398 
399 TEST(HID, GetReportSize){
400     int report_size = 0;
401     const uint8_t * hid_descriptor =  combo_descriptor_with_report_ids;
402     uint16_t hid_descriptor_len = sizeof(combo_descriptor_with_report_ids);
403     report_size = btstack_hid_get_report_size_for_id(1, HID_REPORT_TYPE_INPUT, hid_descriptor_len, hid_descriptor);
404     CHECK_EQUAL(3, report_size);
405 
406     hid_descriptor = hid_descriptor_keyboard_boot_mode;
407     hid_descriptor_len = sizeof(hid_descriptor_keyboard_boot_mode);
408     report_size = btstack_hid_get_report_size_for_id(0, HID_REPORT_TYPE_OUTPUT, hid_descriptor_len, hid_descriptor);
409     CHECK_EQUAL(1, report_size);
410     report_size = btstack_hid_get_report_size_for_id(0, HID_REPORT_TYPE_INPUT, hid_descriptor_len, hid_descriptor);
411     CHECK_EQUAL(8, report_size);
412 }
413 
414 
415 int main (int argc, const char * argv[]){
416     // log into file using HCI_DUMP_PACKETLOGGER format
417     const char * pklg_path = "hci_dump.pklg";
418     hci_dump_posix_fs_open(pklg_path, HCI_DUMP_PACKETLOGGER);
419     hci_dump_init(hci_dump_posix_fs_get_instance());
420     printf("Packet Log: %s\n", pklg_path);
421 
422     return CommandLineTestRunner::RunAllTests(argc, argv);
423 }
424