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