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 void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 192 switch((GlobalItemTag)item->item_tag){ 193 case UsagePage: 194 parser->global_usage_page = item->item_value; 195 break; 196 case LogicalMinimum: 197 parser->global_logical_minimum = item->item_value; 198 break; 199 case LogicalMaximum: 200 parser->global_logical_maximum = item->item_value; 201 break; 202 case ReportSize: 203 parser->global_report_size = item->item_value; 204 break; 205 case ReportID: 206 parser->global_report_id = item->item_value; 207 break; 208 case ReportCount: 209 parser->global_report_count = item->item_value; 210 break; 211 212 // TODO handle tags 213 case PhysicalMinimum: 214 case PhysicalMaximum: 215 case UnitExponent: 216 case Unit: 217 case Push: 218 case Pop: 219 break; 220 221 default: 222 btstack_assert(false); 223 break; 224 } 225 } 226 227 static void hid_find_next_usage(btstack_hid_parser_t * parser){ 228 bool have_usage_min = false; 229 bool have_usage_max = false; 230 parser->usage_range = false; 231 while ((parser->available_usages == 0u) && (parser->usage_pos < parser->descriptor_pos)){ 232 hid_descriptor_item_t usage_item; 233 // parser->usage_pos < parser->descriptor_pos < parser->descriptor_len 234 bool ok = btstack_hid_parse_descriptor_item(&usage_item, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 235 if (ok == false){ 236 break; 237 } 238 if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 239 parser->usage_page = usage_item.item_value; 240 } 241 if (usage_item.item_type == Local){ 242 uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); 243 switch (usage_item.item_tag){ 244 case Usage: 245 parser->available_usages = 1; 246 parser->usage_minimum = usage_value; 247 break; 248 case UsageMinimum: 249 parser->usage_minimum = usage_value; 250 have_usage_min = true; 251 break; 252 case UsageMaximum: 253 parser->usage_maximum = usage_value; 254 have_usage_max = true; 255 break; 256 default: 257 break; 258 } 259 if (have_usage_min && have_usage_max){ 260 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; 261 parser->usage_range = true; 262 if (parser->available_usages < parser->required_usages){ 263 log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); 264 } 265 } 266 } 267 parser->usage_pos += usage_item.item_size; 268 } 269 } 270 271 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 272 hid_pretty_print_item(parser, item); 273 int valid_field = 0; 274 uint16_t report_id_before; 275 switch ((TagType)item->item_type){ 276 case Main: 277 switch ((MainItemTag)item->item_tag){ 278 case Input: 279 valid_field = parser->report_type == HID_REPORT_TYPE_INPUT; 280 break; 281 case Output: 282 valid_field = parser->report_type == HID_REPORT_TYPE_OUTPUT; 283 break; 284 case Feature: 285 valid_field = parser->report_type == HID_REPORT_TYPE_FEATURE; 286 break; 287 default: 288 break; 289 } 290 break; 291 case Global: 292 report_id_before = parser->global_report_id; 293 btstack_hid_handle_global_item(parser, item); 294 // track record id for report handling 295 if ((GlobalItemTag)item->item_tag == ReportID){ 296 if (parser->active_record && (report_id_before != item->item_value)){ 297 parser->active_record = 0; 298 } 299 } 300 break; 301 case Local: 302 case Reserved: 303 break; 304 default: 305 btstack_assert(false); 306 break; 307 } 308 if (!valid_field) return; 309 310 // verify record id 311 if (parser->global_report_id && !parser->active_record){ 312 if (parser->report[0] != parser->global_report_id){ 313 return; 314 } 315 parser->report_pos_in_bit += 8u; 316 } 317 parser->active_record = 1; 318 // handle constant fields used for padding 319 if (item->item_value & 1){ 320 int item_bits = parser->global_report_size * parser->global_report_count; 321 #ifdef HID_PARSER_PRETTY_PRINT 322 log_info("- Skip %u constant bits", item_bits); 323 #endif 324 parser->report_pos_in_bit += item_bits; 325 return; 326 } 327 // Empty Item 328 if (parser->global_report_count == 0u) return; 329 // let's start 330 parser->required_usages = parser->global_report_count; 331 } 332 333 static void hid_post_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 334 if ((TagType)item->item_type == Main){ 335 // reset usage 336 parser->usage_pos = parser->descriptor_pos; 337 parser->usage_page = parser->global_usage_page; 338 } 339 parser->descriptor_pos += item->item_size; 340 } 341 342 static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){ 343 while (parser->state == BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM){ 344 if (parser->descriptor_pos >= parser->descriptor_len){ 345 // end of descriptor 346 parser->state = BTSTACK_HID_PARSER_COMPLETE; 347 break; 348 } 349 bool ok = btstack_hid_parse_descriptor_item(&parser->descriptor_item, &parser->descriptor[parser->descriptor_pos], parser->descriptor_len - parser->descriptor_pos); 350 if (ok == false){ 351 // abort parsing 352 parser->state = BTSTACK_HID_PARSER_COMPLETE; 353 break; 354 } 355 hid_process_item(parser, &parser->descriptor_item); 356 if (parser->required_usages){ 357 hid_find_next_usage(parser); 358 if (parser->available_usages) { 359 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 360 } else { 361 log_debug("no usages found"); 362 parser->state = BTSTACK_HID_PARSER_COMPLETE; 363 } 364 } else { 365 hid_post_process_item(parser, &parser->descriptor_item); 366 } 367 } 368 } 369 370 // PUBLIC API 371 372 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){ 373 374 memset(parser, 0, sizeof(btstack_hid_parser_t)); 375 376 parser->descriptor = hid_descriptor; 377 parser->descriptor_len = hid_descriptor_len; 378 parser->report_type = hid_report_type; 379 parser->report = hid_report; 380 parser->report_len = hid_report_len; 381 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 382 383 btstack_hid_parser_find_next_usage(parser); 384 } 385 386 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 387 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 388 } 389 390 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 391 392 *usage_page = parser->usage_minimum >> 16; 393 394 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 395 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 396 bool is_signed = parser->global_logical_minimum < 0; 397 int pos_start = btstack_min( parser->report_pos_in_bit >> 3, parser->report_len); 398 int pos_end = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len); 399 int bytes_to_read = pos_end - pos_start + 1; 400 int i; 401 uint32_t multi_byte_value = 0; 402 for (i=0;i < bytes_to_read;i++){ 403 multi_byte_value |= parser->report[pos_start+i] << (i*8); 404 } 405 uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u); 406 // 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); 407 if (is_variable){ 408 *usage = parser->usage_minimum & 0xffffu; 409 if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){ 410 *value = unsigned_value - (1u<<parser->global_report_size); 411 } else { 412 *value = unsigned_value; 413 } 414 } else { 415 *usage = unsigned_value; 416 *value = 1; 417 } 418 parser->required_usages--; 419 parser->report_pos_in_bit += parser->global_report_size; 420 421 // next usage 422 if (is_variable){ 423 parser->usage_minimum++; 424 parser->available_usages--; 425 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 426 // usage min - max range smaller than report count, ignore remaining bit in report 427 log_debug("Ignoring %u items without Usage", parser->required_usages); 428 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 429 parser->required_usages = 0; 430 } 431 } else { 432 if (parser->required_usages == 0u){ 433 parser->available_usages = 0; 434 } 435 } 436 if (parser->available_usages) { 437 return; 438 } 439 if (parser->required_usages == 0u){ 440 hid_post_process_item(parser, &parser->descriptor_item); 441 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 442 btstack_hid_parser_find_next_usage(parser); 443 } else { 444 hid_find_next_usage(parser); 445 if (parser->available_usages == 0u) { 446 parser->state = BTSTACK_HID_PARSER_COMPLETE; 447 } 448 } 449 } 450 451 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 452 iterator->descriptor = hid_descriptor; 453 iterator->descriptor_pos = 0; 454 iterator->descriptor_len = hid_descriptor_len; 455 iterator->item_ready = false; 456 iterator->valid = true; 457 } 458 459 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 460 if ((iterator->item_ready == false) && (iterator->descriptor_len > 0)){ 461 uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 462 const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 463 bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 464 if (ok){ 465 iterator->item_ready = true; 466 } else { 467 iterator->valid = false; 468 } 469 } 470 return iterator->item_ready; 471 } 472 473 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 474 475 btstack_assert(iterator->descriptor_len >= iterator->descriptor_item.item_size); 476 477 iterator->descriptor_len -= iterator->descriptor_item.item_size; 478 iterator->descriptor += iterator->descriptor_item.item_size; 479 iterator->item_ready = false; 480 return &iterator->descriptor_item; 481 } 482 483 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 484 return iterator->valid; 485 } 486 487 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){ 488 int total_report_size = 0; 489 int report_size = 0; 490 int report_count = 0; 491 int current_report_id = 0; 492 493 while (hid_descriptor_len){ 494 int valid_report_type = 0; 495 hid_descriptor_item_t item; 496 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 497 if (ok == false) { 498 return 0; 499 } 500 switch (item.item_type){ 501 case Global: 502 switch ((GlobalItemTag)item.item_tag){ 503 case ReportID: 504 current_report_id = item.item_value; 505 break; 506 case ReportCount: 507 report_count = item.item_value; 508 break; 509 case ReportSize: 510 report_size = item.item_value; 511 break; 512 default: 513 break; 514 } 515 break; 516 case Main: 517 if (current_report_id != report_id) break; 518 switch ((MainItemTag)item.item_tag){ 519 case Input: 520 if (report_type != HID_REPORT_TYPE_INPUT) break; 521 valid_report_type = 1; 522 break; 523 case Output: 524 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 525 valid_report_type = 1; 526 break; 527 case Feature: 528 if (report_type != HID_REPORT_TYPE_FEATURE) break; 529 valid_report_type = 1; 530 break; 531 default: 532 break; 533 } 534 if (!valid_report_type) break; 535 total_report_size += report_count * report_size; 536 break; 537 default: 538 break; 539 } 540 if (total_report_size > 0 && current_report_id != report_id) break; 541 hid_descriptor_len -= item.item_size; 542 hid_descriptor += item.item_size; 543 } 544 return (total_report_size + 7)/8; 545 } 546 547 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 548 int current_report_id = 0; 549 while (hid_descriptor_len){ 550 hid_descriptor_item_t item; 551 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 552 if (ok == false){ 553 return HID_REPORT_ID_INVALID; 554 } 555 switch (item.item_type){ 556 case Global: 557 switch ((GlobalItemTag)item.item_tag){ 558 case ReportID: 559 current_report_id = item.item_value; 560 if (current_report_id != report_id) break; 561 return HID_REPORT_ID_VALID; 562 default: 563 break; 564 } 565 break; 566 default: 567 break; 568 } 569 hid_descriptor_len -= item.item_size; 570 hid_descriptor += item.item_size; 571 } 572 if (current_report_id != 0) return HID_REPORT_ID_INVALID; 573 return HID_REPORT_ID_UNDECLARED; 574 } 575 576 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 577 while (hid_descriptor_len){ 578 hid_descriptor_item_t item; 579 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 580 if (ok == false){ 581 break; 582 } 583 switch (item.item_type){ 584 case Global: 585 switch ((GlobalItemTag)item.item_tag){ 586 case ReportID: 587 return true; 588 default: 589 break; 590 } 591 break; 592 default: 593 break; 594 } 595 hid_descriptor_len -= item.item_size; 596 hid_descriptor += item.item_size; 597 } 598 return false; 599 } 600