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