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 btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 447 switch (item.item_type){ 448 case Global: 449 switch ((GlobalItemTag)item.item_tag){ 450 case ReportID: 451 current_report_id = item.item_value; 452 break; 453 case ReportCount: 454 report_count = item.item_value; 455 break; 456 case ReportSize: 457 report_size = item.item_value; 458 break; 459 default: 460 break; 461 } 462 break; 463 case Main: 464 if (current_report_id != report_id) break; 465 switch ((MainItemTag)item.item_tag){ 466 case Input: 467 if (report_type != HID_REPORT_TYPE_INPUT) break; 468 valid_report_type = 1; 469 break; 470 case Output: 471 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 472 valid_report_type = 1; 473 break; 474 case Feature: 475 if (report_type != HID_REPORT_TYPE_FEATURE) break; 476 valid_report_type = 1; 477 break; 478 default: 479 break; 480 } 481 if (!valid_report_type) break; 482 total_report_size += report_count * report_size; 483 break; 484 default: 485 break; 486 } 487 if (total_report_size > 0 && current_report_id != report_id) break; 488 hid_descriptor_len -= item.item_size; 489 hid_descriptor += item.item_size; 490 } 491 return (total_report_size + 7)/8; 492 } 493 494 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 495 int current_report_id = 0; 496 while (hid_descriptor_len){ 497 hid_descriptor_item_t item; 498 btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 499 switch (item.item_type){ 500 case Global: 501 switch ((GlobalItemTag)item.item_tag){ 502 case ReportID: 503 current_report_id = item.item_value; 504 if (current_report_id != report_id) break; 505 return HID_REPORT_ID_VALID; 506 default: 507 break; 508 } 509 break; 510 default: 511 break; 512 } 513 hid_descriptor_len -= item.item_size; 514 hid_descriptor += item.item_size; 515 } 516 if (current_report_id != 0) return HID_REPORT_ID_INVALID; 517 return HID_REPORT_ID_UNDECLARED; 518 } 519 520 int btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 521 while (hid_descriptor_len){ 522 hid_descriptor_item_t item; 523 btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len); 524 switch (item.item_type){ 525 case Global: 526 switch ((GlobalItemTag)item.item_tag){ 527 case ReportID: 528 return 1; 529 default: 530 break; 531 } 532 break; 533 default: 534 break; 535 } 536 hid_descriptor_len -= item.item_size; 537 hid_descriptor += item.item_size; 538 } 539 return 0; 540 } 541