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