1 /* 2 * Copyright (C) 2017 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "btstack_hid_parser.c" 39 40 #include <inttypes.h> 41 #include <string.h> 42 43 #include "btstack_hid_parser.h" 44 #include "btstack_util.h" 45 #include "btstack_debug.h" 46 47 // Not implemented: 48 // - Support for Push/Pop 49 // - Optional Pretty Print of HID Descripor 50 // - Support to query descriptort for contained usages, e.g. to detect keyboard or mouse 51 52 // #define HID_PARSER_PRETTY_PRINT 53 54 /* 55 * btstack_hid_parser.c 56 */ 57 58 #ifdef HID_PARSER_PRETTY_PRINT 59 60 static const char * type_names[] = { 61 "Main", 62 "Global", 63 "Local", 64 "Reserved" 65 }; 66 static const char * main_tags[] = { 67 "", 68 "", 69 "", 70 "", 71 "", 72 "", 73 "", 74 "", 75 "Input ", 76 "Output", 77 "Collection", 78 "Feature", 79 "End Collection", 80 "Reserved", 81 "Reserved", 82 "Reserved" 83 }; 84 static const char * global_tags[] = { 85 "Usage Page", 86 "Logical Minimum", 87 "Logical Maximum", 88 "Physical Minimum", 89 "Physical Maximum", 90 "Unit Exponent", 91 "Unit", 92 "Report Size", 93 "Report ID", 94 "Report Count", 95 "Push", 96 "Pop", 97 "Reserved", 98 "Reserved", 99 "Reserved", 100 "Reserved" 101 }; 102 static const char * local_tags[] = { 103 "Usage", 104 "Usage Minimum", 105 "Usage Maximum", 106 "Designator Index", 107 "Designator Minimum", 108 "Designator Maximum", 109 "String Index", 110 "String Minimum", 111 "String Maximum", 112 "Delimiter", 113 "Reserved", 114 "Reserved", 115 "Reserved", 116 "Reserved", 117 "Reserved", 118 "Reserved" 119 }; 120 #endif 121 122 static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 123 #ifdef HID_PARSER_PRETTY_PRINT 124 const char ** item_tag_table; 125 switch ((TagType)item->item_type){ 126 case Main: 127 item_tag_table = main_tags; 128 break; 129 case Global: 130 item_tag_table = global_tags; 131 break; 132 case Local: 133 item_tag_table = local_tags; 134 break; 135 default: 136 item_tag_table = NULL; 137 break; 138 } 139 const char * item_tag_name = "Invalid"; 140 if (item_tag_table){ 141 item_tag_name = item_tag_table[item->item_tag]; 142 } 143 log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); 144 #else 145 UNUSED(parser); 146 UNUSED(item); 147 #endif 148 } 149 150 // parse descriptor item and read up to 32-bit bit value 151 bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 152 153 const int hid_item_sizes[] = { 0, 1, 2, 4 }; 154 155 // parse item header 156 if (hid_descriptor_len < 1u) return false; 157 uint16_t pos = 0; 158 uint8_t item_header = hid_descriptor[pos++]; 159 item->data_size = hid_item_sizes[item_header & 0x03u]; 160 item->item_type = (item_header & 0x0cu) >> 2u; 161 item->item_tag = (item_header & 0xf0u) >> 4u; 162 // long item 163 if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){ 164 if (hid_descriptor_len < 3u) return false; 165 item->data_size = hid_descriptor[pos++]; 166 item->item_tag = hid_descriptor[pos++]; 167 } 168 item->item_size = pos + item->data_size; 169 item->item_value = 0; 170 171 // read item value 172 if (hid_descriptor_len < item->item_size) return false; 173 if (item->data_size > 4u) return false; 174 int i; 175 int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u); 176 int32_t value = 0; 177 uint8_t latest_byte = 0; 178 for (i=0;i<item->data_size;i++){ 179 latest_byte = hid_descriptor[pos++]; 180 value = (latest_byte << (8*i)) | value; 181 } 182 if (sgnd && (item->data_size > 0u)){ 183 if (latest_byte & 0x80u) { 184 value -= 1u << (item->data_size*8u); 185 } 186 } 187 item->item_value = value; 188 return true; 189 } 190 191 static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){ 192 switch (tag){ 193 case Input: 194 return report_type == HID_REPORT_TYPE_INPUT; 195 case Output: 196 return report_type == HID_REPORT_TYPE_OUTPUT; 197 case Feature: 198 return report_type == HID_REPORT_TYPE_FEATURE; 199 default: 200 return false; 201 } 202 } 203 204 static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 205 switch((GlobalItemTag)item->item_tag){ 206 case UsagePage: 207 parser->global_usage_page = item->item_value; 208 break; 209 case LogicalMinimum: 210 parser->global_logical_minimum = item->item_value; 211 break; 212 case LogicalMaximum: 213 parser->global_logical_maximum = item->item_value; 214 break; 215 case ReportSize: 216 parser->global_report_size = item->item_value; 217 break; 218 case ReportID: 219 parser->global_report_id = item->item_value; 220 break; 221 case ReportCount: 222 parser->global_report_count = item->item_value; 223 break; 224 225 // TODO handle tags 226 case PhysicalMinimum: 227 case PhysicalMaximum: 228 case UnitExponent: 229 case Unit: 230 case Push: 231 case Pop: 232 break; 233 234 default: 235 btstack_assert(false); 236 break; 237 } 238 } 239 240 static void hid_find_next_usage(btstack_hid_parser_t * parser){ 241 bool have_usage_min = false; 242 bool have_usage_max = false; 243 parser->usage_range = false; 244 btstack_hid_descriptor_iterator_t iterator; 245 btstack_hid_descriptor_iterator_init(&iterator, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 246 while ((parser->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ 247 hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator); 248 if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 249 parser->usage_page = usage_item.item_value; 250 } 251 if (usage_item.item_type == Local){ 252 uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); 253 switch (usage_item.item_tag){ 254 case Usage: 255 parser->available_usages = 1; 256 parser->usage_minimum = usage_value; 257 break; 258 case UsageMinimum: 259 parser->usage_minimum = usage_value; 260 have_usage_min = true; 261 break; 262 case UsageMaximum: 263 parser->usage_maximum = usage_value; 264 have_usage_max = true; 265 break; 266 default: 267 break; 268 } 269 if (have_usage_min && have_usage_max){ 270 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; 271 parser->usage_range = true; 272 if (parser->available_usages < parser->required_usages){ 273 log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); 274 } 275 } 276 } 277 } 278 parser->usage_pos += iterator.descriptor_pos; 279 } 280 281 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 282 hid_pretty_print_item(parser, item); 283 int valid_field = 0; 284 uint16_t report_id_before; 285 switch ((TagType)item->item_type){ 286 case Main: 287 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 288 parser->report_type); 289 break; 290 case Global: 291 report_id_before = parser->global_report_id; 292 btstack_hid_handle_global_item(parser, item); 293 // track record id for report handling 294 if ((GlobalItemTag)item->item_tag == ReportID){ 295 if (parser->active_record && (report_id_before != item->item_value)){ 296 parser->active_record = 0; 297 } 298 } 299 break; 300 case Local: 301 case Reserved: 302 break; 303 default: 304 btstack_assert(false); 305 break; 306 } 307 if (!valid_field) return; 308 309 // verify record id 310 if (parser->global_report_id && !parser->active_record){ 311 if (parser->report[0] != parser->global_report_id){ 312 return; 313 } 314 parser->report_pos_in_bit += 8u; 315 } 316 parser->active_record = 1; 317 // handle constant fields used for padding 318 if (item->item_value & 1){ 319 int item_bits = parser->global_report_size * parser->global_report_count; 320 #ifdef HID_PARSER_PRETTY_PRINT 321 log_info("- Skip %u constant bits", item_bits); 322 #endif 323 parser->report_pos_in_bit += item_bits; 324 return; 325 } 326 // Empty Item 327 if (parser->global_report_count == 0u) return; 328 // let's start 329 parser->required_usages = parser->global_report_count; 330 } 331 332 static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){ 333 while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){ 334 parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator); 335 hid_process_item(parser, &parser->descriptor_item); 336 if (parser->required_usages){ 337 hid_find_next_usage(parser); 338 if (parser->available_usages) { 339 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 340 return; 341 } else { 342 log_debug("no usages found"); 343 parser->state = BTSTACK_HID_PARSER_COMPLETE; 344 return; 345 } 346 } else { 347 if ((TagType) (&parser->descriptor_item)->item_type == Main) { 348 // reset usage 349 parser->usage_pos = parser->descriptor_iterator.descriptor_pos; 350 parser->usage_page = parser->global_usage_page; 351 } 352 } 353 } 354 // end of descriptor 355 parser->state = BTSTACK_HID_PARSER_COMPLETE; 356 } 357 358 // PUBLIC API 359 360 void btstack_hid_parser_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type, const uint8_t * hid_report, uint16_t hid_report_len){ 361 362 memset(parser, 0, sizeof(btstack_hid_parser_t)); 363 364 parser->descriptor = hid_descriptor; 365 parser->descriptor_len = hid_descriptor_len; 366 parser->report_type = hid_report_type; 367 parser->report = hid_report; 368 parser->report_len = hid_report_len; 369 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 370 371 btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len); 372 373 btstack_hid_parser_find_next_usage(parser); 374 } 375 376 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 377 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 378 } 379 380 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 381 382 *usage_page = parser->usage_minimum >> 16; 383 384 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 385 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 386 bool is_signed = parser->global_logical_minimum < 0; 387 int pos_start = btstack_min( parser->report_pos_in_bit >> 3, parser->report_len); 388 int pos_end = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len); 389 int bytes_to_read = pos_end - pos_start + 1; 390 int i; 391 uint32_t multi_byte_value = 0; 392 for (i=0;i < bytes_to_read;i++){ 393 multi_byte_value |= parser->report[pos_start+i] << (i*8); 394 } 395 uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u); 396 // log_debug("bit pos %2u, report size %u, start %u, end %u, len %u;; unsigned value %08x", parser->report_pos_in_bit, parser->global_report_size, pos_start, pos_end, parser->report_len, unsigned_value); 397 if (is_variable){ 398 *usage = parser->usage_minimum & 0xffffu; 399 if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){ 400 *value = unsigned_value - (1u<<parser->global_report_size); 401 } else { 402 *value = unsigned_value; 403 } 404 } else { 405 *usage = unsigned_value; 406 *value = 1; 407 } 408 parser->required_usages--; 409 parser->report_pos_in_bit += parser->global_report_size; 410 411 // next usage 412 if (is_variable){ 413 parser->usage_minimum++; 414 parser->available_usages--; 415 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 416 // usage min - max range smaller than report count, ignore remaining bit in report 417 log_debug("Ignoring %u items without Usage", parser->required_usages); 418 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 419 parser->required_usages = 0; 420 } 421 } else { 422 if (parser->required_usages == 0u){ 423 parser->available_usages = 0; 424 } 425 } 426 if (parser->available_usages) { 427 return; 428 } 429 if (parser->required_usages == 0u){ 430 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 431 btstack_hid_parser_find_next_usage(parser); 432 } else { 433 hid_find_next_usage(parser); 434 if (parser->available_usages == 0u) { 435 parser->state = BTSTACK_HID_PARSER_COMPLETE; 436 } 437 } 438 } 439 440 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 441 iterator->descriptor = hid_descriptor; 442 iterator->descriptor_pos = 0; 443 iterator->descriptor_len = hid_descriptor_len; 444 iterator->item_ready = false; 445 iterator->valid = true; 446 } 447 448 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 449 if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){ 450 uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 451 const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 452 bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 453 if (ok){ 454 iterator->item_ready = true; 455 } else { 456 iterator->valid = false; 457 } 458 } 459 return iterator->item_ready; 460 } 461 462 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 463 iterator->descriptor_pos += iterator->descriptor_item.item_size; 464 iterator->item_ready = false; 465 return &iterator->descriptor_item; 466 } 467 468 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 469 return iterator->valid; 470 } 471 472 int btstack_hid_get_report_size_for_id(int report_id, hid_report_type_t report_type, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor) { 473 int total_report_size = 0; 474 int report_size = 0; 475 int report_count = 0; 476 int current_report_id = 0; 477 478 btstack_hid_descriptor_iterator_t iterator; 479 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 480 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 481 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 482 int valid_report_type = 0; 483 switch (item->item_type) { 484 case Global: 485 switch ((GlobalItemTag) item->item_tag) { 486 case ReportID: 487 current_report_id = item->item_value; 488 break; 489 case ReportCount: 490 report_count = item->item_value; 491 break; 492 case ReportSize: 493 report_size = item->item_value; 494 break; 495 default: 496 break; 497 } 498 break; 499 case Main: 500 if (current_report_id != report_id) break; 501 switch ((MainItemTag) item->item_tag) { 502 case Input: 503 if (report_type != HID_REPORT_TYPE_INPUT) break; 504 valid_report_type = 1; 505 break; 506 case Output: 507 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 508 valid_report_type = 1; 509 break; 510 case Feature: 511 if (report_type != HID_REPORT_TYPE_FEATURE) break; 512 valid_report_type = 1; 513 break; 514 default: 515 break; 516 } 517 if (!valid_report_type) break; 518 total_report_size += report_count * report_size; 519 break; 520 default: 521 break; 522 } 523 if (total_report_size > 0 && current_report_id != report_id) break; 524 } 525 526 if (btstack_hid_descriptor_iterator_valid(&iterator)){ 527 return (total_report_size + 7) / 8; 528 } else { 529 return 0; 530 } 531 } 532 533 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 534 int current_report_id = -1; 535 btstack_hid_descriptor_iterator_t iterator; 536 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 537 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 538 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 539 switch (item->item_type){ 540 case Global: 541 switch ((GlobalItemTag)item->item_tag){ 542 case ReportID: 543 current_report_id = item->item_value; 544 if (current_report_id != report_id) break; 545 return HID_REPORT_ID_VALID; 546 default: 547 break; 548 } 549 break; 550 default: 551 break; 552 } 553 } 554 555 if (btstack_hid_descriptor_iterator_valid(&iterator)) { 556 if (current_report_id != -1) { 557 return HID_REPORT_ID_INVALID; 558 } else { 559 return HID_REPORT_ID_UNDECLARED; 560 } 561 } else { 562 return HID_REPORT_ID_INVALID; 563 } 564 } 565 566 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 567 btstack_hid_descriptor_iterator_t iterator; 568 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 569 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 570 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 571 switch (item->item_type){ 572 case Global: 573 switch ((GlobalItemTag)item->item_tag){ 574 case ReportID: 575 return true; 576 default: 577 break; 578 } 579 break; 580 default: 581 break; 582 } 583 } 584 return false; 585 } 586 587 static void btstack_parser_usage_iterator_process_item2(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 588 hid_pretty_print_item(parser, item); 589 int valid_field = 0; 590 uint16_t report_id_before; 591 switch ((TagType)item->item_type){ 592 case Main: 593 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 594 parser->report_type); 595 break; 596 case Global: 597 report_id_before = parser->global_report_id; 598 btstack_hid_handle_global_item(parser, item); 599 // track record id for report handling, reset report position 600 if (report_id_before != parser->global_report_id){ 601 parser->report_pos_in_bit = 8u; 602 } 603 break; 604 case Local: 605 case Reserved: 606 break; 607 default: 608 btstack_assert(false); 609 break; 610 } 611 if (!valid_field) return; 612 613 // handle constant fields used for padding 614 if (item->item_value & 1){ 615 int item_bits = parser->global_report_size * parser->global_report_count; 616 #ifdef HID_PARSER_PRETTY_PRINT 617 log_info("- Skip %u constant bits", item_bits); 618 #endif 619 parser->report_pos_in_bit += item_bits; 620 return; 621 } 622 // Empty Item 623 if (parser->global_report_count == 0u) return; 624 // let's start 625 parser->required_usages = parser->global_report_count; 626 } 627 628 static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_parser_t * parser) { 629 while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){ 630 parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator); 631 632 btstack_parser_usage_iterator_process_item2(parser, &parser->descriptor_item); 633 634 if (parser->required_usages){ 635 hid_find_next_usage(parser); 636 if (parser->available_usages) { 637 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 638 return; 639 } else { 640 log_debug("no usages found"); 641 parser->state = BTSTACK_HID_PARSER_COMPLETE; 642 return; 643 } 644 } else { 645 if ((TagType) (&parser->descriptor_item)->item_type == Main) { 646 // reset usage 647 parser->usage_pos = parser->descriptor_iterator.descriptor_pos; 648 parser->usage_page = parser->global_usage_page; 649 } 650 } 651 } 652 // end of descriptor 653 parser->state = BTSTACK_HID_PARSER_COMPLETE; 654 } 655 656 void btstack_hid_usage_iterator_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type){ 657 memset(parser, 0, sizeof(btstack_hid_parser_t)); 658 659 parser->descriptor = hid_descriptor; 660 parser->descriptor_len = hid_descriptor_len; 661 parser->report_type = hid_report_type; 662 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 663 btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len); 664 665 btstack_hid_usage_iterator_find_next_usage(parser); 666 } 667 668 bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser){ 669 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 670 } 671 672 void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item){ 673 // cache current values 674 memset(item, 0, sizeof(btstack_hid_usage_item_t)); 675 item->size = parser->global_report_size; 676 item->report_id = parser->global_report_id; 677 item->usage_page = parser->usage_minimum >> 16; 678 item->bit_pos = parser->report_pos_in_bit; 679 680 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 681 if (is_variable){ 682 item->usage = parser->usage_minimum & 0xffffu; 683 } 684 parser->required_usages--; 685 parser->report_pos_in_bit += parser->global_report_size; 686 687 // next usage 688 if (is_variable){ 689 parser->usage_minimum++; 690 parser->available_usages--; 691 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 692 // usage min - max range smaller than report count, ignore remaining bit in report 693 log_debug("Ignoring %u items without Usage", parser->required_usages); 694 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 695 parser->required_usages = 0; 696 } 697 } else { 698 if (parser->required_usages == 0u){ 699 parser->available_usages = 0; 700 } 701 } 702 if (parser->available_usages) { 703 return; 704 } 705 if (parser->required_usages == 0u){ 706 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 707 btstack_hid_usage_iterator_find_next_usage(parser); 708 } else { 709 hid_find_next_usage(parser); 710 if (parser->available_usages == 0u) { 711 parser->state = BTSTACK_HID_PARSER_COMPLETE; 712 } 713 } 714 } 715 716 //