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