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 Descriptor 50 51 // #define HID_PARSER_PRETTY_PRINT 52 53 /* 54 * btstack_hid_parser.c 55 */ 56 57 #ifdef HID_PARSER_PRETTY_PRINT 58 59 static const char * type_names[] = { 60 "Main", 61 "Global", 62 "Local", 63 "Reserved" 64 }; 65 static const char * main_tags[] = { 66 "", 67 "", 68 "", 69 "", 70 "", 71 "", 72 "", 73 "", 74 "Input ", 75 "Output", 76 "Collection", 77 "Feature", 78 "End Collection", 79 "Reserved", 80 "Reserved", 81 "Reserved" 82 }; 83 static const char * global_tags[] = { 84 "Usage Page", 85 "Logical Minimum", 86 "Logical Maximum", 87 "Physical Minimum", 88 "Physical Maximum", 89 "Unit Exponent", 90 "Unit", 91 "Report Size", 92 "Report ID", 93 "Report Count", 94 "Push", 95 "Pop", 96 "Reserved", 97 "Reserved", 98 "Reserved", 99 "Reserved" 100 }; 101 static const char * local_tags[] = { 102 "Usage", 103 "Usage Minimum", 104 "Usage Maximum", 105 "Designator Index", 106 "Designator Minimum", 107 "Designator Maximum", 108 "String Index", 109 "String Minimum", 110 "String Maximum", 111 "Delimiter", 112 "Reserved", 113 "Reserved", 114 "Reserved", 115 "Reserved", 116 "Reserved", 117 "Reserved" 118 }; 119 #endif 120 121 static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 122 #ifdef HID_PARSER_PRETTY_PRINT 123 const char ** item_tag_table; 124 switch ((TagType)item->item_type){ 125 case Main: 126 item_tag_table = main_tags; 127 break; 128 case Global: 129 item_tag_table = global_tags; 130 break; 131 case Local: 132 item_tag_table = local_tags; 133 break; 134 default: 135 item_tag_table = NULL; 136 break; 137 } 138 const char * item_tag_name = "Invalid"; 139 if (item_tag_table){ 140 item_tag_name = item_tag_table[item->item_tag]; 141 } 142 log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); 143 #else 144 UNUSED(parser); 145 UNUSED(item); 146 #endif 147 } 148 149 // parse descriptor item and read up to 32-bit bit value 150 bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 151 152 const int hid_item_sizes[] = { 0, 1, 2, 4 }; 153 154 // parse item header 155 if (hid_descriptor_len < 1u) return false; 156 uint16_t pos = 0; 157 uint8_t item_header = hid_descriptor[pos++]; 158 item->data_size = hid_item_sizes[item_header & 0x03u]; 159 item->item_type = (item_header & 0x0cu) >> 2u; 160 item->item_tag = (item_header & 0xf0u) >> 4u; 161 // long item 162 if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){ 163 if (hid_descriptor_len < 3u) return false; 164 item->data_size = hid_descriptor[pos++]; 165 item->item_tag = hid_descriptor[pos++]; 166 } 167 item->item_size = pos + item->data_size; 168 item->item_value = 0; 169 170 // read item value 171 if (hid_descriptor_len < item->item_size) return false; 172 if (item->data_size > 4u) return false; 173 int i; 174 int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u); 175 int32_t value = 0; 176 uint8_t latest_byte = 0; 177 for (i=0;i<item->data_size;i++){ 178 latest_byte = hid_descriptor[pos++]; 179 value = (latest_byte << (8*i)) | value; 180 } 181 if (sgnd && (item->data_size > 0u)){ 182 if (latest_byte & 0x80u) { 183 value -= 1u << (item->data_size*8u); 184 } 185 } 186 item->item_value = value; 187 return true; 188 } 189 190 static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){ 191 switch (tag){ 192 case Input: 193 return report_type == HID_REPORT_TYPE_INPUT; 194 case Output: 195 return report_type == HID_REPORT_TYPE_OUTPUT; 196 case Feature: 197 return report_type == HID_REPORT_TYPE_FEATURE; 198 default: 199 return false; 200 } 201 } 202 203 static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 204 switch((GlobalItemTag)item->item_tag){ 205 case UsagePage: 206 parser->global_usage_page = item->item_value; 207 break; 208 case LogicalMinimum: 209 parser->global_logical_minimum = item->item_value; 210 break; 211 case LogicalMaximum: 212 parser->global_logical_maximum = item->item_value; 213 break; 214 case ReportSize: 215 parser->global_report_size = item->item_value; 216 break; 217 case ReportID: 218 parser->global_report_id = item->item_value; 219 break; 220 case ReportCount: 221 parser->global_report_count = item->item_value; 222 break; 223 224 // TODO handle tags 225 case PhysicalMinimum: 226 case PhysicalMaximum: 227 case UnitExponent: 228 case Unit: 229 case Push: 230 case Pop: 231 break; 232 233 default: 234 btstack_assert(false); 235 break; 236 } 237 } 238 239 static void hid_find_next_usage(btstack_hid_parser_t * parser){ 240 bool have_usage_min = false; 241 bool have_usage_max = false; 242 parser->usage_range = false; 243 btstack_hid_descriptor_iterator_t iterator; 244 btstack_hid_descriptor_iterator_init(&iterator, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 245 while ((parser->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ 246 hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator); 247 if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 248 parser->usage_page = usage_item.item_value; 249 } 250 if (usage_item.item_type == Local){ 251 uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); 252 switch (usage_item.item_tag){ 253 case Usage: 254 parser->available_usages = 1; 255 parser->usage_minimum = usage_value; 256 break; 257 case UsageMinimum: 258 parser->usage_minimum = usage_value; 259 have_usage_min = true; 260 break; 261 case UsageMaximum: 262 parser->usage_maximum = usage_value; 263 have_usage_max = true; 264 break; 265 default: 266 break; 267 } 268 if (have_usage_min && have_usage_max){ 269 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; 270 parser->usage_range = true; 271 if (parser->available_usages < parser->required_usages){ 272 log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); 273 } 274 } 275 } 276 } 277 parser->usage_pos += iterator.descriptor_pos; 278 } 279 280 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 281 hid_pretty_print_item(parser, item); 282 int valid_field = 0; 283 uint16_t report_id_before; 284 switch ((TagType)item->item_type){ 285 case Main: 286 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 287 parser->report_type); 288 break; 289 case Global: 290 report_id_before = parser->global_report_id; 291 btstack_hid_handle_global_item(parser, item); 292 // track record id for report handling 293 if ((GlobalItemTag)item->item_tag == ReportID){ 294 if (parser->active_record && (report_id_before != item->item_value)){ 295 parser->active_record = 0; 296 } 297 } 298 break; 299 case Local: 300 case Reserved: 301 break; 302 default: 303 btstack_assert(false); 304 break; 305 } 306 if (!valid_field) return; 307 308 // verify record id 309 if (parser->global_report_id && !parser->active_record){ 310 if (parser->report[0] != parser->global_report_id){ 311 return; 312 } 313 parser->report_pos_in_bit += 8u; 314 } 315 parser->active_record = 1; 316 // handle constant fields used for padding 317 if (item->item_value & 1){ 318 int item_bits = parser->global_report_size * parser->global_report_count; 319 #ifdef HID_PARSER_PRETTY_PRINT 320 log_info("- Skip %u constant bits", item_bits); 321 #endif 322 parser->report_pos_in_bit += item_bits; 323 return; 324 } 325 // Empty Item 326 if (parser->global_report_count == 0u) return; 327 // let's start 328 parser->required_usages = parser->global_report_count; 329 } 330 331 // PUBLIC API 332 333 // HID Descriptor Iterator 334 335 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 336 iterator->descriptor = hid_descriptor; 337 iterator->descriptor_pos = 0; 338 iterator->descriptor_len = hid_descriptor_len; 339 iterator->item_ready = false; 340 iterator->valid = true; 341 } 342 343 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 344 if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){ 345 uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 346 const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 347 bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 348 if (ok){ 349 iterator->item_ready = true; 350 } else { 351 iterator->valid = false; 352 } 353 } 354 return iterator->item_ready; 355 } 356 357 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 358 iterator->descriptor_pos += iterator->descriptor_item.item_size; 359 iterator->item_ready = false; 360 return &iterator->descriptor_item; 361 } 362 363 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 364 return iterator->valid; 365 } 366 367 368 int btstack_hid_get_report_size_for_id(uint16_t report_id, hid_report_type_t report_type, const uint8_t *hid_descriptor, 369 uint16_t hid_descriptor_len) { 370 int total_report_size = 0; 371 int report_size = 0; 372 int report_count = 0; 373 int current_report_id = HID_REPORT_ID_UNDEFINED; 374 375 btstack_hid_descriptor_iterator_t iterator; 376 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 377 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 378 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 379 int valid_report_type = 0; 380 switch (item->item_type) { 381 case Global: 382 switch ((GlobalItemTag) item->item_tag) { 383 case ReportID: 384 current_report_id = item->item_value; 385 break; 386 case ReportCount: 387 report_count = item->item_value; 388 break; 389 case ReportSize: 390 report_size = item->item_value; 391 break; 392 default: 393 break; 394 } 395 break; 396 case Main: 397 if (current_report_id != report_id) break; 398 switch ((MainItemTag) item->item_tag) { 399 case Input: 400 if (report_type != HID_REPORT_TYPE_INPUT) break; 401 valid_report_type = 1; 402 break; 403 case Output: 404 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 405 valid_report_type = 1; 406 break; 407 case Feature: 408 if (report_type != HID_REPORT_TYPE_FEATURE) break; 409 valid_report_type = 1; 410 break; 411 default: 412 break; 413 } 414 if (!valid_report_type) break; 415 total_report_size += report_count * report_size; 416 break; 417 default: 418 break; 419 } 420 if (total_report_size > 0 && current_report_id != report_id) break; 421 } 422 423 if (btstack_hid_descriptor_iterator_valid(&iterator)){ 424 return (total_report_size + 7) / 8; 425 } else { 426 return 0; 427 } 428 } 429 430 hid_report_id_status_t btstack_hid_report_id_valid(uint16_t report_id, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 431 uint16_t current_report_id = HID_REPORT_ID_UNDEFINED; 432 btstack_hid_descriptor_iterator_t iterator; 433 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 434 bool report_id_found = false; 435 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 436 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 437 switch (item->item_type){ 438 case Global: 439 switch ((GlobalItemTag)item->item_tag){ 440 case ReportID: 441 current_report_id = item->item_value; 442 if (current_report_id == report_id) { 443 report_id_found = true; 444 } 445 default: 446 break; 447 } 448 break; 449 default: 450 break; 451 } 452 } 453 454 if (btstack_hid_descriptor_iterator_valid(&iterator)) { 455 if (report_id_found){ 456 return HID_REPORT_ID_VALID; 457 } 458 if ((report_id == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) { 459 return HID_REPORT_ID_VALID; 460 } 461 return HID_REPORT_ID_UNDECLARED; 462 } else { 463 return HID_REPORT_ID_INVALID; 464 } 465 } 466 467 bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_descriptor_len) { 468 btstack_hid_descriptor_iterator_t iterator; 469 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 470 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 471 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 472 switch (item->item_type){ 473 case Global: 474 switch ((GlobalItemTag)item->item_tag){ 475 case ReportID: 476 return true; 477 default: 478 break; 479 } 480 break; 481 default: 482 break; 483 } 484 } 485 return false; 486 } 487 488 // HID Descriptor Usage Iterator 489 490 static void btstack_parser_usage_iterator_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 491 hid_pretty_print_item(parser, item); 492 int valid_field = 0; 493 uint16_t report_id_before; 494 switch ((TagType)item->item_type){ 495 case Main: 496 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 497 parser->report_type); 498 break; 499 case Global: 500 report_id_before = parser->global_report_id; 501 btstack_hid_handle_global_item(parser, item); 502 // track record id for report handling, reset report position 503 if (report_id_before != parser->global_report_id){ 504 parser->report_pos_in_bit = 8u; 505 } 506 break; 507 case Local: 508 case Reserved: 509 break; 510 default: 511 btstack_assert(false); 512 break; 513 } 514 if (!valid_field) return; 515 516 // handle constant fields used for padding 517 if (item->item_value & 1){ 518 int item_bits = parser->global_report_size * parser->global_report_count; 519 #ifdef HID_PARSER_PRETTY_PRINT 520 log_info("- Skip %u constant bits", item_bits); 521 #endif 522 parser->report_pos_in_bit += item_bits; 523 return; 524 } 525 // Empty Item 526 if (parser->global_report_count == 0u) return; 527 // let's start 528 parser->required_usages = parser->global_report_count; 529 } 530 531 static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_parser_t * parser) { 532 while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){ 533 parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator); 534 535 btstack_parser_usage_iterator_process_item(parser, &parser->descriptor_item); 536 537 if (parser->required_usages){ 538 hid_find_next_usage(parser); 539 if (parser->available_usages) { 540 parser->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; 541 return; 542 } else { 543 log_debug("no usages found"); 544 parser->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; 545 return; 546 } 547 } else { 548 if ((TagType) (&parser->descriptor_item)->item_type == Main) { 549 // reset usage 550 parser->usage_pos = parser->descriptor_iterator.descriptor_pos; 551 parser->usage_page = parser->global_usage_page; 552 } 553 } 554 } 555 // end of descriptor 556 parser->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; 557 } 558 559 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){ 560 memset(parser, 0, sizeof(btstack_hid_parser_t)); 561 562 parser->descriptor = hid_descriptor; 563 parser->descriptor_len = hid_descriptor_len; 564 parser->report_type = hid_report_type; 565 parser->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; 566 parser->global_report_id = HID_REPORT_ID_UNDEFINED; 567 btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len); 568 } 569 570 bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser){ 571 while (parser->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){ 572 btstack_hid_usage_iterator_find_next_usage(parser); 573 } 574 return parser->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; 575 } 576 577 void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item){ 578 // cache current values 579 memset(item, 0, sizeof(btstack_hid_usage_item_t)); 580 item->size = parser->global_report_size; 581 item->report_id = parser->global_report_id; 582 item->usage_page = parser->usage_minimum >> 16; 583 item->bit_pos = parser->report_pos_in_bit; 584 585 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 586 if (is_variable){ 587 item->usage = parser->usage_minimum & 0xffffu; 588 } 589 parser->required_usages--; 590 parser->report_pos_in_bit += parser->global_report_size; 591 592 // cache descriptor item and 593 item->descriptor_item = parser->descriptor_item; 594 item->global_logical_minimum = parser->global_logical_minimum; 595 596 // next usage 597 if (is_variable){ 598 parser->usage_minimum++; 599 parser->available_usages--; 600 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 601 // usage min - max range smaller than report count, ignore remaining bit in report 602 log_debug("Ignoring %u items without Usage", parser->required_usages); 603 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 604 parser->required_usages = 0; 605 } 606 } else { 607 if (parser->required_usages == 0u){ 608 parser->available_usages = 0; 609 } 610 } 611 612 if (parser->available_usages) { 613 return; 614 } 615 if (parser->required_usages == 0u){ 616 parser->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; 617 } else { 618 hid_find_next_usage(parser); 619 if (parser->available_usages == 0u) { 620 parser->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; 621 } 622 } 623 } 624 625 626 // HID Report Parser 627 628 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){ 629 btstack_hid_usage_iterator_init(parser, hid_descriptor, hid_descriptor_len, hid_report_type); 630 parser->report = hid_report; 631 parser->report_len = hid_report_len; 632 parser->have_report_usage_ready = false; 633 } 634 635 /** 636 * @brief Checks if more fields are available 637 * @param parser 638 */ 639 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 640 while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(parser)){ 641 btstack_hid_usage_iterator_get_item(parser, &parser->descriptor__usage_item); 642 // ignore usages for other report ids 643 if (parser->descriptor__usage_item.report_id != HID_REPORT_ID_UNDEFINED){ 644 if (parser->descriptor__usage_item.report_id != parser->report[0]){ 645 continue; 646 } 647 } 648 parser->have_report_usage_ready = true; 649 } 650 return parser->have_report_usage_ready; 651 } 652 653 /** 654 * @brief Get next field 655 * @param parser 656 * @param usage_page 657 * @param usage 658 * @param value provided in HID report 659 */ 660 661 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 662 663 // fetch data from descriptor usage item 664 uint16_t bit_pos = parser->descriptor__usage_item.bit_pos; 665 uint16_t size = parser->descriptor__usage_item.size; 666 *usage_page = parser->descriptor__usage_item.usage_page; 667 *usage = parser->descriptor__usage_item.usage; 668 669 670 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 671 bool is_variable = (parser->descriptor__usage_item.descriptor_item.item_value & 2) != 0; 672 bool is_signed = parser->descriptor__usage_item.global_logical_minimum < 0; 673 int pos_start = btstack_min( bit_pos >> 3, parser->report_len); 674 int pos_end = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len); 675 int bytes_to_read = pos_end - pos_start + 1; 676 677 int i; 678 uint32_t multi_byte_value = 0; 679 for (i=0;i < bytes_to_read;i++){ 680 multi_byte_value |= parser->report[pos_start+i] << (i*8); 681 } 682 uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u); 683 // 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); 684 if (is_variable){ 685 if (is_signed && (unsigned_value & (1u<<(size-1u)))){ 686 *value = unsigned_value - (1u<<size); 687 } else { 688 *value = unsigned_value; 689 } 690 } else { 691 *usage = unsigned_value; 692 *value = 1; 693 } 694 695 parser->have_report_usage_ready = false; 696 } 697