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 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){ 452 int total_report_size = 0; 453 int report_size = 0; 454 int report_count = 0; 455 int current_report_id = 0; 456 457 while (hid_descriptor_len){ 458 int valid_report_type = 0; 459 hid_descriptor_item_t item; 460 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 461 if (ok == false) { 462 return 0; 463 } 464 switch (item.item_type){ 465 case Global: 466 switch ((GlobalItemTag)item.item_tag){ 467 case ReportID: 468 current_report_id = item.item_value; 469 break; 470 case ReportCount: 471 report_count = item.item_value; 472 break; 473 case ReportSize: 474 report_size = item.item_value; 475 break; 476 default: 477 break; 478 } 479 break; 480 case Main: 481 if (current_report_id != report_id) break; 482 switch ((MainItemTag)item.item_tag){ 483 case Input: 484 if (report_type != HID_REPORT_TYPE_INPUT) break; 485 valid_report_type = 1; 486 break; 487 case Output: 488 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 489 valid_report_type = 1; 490 break; 491 case Feature: 492 if (report_type != HID_REPORT_TYPE_FEATURE) break; 493 valid_report_type = 1; 494 break; 495 default: 496 break; 497 } 498 if (!valid_report_type) break; 499 total_report_size += report_count * report_size; 500 break; 501 default: 502 break; 503 } 504 if (total_report_size > 0 && current_report_id != report_id) break; 505 hid_descriptor_len -= item.item_size; 506 hid_descriptor += item.item_size; 507 } 508 return (total_report_size + 7)/8; 509 } 510 511 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 512 int current_report_id = 0; 513 while (hid_descriptor_len){ 514 hid_descriptor_item_t item; 515 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 516 if (ok == false){ 517 return HID_REPORT_ID_INVALID; 518 } 519 switch (item.item_type){ 520 case Global: 521 switch ((GlobalItemTag)item.item_tag){ 522 case ReportID: 523 current_report_id = item.item_value; 524 if (current_report_id != report_id) break; 525 return HID_REPORT_ID_VALID; 526 default: 527 break; 528 } 529 break; 530 default: 531 break; 532 } 533 hid_descriptor_len -= item.item_size; 534 hid_descriptor += item.item_size; 535 } 536 if (current_report_id != 0) return HID_REPORT_ID_INVALID; 537 return HID_REPORT_ID_UNDECLARED; 538 } 539 540 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 541 while (hid_descriptor_len){ 542 hid_descriptor_item_t item; 543 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 544 if (ok == false){ 545 break; 546 } 547 switch (item.item_type){ 548 case Global: 549 switch ((GlobalItemTag)item.item_tag){ 550 case ReportID: 551 return true; 552 default: 553 break; 554 } 555 break; 556 default: 557 break; 558 } 559 hid_descriptor_len -= item.item_size; 560 hid_descriptor += item.item_size; 561 } 562 return false; 563 } 564