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, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor) { 369 int total_report_size = 0; 370 int report_size = 0; 371 int report_count = 0; 372 int current_report_id = HID_REPORT_ID_UNDEFINED; 373 374 btstack_hid_descriptor_iterator_t iterator; 375 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 376 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 377 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 378 int valid_report_type = 0; 379 switch (item->item_type) { 380 case Global: 381 switch ((GlobalItemTag) item->item_tag) { 382 case ReportID: 383 current_report_id = item->item_value; 384 break; 385 case ReportCount: 386 report_count = item->item_value; 387 break; 388 case ReportSize: 389 report_size = item->item_value; 390 break; 391 default: 392 break; 393 } 394 break; 395 case Main: 396 if (current_report_id != report_id) break; 397 switch ((MainItemTag) item->item_tag) { 398 case Input: 399 if (report_type != HID_REPORT_TYPE_INPUT) break; 400 valid_report_type = 1; 401 break; 402 case Output: 403 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 404 valid_report_type = 1; 405 break; 406 case Feature: 407 if (report_type != HID_REPORT_TYPE_FEATURE) break; 408 valid_report_type = 1; 409 break; 410 default: 411 break; 412 } 413 if (!valid_report_type) break; 414 total_report_size += report_count * report_size; 415 break; 416 default: 417 break; 418 } 419 if (total_report_size > 0 && current_report_id != report_id) break; 420 } 421 422 if (btstack_hid_descriptor_iterator_valid(&iterator)){ 423 return (total_report_size + 7) / 8; 424 } else { 425 return 0; 426 } 427 } 428 429 hid_report_id_status_t btstack_hid_report_id_valid(uint16_t report_id, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 430 uint16_t current_report_id = HID_REPORT_ID_UNDEFINED; 431 btstack_hid_descriptor_iterator_t iterator; 432 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 433 bool report_id_found = false; 434 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 435 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 436 switch (item->item_type){ 437 case Global: 438 switch ((GlobalItemTag)item->item_tag){ 439 case ReportID: 440 current_report_id = item->item_value; 441 if (current_report_id == report_id) { 442 report_id_found = true; 443 } 444 default: 445 break; 446 } 447 break; 448 default: 449 break; 450 } 451 } 452 453 if (btstack_hid_descriptor_iterator_valid(&iterator)) { 454 if (report_id_found){ 455 return HID_REPORT_ID_VALID; 456 } 457 if ((report_id == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) { 458 return HID_REPORT_ID_VALID; 459 } 460 return HID_REPORT_ID_UNDECLARED; 461 } else { 462 return HID_REPORT_ID_INVALID; 463 } 464 } 465 466 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 467 btstack_hid_descriptor_iterator_t iterator; 468 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 469 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 470 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 471 switch (item->item_type){ 472 case Global: 473 switch ((GlobalItemTag)item->item_tag){ 474 case ReportID: 475 return true; 476 default: 477 break; 478 } 479 break; 480 default: 481 break; 482 } 483 } 484 return false; 485 } 486 487 // HID Descriptor Usage Iterator 488 489 static void btstack_parser_usage_iterator_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 490 hid_pretty_print_item(parser, item); 491 int valid_field = 0; 492 uint16_t report_id_before; 493 switch ((TagType)item->item_type){ 494 case Main: 495 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 496 parser->report_type); 497 break; 498 case Global: 499 report_id_before = parser->global_report_id; 500 btstack_hid_handle_global_item(parser, item); 501 // track record id for report handling, reset report position 502 if (report_id_before != parser->global_report_id){ 503 parser->report_pos_in_bit = 8u; 504 } 505 break; 506 case Local: 507 case Reserved: 508 break; 509 default: 510 btstack_assert(false); 511 break; 512 } 513 if (!valid_field) return; 514 515 // handle constant fields used for padding 516 if (item->item_value & 1){ 517 int item_bits = parser->global_report_size * parser->global_report_count; 518 #ifdef HID_PARSER_PRETTY_PRINT 519 log_info("- Skip %u constant bits", item_bits); 520 #endif 521 parser->report_pos_in_bit += item_bits; 522 return; 523 } 524 // Empty Item 525 if (parser->global_report_count == 0u) return; 526 // let's start 527 parser->required_usages = parser->global_report_count; 528 } 529 530 static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_parser_t * parser) { 531 while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){ 532 parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator); 533 534 btstack_parser_usage_iterator_process_item(parser, &parser->descriptor_item); 535 536 if (parser->required_usages){ 537 hid_find_next_usage(parser); 538 if (parser->available_usages) { 539 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 540 return; 541 } else { 542 log_debug("no usages found"); 543 parser->state = BTSTACK_HID_PARSER_COMPLETE; 544 return; 545 } 546 } else { 547 if ((TagType) (&parser->descriptor_item)->item_type == Main) { 548 // reset usage 549 parser->usage_pos = parser->descriptor_iterator.descriptor_pos; 550 parser->usage_page = parser->global_usage_page; 551 } 552 } 553 } 554 // end of descriptor 555 parser->state = BTSTACK_HID_PARSER_COMPLETE; 556 } 557 558 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){ 559 memset(parser, 0, sizeof(btstack_hid_parser_t)); 560 561 parser->descriptor = hid_descriptor; 562 parser->descriptor_len = hid_descriptor_len; 563 parser->report_type = hid_report_type; 564 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 565 parser->global_report_id = HID_REPORT_ID_UNDEFINED; 566 btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len); 567 568 btstack_hid_usage_iterator_find_next_usage(parser); 569 } 570 571 bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser){ 572 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 573 } 574 575 void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item){ 576 // cache current values 577 memset(item, 0, sizeof(btstack_hid_usage_item_t)); 578 item->size = parser->global_report_size; 579 item->report_id = parser->global_report_id; 580 item->usage_page = parser->usage_minimum >> 16; 581 item->bit_pos = parser->report_pos_in_bit; 582 583 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 584 if (is_variable){ 585 item->usage = parser->usage_minimum & 0xffffu; 586 } 587 parser->required_usages--; 588 parser->report_pos_in_bit += parser->global_report_size; 589 590 // cache descriptor item and 591 item->descriptor_item = parser->descriptor_item; 592 item->global_logical_minimum = parser->global_logical_minimum; 593 594 // next usage 595 if (is_variable){ 596 parser->usage_minimum++; 597 parser->available_usages--; 598 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 599 // usage min - max range smaller than report count, ignore remaining bit in report 600 log_debug("Ignoring %u items without Usage", parser->required_usages); 601 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 602 parser->required_usages = 0; 603 } 604 } else { 605 if (parser->required_usages == 0u){ 606 parser->available_usages = 0; 607 } 608 } 609 if (parser->available_usages) { 610 return; 611 } 612 if (parser->required_usages == 0u){ 613 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 614 btstack_hid_usage_iterator_find_next_usage(parser); 615 } else { 616 hid_find_next_usage(parser); 617 if (parser->available_usages == 0u) { 618 parser->state = BTSTACK_HID_PARSER_COMPLETE; 619 } 620 } 621 } 622 623 624 // HID Report Parser 625 626 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){ 627 btstack_hid_usage_iterator_init(parser, hid_descriptor, hid_descriptor_len, hid_report_type); 628 parser->report = hid_report; 629 parser->report_len = hid_report_len; 630 parser->have_report_usage_ready = false; 631 } 632 633 /** 634 * @brief Checks if more fields are available 635 * @param parser 636 */ 637 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 638 while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(parser)){ 639 btstack_hid_usage_iterator_get_item(parser, &parser->descriptor__usage_item); 640 // ignore usages for other report ids 641 if (parser->descriptor__usage_item.report_id != HID_REPORT_ID_UNDEFINED){ 642 if (parser->descriptor__usage_item.report_id != parser->report[0]){ 643 continue; 644 } 645 } 646 parser->have_report_usage_ready = true; 647 } 648 return parser->have_report_usage_ready; 649 } 650 651 /** 652 * @brief Get next field 653 * @param parser 654 * @param usage_page 655 * @param usage 656 * @param value provided in HID report 657 */ 658 659 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 660 661 // fetch data from descriptor usage item 662 uint16_t bit_pos = parser->descriptor__usage_item.bit_pos; 663 uint16_t size = parser->descriptor__usage_item.size; 664 *usage_page = parser->descriptor__usage_item.usage_page; 665 *usage = parser->descriptor__usage_item.usage; 666 667 668 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 669 bool is_variable = (parser->descriptor__usage_item.descriptor_item.item_value & 2) != 0; 670 bool is_signed = parser->descriptor__usage_item.global_logical_minimum < 0; 671 int pos_start = btstack_min( bit_pos >> 3, parser->report_len); 672 int pos_end = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len); 673 int bytes_to_read = pos_end - pos_start + 1; 674 675 int i; 676 uint32_t multi_byte_value = 0; 677 for (i=0;i < bytes_to_read;i++){ 678 multi_byte_value |= parser->report[pos_start+i] << (i*8); 679 } 680 uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u); 681 // 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); 682 if (is_variable){ 683 if (is_signed && (unsigned_value & (1u<<(size-1u)))){ 684 *value = unsigned_value - (1u<<size); 685 } else { 686 *value = unsigned_value; 687 } 688 } else { 689 *usage = unsigned_value; 690 *value = 1; 691 } 692 693 parser->have_report_usage_ready = false; 694 } 695