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 <string.h> 41 42 #include "btstack_hid_parser.h" 43 #include "btstack_util.h" 44 #include "btstack_debug.h" 45 46 // Not implemented: 47 // - Support for Push/Pop 48 // - Optional Pretty Print of HID Descripor 49 // - Support to query descriptort for contained usages, e.g. to detect keyboard or mouse 50 51 // #define HID_PARSER_PRETTY_PRINT 52 53 /* 54 * btstack_hid_parser.c 55 */ 56 57 #ifdef HID_PARSER_PRETTY_PRINT 58 59 static const char * type_names[] = { 60 "Main", 61 "Global", 62 "Local", 63 "Reserved" 64 }; 65 static const char * main_tags[] = { 66 "", 67 "", 68 "", 69 "", 70 "", 71 "", 72 "", 73 "", 74 "Input ", 75 "Output", 76 "Collection", 77 "Feature", 78 "End Collection", 79 "Reserved", 80 "Reserved", 81 "Reserved" 82 }; 83 static const char * global_tags[] = { 84 "Usage Page", 85 "Logical Minimum", 86 "Logical Maximum", 87 "Physical Minimum", 88 "Physical Maximum", 89 "Unit Exponent", 90 "Unit", 91 "Report Size", 92 "Report ID", 93 "Report Count", 94 "Push", 95 "Pop", 96 "Reserved", 97 "Reserved", 98 "Reserved", 99 "Reserved" 100 }; 101 static const char * local_tags[] = { 102 "Usage", 103 "Usage Minimum", 104 "Usage Maximum", 105 "Designator Index", 106 "Designator Minimum", 107 "Designator Maximum", 108 "String Index", 109 "String Minimum", 110 "String Maximum", 111 "Delimiter", 112 "Reserved", 113 "Reserved", 114 "Reserved", 115 "Reserved", 116 "Reserved", 117 "Reserved" 118 }; 119 #endif 120 121 static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 122 #ifdef HID_PARSER_PRETTY_PRINT 123 const char ** item_tag_table; 124 switch ((TagType)item->item_type){ 125 case Main: 126 item_tag_table = main_tags; 127 break; 128 case Global: 129 item_tag_table = global_tags; 130 break; 131 case Local: 132 item_tag_table = local_tags; 133 break; 134 default: 135 item_tag_table = NULL; 136 break; 137 } 138 const char * item_tag_name = "Invalid"; 139 if (item_tag_table){ 140 item_tag_name = item_tag_table[item->item_tag]; 141 } 142 log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); 143 #else 144 UNUSED(parser); 145 UNUSED(item); 146 #endif 147 } 148 149 // parse descriptor item and read up to 32-bit bit value 150 bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 151 152 const int hid_item_sizes[] = { 0, 1, 2, 4 }; 153 154 // parse item header 155 if (hid_descriptor_len < 1u) return false; 156 uint16_t pos = 0; 157 uint8_t item_header = hid_descriptor[pos++]; 158 item->data_size = hid_item_sizes[item_header & 0x03u]; 159 item->item_type = (item_header & 0x0cu) >> 2u; 160 item->item_tag = (item_header & 0xf0u) >> 4u; 161 // long item 162 if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){ 163 if (hid_descriptor_len < 3u) return false; 164 item->data_size = hid_descriptor[pos++]; 165 item->item_tag = hid_descriptor[pos++]; 166 } 167 item->item_size = pos + item->data_size; 168 item->item_value = 0; 169 170 // read item value 171 if (hid_descriptor_len < item->item_size) return false; 172 if (item->data_size > 4u) return false; 173 int i; 174 int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u); 175 int32_t value = 0; 176 uint8_t latest_byte = 0; 177 for (i=0;i<item->data_size;i++){ 178 latest_byte = hid_descriptor[pos++]; 179 value = (latest_byte << (8*i)) | value; 180 } 181 if (sgnd && (item->data_size > 0u)){ 182 if (latest_byte & 0x80u) { 183 value -= 1u << (item->data_size*8u); 184 } 185 } 186 item->item_value = value; 187 return true; 188 } 189 190 static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 191 switch((GlobalItemTag)item->item_tag){ 192 case UsagePage: 193 parser->global_usage_page = item->item_value; 194 break; 195 case LogicalMinimum: 196 parser->global_logical_minimum = item->item_value; 197 break; 198 case LogicalMaximum: 199 parser->global_logical_maximum = item->item_value; 200 break; 201 case ReportSize: 202 parser->global_report_size = item->item_value; 203 break; 204 case ReportID: 205 if (parser->active_record && (parser->global_report_id != item->item_value)){ 206 parser->active_record = 0; 207 } 208 parser->global_report_id = item->item_value; 209 break; 210 case ReportCount: 211 parser->global_report_count = item->item_value; 212 break; 213 214 // TODO handle tags 215 case PhysicalMinimum: 216 case PhysicalMaximum: 217 case UnitExponent: 218 case Unit: 219 case Push: 220 case Pop: 221 break; 222 223 default: 224 btstack_assert(false); 225 break; 226 } 227 } 228 229 static void hid_find_next_usage(btstack_hid_parser_t * parser){ 230 bool have_usage_min = false; 231 bool have_usage_max = false; 232 parser->usage_range = false; 233 while ((parser->available_usages == 0u) && (parser->usage_pos < parser->descriptor_pos)){ 234 hid_descriptor_item_t usage_item; 235 // parser->usage_pos < parser->descriptor_pos < parser->descriptor_len 236 bool ok = btstack_hid_parse_descriptor_item(&usage_item, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 237 if (ok == false){ 238 break; 239 } 240 if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 241 parser->usage_page = usage_item.item_value; 242 } 243 if (usage_item.item_type == Local){ 244 uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); 245 switch (usage_item.item_tag){ 246 case Usage: 247 parser->available_usages = 1; 248 parser->usage_minimum = usage_value; 249 break; 250 case UsageMinimum: 251 parser->usage_minimum = usage_value; 252 have_usage_min = true; 253 break; 254 case UsageMaximum: 255 parser->usage_maximum = usage_value; 256 have_usage_max = true; 257 break; 258 default: 259 break; 260 } 261 if (have_usage_min && have_usage_max){ 262 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; 263 parser->usage_range = true; 264 if (parser->available_usages < parser->required_usages){ 265 log_debug("Usage Min - Usage Max [%04x..%04x] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); 266 } 267 } 268 } 269 parser->usage_pos += usage_item.item_size; 270 } 271 } 272 273 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 274 hid_pretty_print_item(parser, item); 275 int valid_field = 0; 276 switch ((TagType)item->item_type){ 277 case Main: 278 switch ((MainItemTag)item->item_tag){ 279 case Input: 280 valid_field = parser->report_type == HID_REPORT_TYPE_INPUT; 281 break; 282 case Output: 283 valid_field = parser->report_type == HID_REPORT_TYPE_OUTPUT; 284 break; 285 case Feature: 286 valid_field = parser->report_type == HID_REPORT_TYPE_FEATURE; 287 break; 288 default: 289 break; 290 } 291 break; 292 case Global: 293 btstack_hid_handle_global_item(parser, item); 294 break; 295 case Local: 296 case Reserved: 297 break; 298 default: 299 btstack_assert(false); 300 break; 301 } 302 if (!valid_field) return; 303 304 // verify record id 305 if (parser->global_report_id && !parser->active_record){ 306 if (parser->report[0] != parser->global_report_id){ 307 return; 308 } 309 parser->report_pos_in_bit += 8u; 310 } 311 parser->active_record = 1; 312 // handle constant fields used for padding 313 if (item->item_value & 1){ 314 int item_bits = parser->global_report_size * parser->global_report_count; 315 #ifdef HID_PARSER_PRETTY_PRINT 316 log_info("- Skip %u constant bits", item_bits); 317 #endif 318 parser->report_pos_in_bit += item_bits; 319 return; 320 } 321 // Empty Item 322 if (parser->global_report_count == 0u) return; 323 // let's start 324 parser->required_usages = parser->global_report_count; 325 } 326 327 static void hid_post_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 328 if ((TagType)item->item_type == Main){ 329 // reset usage 330 parser->usage_pos = parser->descriptor_pos; 331 parser->usage_page = parser->global_usage_page; 332 } 333 parser->descriptor_pos += item->item_size; 334 } 335 336 static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){ 337 while (parser->state == BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM){ 338 if (parser->descriptor_pos >= parser->descriptor_len){ 339 // end of descriptor 340 parser->state = BTSTACK_HID_PARSER_COMPLETE; 341 break; 342 } 343 btstack_hid_parse_descriptor_item(&parser->descriptor_item, &parser->descriptor[parser->descriptor_pos], parser->descriptor_len - parser->descriptor_pos); 344 hid_process_item(parser, &parser->descriptor_item); 345 if (parser->required_usages){ 346 hid_find_next_usage(parser); 347 if (parser->available_usages) { 348 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 349 } else { 350 log_debug("no usages found"); 351 parser->state = BTSTACK_HID_PARSER_COMPLETE; 352 } 353 } else { 354 hid_post_process_item(parser, &parser->descriptor_item); 355 } 356 } 357 } 358 359 // PUBLIC API 360 361 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){ 362 363 memset(parser, 0, sizeof(btstack_hid_parser_t)); 364 365 parser->descriptor = hid_descriptor; 366 parser->descriptor_len = hid_descriptor_len; 367 parser->report_type = hid_report_type; 368 parser->report = hid_report; 369 parser->report_len = hid_report_len; 370 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 371 372 btstack_hid_parser_find_next_usage(parser); 373 } 374 375 int btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 376 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 377 } 378 379 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 380 381 *usage_page = parser->usage_minimum >> 16; 382 383 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 384 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 385 bool is_signed = parser->global_logical_minimum < 0; 386 int pos_start = btstack_min( parser->report_pos_in_bit >> 3, parser->report_len); 387 int pos_end = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len); 388 int bytes_to_read = pos_end - pos_start + 1; 389 int i; 390 uint32_t multi_byte_value = 0; 391 for (i=0;i < bytes_to_read;i++){ 392 multi_byte_value |= parser->report[pos_start+i] << (i*8); 393 } 394 uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u); 395 // 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); 396 if (is_variable){ 397 *usage = parser->usage_minimum & 0xffffu; 398 if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){ 399 *value = unsigned_value - (1u<<parser->global_report_size); 400 } else { 401 *value = unsigned_value; 402 } 403 } else { 404 *usage = unsigned_value; 405 *value = 1; 406 } 407 parser->required_usages--; 408 parser->report_pos_in_bit += parser->global_report_size; 409 410 // next usage 411 if (is_variable){ 412 parser->usage_minimum++; 413 parser->available_usages--; 414 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 415 // usage min - max range smaller than report count, ignore remaining bit in report 416 log_debug("Ignoring %u items without Usage", parser->required_usages); 417 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 418 parser->required_usages = 0; 419 } 420 } else { 421 if (parser->required_usages == 0u){ 422 parser->available_usages = 0; 423 } 424 } 425 if (parser->available_usages) { 426 return; 427 } 428 if (parser->required_usages == 0u){ 429 hid_post_process_item(parser, &parser->descriptor_item); 430 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 431 btstack_hid_parser_find_next_usage(parser); 432 } else { 433 hid_find_next_usage(parser); 434 if (parser->available_usages == 0u) { 435 parser->state = BTSTACK_HID_PARSER_COMPLETE; 436 } 437 } 438 } 439 440 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){ 441 int total_report_size = 0; 442 int report_size = 0; 443 int report_count = 0; 444 int current_report_id = 0; 445 446 while (hid_descriptor_len){ 447 int valid_report_type = 0; 448 hid_descriptor_item_t item; 449 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 450 if (ok == false) { 451 return 0; 452 } 453 switch (item.item_type){ 454 case Global: 455 switch ((GlobalItemTag)item.item_tag){ 456 case ReportID: 457 current_report_id = item.item_value; 458 break; 459 case ReportCount: 460 report_count = item.item_value; 461 break; 462 case ReportSize: 463 report_size = item.item_value; 464 break; 465 default: 466 break; 467 } 468 break; 469 case Main: 470 if (current_report_id != report_id) break; 471 switch ((MainItemTag)item.item_tag){ 472 case Input: 473 if (report_type != HID_REPORT_TYPE_INPUT) break; 474 valid_report_type = 1; 475 break; 476 case Output: 477 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 478 valid_report_type = 1; 479 break; 480 case Feature: 481 if (report_type != HID_REPORT_TYPE_FEATURE) break; 482 valid_report_type = 1; 483 break; 484 default: 485 break; 486 } 487 if (!valid_report_type) break; 488 total_report_size += report_count * report_size; 489 break; 490 default: 491 break; 492 } 493 if (total_report_size > 0 && current_report_id != report_id) break; 494 hid_descriptor_len -= item.item_size; 495 hid_descriptor += item.item_size; 496 } 497 return (total_report_size + 7)/8; 498 } 499 500 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 501 int current_report_id = 0; 502 while (hid_descriptor_len){ 503 hid_descriptor_item_t item; 504 bool ok = btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 505 if (ok == false){ 506 return HID_REPORT_ID_INVALID; 507 } 508 switch (item.item_type){ 509 case Global: 510 switch ((GlobalItemTag)item.item_tag){ 511 case ReportID: 512 current_report_id = item.item_value; 513 if (current_report_id != report_id) break; 514 return HID_REPORT_ID_VALID; 515 default: 516 break; 517 } 518 break; 519 default: 520 break; 521 } 522 hid_descriptor_len -= item.item_size; 523 hid_descriptor += item.item_size; 524 } 525 if (current_report_id != 0) return HID_REPORT_ID_INVALID; 526 return HID_REPORT_ID_UNDECLARED; 527 } 528 529 int btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 530 while (hid_descriptor_len){ 531 hid_descriptor_item_t item; 532 btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 533 switch (item.item_type){ 534 case Global: 535 switch ((GlobalItemTag)item.item_tag){ 536 case ReportID: 537 return 1; 538 default: 539 break; 540 } 541 break; 542 default: 543 break; 544 } 545 hid_descriptor_len -= item.item_size; 546 hid_descriptor += item.item_size; 547 } 548 return 0; 549 } 550