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 btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){ 334 while (parser->state == BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM){ 335 if (parser->descriptor_pos >= parser->descriptor_len){ 336 // end of descriptor 337 parser->state = BTSTACK_HID_PARSER_COMPLETE; 338 break; 339 } 340 bool ok = btstack_hid_parse_descriptor_item(&parser->descriptor_item, &parser->descriptor[parser->descriptor_pos], parser->descriptor_len - parser->descriptor_pos); 341 if (ok == false){ 342 // abort parsing 343 parser->state = BTSTACK_HID_PARSER_COMPLETE; 344 break; 345 } 346 hid_process_item(parser, &parser->descriptor_item); 347 if (parser->required_usages){ 348 hid_find_next_usage(parser); 349 if (parser->available_usages) { 350 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 351 } else { 352 log_debug("no usages found"); 353 parser->state = BTSTACK_HID_PARSER_COMPLETE; 354 } 355 } else { 356 if ((TagType) (&parser->descriptor_item)->item_type == Main) { 357 // reset usage 358 parser->usage_pos = parser->descriptor_pos; 359 parser->usage_page = parser->global_usage_page; 360 } 361 parser->descriptor_pos += parser->descriptor_item.item_size; 362 } 363 } 364 } 365 366 // PUBLIC API 367 368 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){ 369 370 memset(parser, 0, sizeof(btstack_hid_parser_t)); 371 372 parser->descriptor = hid_descriptor; 373 parser->descriptor_len = hid_descriptor_len; 374 parser->report_type = hid_report_type; 375 parser->report = hid_report; 376 parser->report_len = hid_report_len; 377 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 378 379 btstack_hid_parser_find_next_usage(parser); 380 } 381 382 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 383 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 384 } 385 386 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 387 388 *usage_page = parser->usage_minimum >> 16; 389 390 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 391 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 392 bool is_signed = parser->global_logical_minimum < 0; 393 int pos_start = btstack_min( parser->report_pos_in_bit >> 3, parser->report_len); 394 int pos_end = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len); 395 int bytes_to_read = pos_end - pos_start + 1; 396 int i; 397 uint32_t multi_byte_value = 0; 398 for (i=0;i < bytes_to_read;i++){ 399 multi_byte_value |= parser->report[pos_start+i] << (i*8); 400 } 401 uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u); 402 // 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); 403 if (is_variable){ 404 *usage = parser->usage_minimum & 0xffffu; 405 if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){ 406 *value = unsigned_value - (1u<<parser->global_report_size); 407 } else { 408 *value = unsigned_value; 409 } 410 } else { 411 *usage = unsigned_value; 412 *value = 1; 413 } 414 parser->required_usages--; 415 parser->report_pos_in_bit += parser->global_report_size; 416 417 // next usage 418 if (is_variable){ 419 parser->usage_minimum++; 420 parser->available_usages--; 421 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 422 // usage min - max range smaller than report count, ignore remaining bit in report 423 log_debug("Ignoring %u items without Usage", parser->required_usages); 424 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 425 parser->required_usages = 0; 426 } 427 } else { 428 if (parser->required_usages == 0u){ 429 parser->available_usages = 0; 430 } 431 } 432 if (parser->available_usages) { 433 return; 434 } 435 if (parser->required_usages == 0u){ 436 parser->descriptor_pos += parser->descriptor_item.item_size; 437 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 438 btstack_hid_parser_find_next_usage(parser); 439 } else { 440 hid_find_next_usage(parser); 441 if (parser->available_usages == 0u) { 442 parser->state = BTSTACK_HID_PARSER_COMPLETE; 443 } 444 } 445 } 446 447 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 448 iterator->descriptor = hid_descriptor; 449 iterator->descriptor_pos = 0; 450 iterator->descriptor_len = hid_descriptor_len; 451 iterator->item_ready = false; 452 iterator->valid = true; 453 } 454 455 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 456 if ((iterator->item_ready == false) && (iterator->descriptor_len > 0)){ 457 uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 458 const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 459 bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 460 if (ok){ 461 iterator->item_ready = true; 462 } else { 463 iterator->valid = false; 464 } 465 } 466 return iterator->item_ready; 467 } 468 469 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 470 471 btstack_assert(iterator->descriptor_len >= iterator->descriptor_item.item_size); 472 473 iterator->descriptor_len -= iterator->descriptor_item.item_size; 474 iterator->descriptor += iterator->descriptor_item.item_size; 475 iterator->item_ready = false; 476 return &iterator->descriptor_item; 477 } 478 479 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 480 return iterator->valid; 481 } 482 483 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) { 484 int total_report_size = 0; 485 int report_size = 0; 486 int report_count = 0; 487 int current_report_id = 0; 488 489 btstack_hid_descriptor_iterator_t iterator; 490 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 491 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 492 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 493 int valid_report_type = 0; 494 switch (item->item_type) { 495 case Global: 496 switch ((GlobalItemTag) item->item_tag) { 497 case ReportID: 498 current_report_id = item->item_value; 499 break; 500 case ReportCount: 501 report_count = item->item_value; 502 break; 503 case ReportSize: 504 report_size = item->item_value; 505 break; 506 default: 507 break; 508 } 509 break; 510 case Main: 511 if (current_report_id != report_id) break; 512 switch ((MainItemTag) item->item_tag) { 513 case Input: 514 if (report_type != HID_REPORT_TYPE_INPUT) break; 515 valid_report_type = 1; 516 break; 517 case Output: 518 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 519 valid_report_type = 1; 520 break; 521 case Feature: 522 if (report_type != HID_REPORT_TYPE_FEATURE) break; 523 valid_report_type = 1; 524 break; 525 default: 526 break; 527 } 528 if (!valid_report_type) break; 529 total_report_size += report_count * report_size; 530 break; 531 default: 532 break; 533 } 534 if (total_report_size > 0 && current_report_id != report_id) break; 535 } 536 537 if (btstack_hid_descriptor_iterator_valid(&iterator)){ 538 return (total_report_size + 7) / 8; 539 } else { 540 return 0; 541 } 542 } 543 544 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 545 int current_report_id = -1; 546 btstack_hid_descriptor_iterator_t iterator; 547 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 548 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 549 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 550 switch (item->item_type){ 551 case Global: 552 switch ((GlobalItemTag)item->item_tag){ 553 case ReportID: 554 current_report_id = item->item_value; 555 if (current_report_id != report_id) break; 556 return HID_REPORT_ID_VALID; 557 default: 558 break; 559 } 560 break; 561 default: 562 break; 563 } 564 } 565 566 if (btstack_hid_descriptor_iterator_valid(&iterator)) { 567 if (current_report_id != -1) { 568 return HID_REPORT_ID_INVALID; 569 } else { 570 return HID_REPORT_ID_UNDECLARED; 571 } 572 } else { 573 return HID_REPORT_ID_INVALID; 574 } 575 } 576 577 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 578 btstack_hid_descriptor_iterator_t iterator; 579 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 580 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 581 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 582 switch (item->item_type){ 583 case Global: 584 switch ((GlobalItemTag)item->item_tag){ 585 case ReportID: 586 return true; 587 default: 588 break; 589 } 590 break; 591 default: 592 break; 593 } 594 } 595 return false; 596 } 597