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