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