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