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