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