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