diff --git a/src/btstack_hid_parser.c b/src/btstack_hid_parser.c index 68f300482..24c66bd2d 100644 --- a/src/btstack_hid_parser.c +++ b/src/btstack_hid_parser.c @@ -118,7 +118,7 @@ static const char * local_tags[] = { }; #endif -static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ +static void hid_pretty_print_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){ #ifdef HID_PARSER_PRETTY_PRINT const char ** item_tag_table; switch ((TagType)item->item_type){ @@ -139,9 +139,9 @@ static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_ if (item_tag_table){ item_tag_name = item_tag_table[item->item_tag]; } - log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); + log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], iterator->descriptor[iterator->descriptor_pos], item->item_value); #else - UNUSED(parser); + UNUSED(iterator); UNUSED(item); #endif } @@ -200,25 +200,25 @@ static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_r } } -static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ +static void btstack_hid_handle_global_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){ switch((GlobalItemTag)item->item_tag){ case UsagePage: - parser->global_usage_page = item->item_value; + iterator->global_usage_page = item->item_value; break; case LogicalMinimum: - parser->global_logical_minimum = item->item_value; + iterator->global_logical_minimum = item->item_value; break; case LogicalMaximum: - parser->global_logical_maximum = item->item_value; + iterator->global_logical_maximum = item->item_value; break; case ReportSize: - parser->global_report_size = item->item_value; + iterator->global_report_size = item->item_value; break; case ReportID: - parser->global_report_id = item->item_value; + iterator->global_report_id = item->item_value; break; case ReportCount: - parser->global_report_count = item->item_value; + iterator->global_report_count = item->item_value; break; // TODO handle tags @@ -236,97 +236,47 @@ static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_de } } -static void hid_find_next_usage(btstack_hid_parser_t * parser){ +static void hid_find_next_usage(btstack_hid_usage_iterator_t * main_iterator){ bool have_usage_min = false; bool have_usage_max = false; - parser->usage_range = false; + main_iterator->usage_range = false; btstack_hid_descriptor_iterator_t iterator; - btstack_hid_descriptor_iterator_init(&iterator, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); - while ((parser->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ + btstack_hid_descriptor_iterator_init(&iterator, &main_iterator->descriptor[main_iterator->usage_pos], main_iterator->descriptor_len - main_iterator->usage_pos); + while ((main_iterator->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator); if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ - parser->usage_page = usage_item.item_value; + main_iterator->usage_page = usage_item.item_value; } if (usage_item.item_type == Local){ - uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); + uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((main_iterator->usage_page << 16u) | usage_item.item_value); switch (usage_item.item_tag){ case Usage: - parser->available_usages = 1; - parser->usage_minimum = usage_value; + main_iterator->available_usages = 1; + main_iterator->usage_minimum = usage_value; break; case UsageMinimum: - parser->usage_minimum = usage_value; + main_iterator->usage_minimum = usage_value; have_usage_min = true; break; case UsageMaximum: - parser->usage_maximum = usage_value; + main_iterator->usage_maximum = usage_value; have_usage_max = true; break; default: break; } if (have_usage_min && have_usage_max){ - parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; - parser->usage_range = true; - if (parser->available_usages < parser->required_usages){ - log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); + main_iterator->available_usages = main_iterator->usage_maximum - main_iterator->usage_minimum + 1u; + main_iterator->usage_range = true; + if (main_iterator->available_usages < main_iterator->required_usages){ + log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", main_iterator->usage_minimum & 0xffff, main_iterator->usage_maximum & 0xffff, main_iterator->required_usages); } } } } - parser->usage_pos += iterator.descriptor_pos; + main_iterator->usage_pos += iterator.descriptor_pos; } -static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ - hid_pretty_print_item(parser, item); - int valid_field = 0; - uint16_t report_id_before; - switch ((TagType)item->item_type){ - case Main: - valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, - parser->report_type); - break; - case Global: - report_id_before = parser->global_report_id; - btstack_hid_handle_global_item(parser, item); - // track record id for report handling - if ((GlobalItemTag)item->item_tag == ReportID){ - if (parser->active_record && (report_id_before != item->item_value)){ - parser->active_record = 0; - } - } - break; - case Local: - case Reserved: - break; - default: - btstack_assert(false); - break; - } - if (!valid_field) return; - - // verify record id - if (parser->global_report_id && !parser->active_record){ - if (parser->report[0] != parser->global_report_id){ - return; - } - parser->report_pos_in_bit += 8u; - } - parser->active_record = 1; - // handle constant fields used for padding - if (item->item_value & 1){ - int item_bits = parser->global_report_size * parser->global_report_count; -#ifdef HID_PARSER_PRETTY_PRINT - log_info("- Skip %u constant bits", item_bits); -#endif - parser->report_pos_in_bit += item_bits; - return; - } - // Empty Item - if (parser->global_report_count == 0u) return; - // let's start - parser->required_usages = parser->global_report_count; -} // PUBLIC API @@ -487,21 +437,21 @@ bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_ // HID Descriptor Usage Iterator -static void btstack_parser_usage_iterator_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ - hid_pretty_print_item(parser, item); +static void btstack_parser_usage_iterator_process_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){ + hid_pretty_print_item(iterator, item); int valid_field = 0; uint16_t report_id_before; switch ((TagType)item->item_type){ case Main: valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, - parser->report_type); + iterator->report_type); break; case Global: - report_id_before = parser->global_report_id; - btstack_hid_handle_global_item(parser, item); + report_id_before = iterator->global_report_id; + btstack_hid_handle_global_item(iterator, item); // track record id for report handling, reset report position - if (report_id_before != parser->global_report_id){ - parser->report_pos_in_bit = 8u; + if (report_id_before != iterator->global_report_id){ + iterator->report_pos_in_bit = 8u; } break; case Local: @@ -515,109 +465,109 @@ static void btstack_parser_usage_iterator_process_item(btstack_hid_parser_t * pa // handle constant fields used for padding if (item->item_value & 1){ - int item_bits = parser->global_report_size * parser->global_report_count; + int item_bits = iterator->global_report_size * iterator->global_report_count; #ifdef HID_PARSER_PRETTY_PRINT log_info("- Skip %u constant bits", item_bits); #endif - parser->report_pos_in_bit += item_bits; + iterator->report_pos_in_bit += item_bits; return; } // Empty Item - if (parser->global_report_count == 0u) return; + if (iterator->global_report_count == 0u) return; // let's start - parser->required_usages = parser->global_report_count; + iterator->required_usages = iterator->global_report_count; } -static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_parser_t * parser) { - while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){ - parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator); +static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_usage_iterator_t * iterator) { + while (btstack_hid_descriptor_iterator_has_more(&iterator->descriptor_iterator)){ + iterator->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&iterator->descriptor_iterator); - btstack_parser_usage_iterator_process_item(parser, &parser->descriptor_item); + btstack_parser_usage_iterator_process_item(iterator, &iterator->descriptor_item); - if (parser->required_usages){ - hid_find_next_usage(parser); - if (parser->available_usages) { - parser->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; + if (iterator->required_usages){ + hid_find_next_usage(iterator); + if (iterator->available_usages) { + iterator->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; return; } else { log_debug("no usages found"); - parser->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; + iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; return; } } else { - if ((TagType) (&parser->descriptor_item)->item_type == Main) { + if ((TagType) (&iterator->descriptor_item)->item_type == Main) { // reset usage - parser->usage_pos = parser->descriptor_iterator.descriptor_pos; - parser->usage_page = parser->global_usage_page; + iterator->usage_pos = iterator->descriptor_iterator.descriptor_pos; + iterator->usage_page = iterator->global_usage_page; } } } // end of descriptor - parser->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; + iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; } -void btstack_hid_usage_iterator_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type){ - memset(parser, 0, sizeof(btstack_hid_parser_t)); +void btstack_hid_usage_iterator_init(btstack_hid_usage_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type){ + memset(iterator, 0, sizeof(btstack_hid_usage_iterator_t)); - parser->descriptor = hid_descriptor; - parser->descriptor_len = hid_descriptor_len; - parser->report_type = hid_report_type; - parser->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; - parser->global_report_id = HID_REPORT_ID_UNDEFINED; - btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len); + iterator->descriptor = hid_descriptor; + iterator->descriptor_len = hid_descriptor_len; + iterator->report_type = hid_report_type; + iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; + iterator->global_report_id = HID_REPORT_ID_UNDEFINED; + btstack_hid_descriptor_iterator_init(&iterator->descriptor_iterator, hid_descriptor, hid_descriptor_len); } -bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser){ - while (parser->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){ - btstack_hid_usage_iterator_find_next_usage(parser); +bool btstack_hid_usage_iterator_has_more(btstack_hid_usage_iterator_t * iterator){ + while (iterator->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){ + btstack_hid_usage_iterator_find_next_usage(iterator); } - return parser->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; + return iterator->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; } -void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item){ +void btstack_hid_usage_iterator_get_item(btstack_hid_usage_iterator_t * iterator, btstack_hid_usage_item_t * item){ // cache current values memset(item, 0, sizeof(btstack_hid_usage_item_t)); - item->size = parser->global_report_size; - item->report_id = parser->global_report_id; - item->usage_page = parser->usage_minimum >> 16; - item->bit_pos = parser->report_pos_in_bit; + item->size = iterator->global_report_size; + item->report_id = iterator->global_report_id; + item->usage_page = iterator->usage_minimum >> 16; + item->bit_pos = iterator->report_pos_in_bit; - bool is_variable = (parser->descriptor_item.item_value & 2) != 0; + bool is_variable = (iterator->descriptor_item.item_value & 2) != 0; if (is_variable){ - item->usage = parser->usage_minimum & 0xffffu; + item->usage = iterator->usage_minimum & 0xffffu; } - parser->required_usages--; - parser->report_pos_in_bit += parser->global_report_size; + iterator->required_usages--; + iterator->report_pos_in_bit += iterator->global_report_size; // cache descriptor item and - item->descriptor_item = parser->descriptor_item; - item->global_logical_minimum = parser->global_logical_minimum; + item->descriptor_item = iterator->descriptor_item; + item->global_logical_minimum = iterator->global_logical_minimum; // next usage if (is_variable){ - parser->usage_minimum++; - parser->available_usages--; - if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ + iterator->usage_minimum++; + iterator->available_usages--; + if (iterator->usage_range && (iterator->usage_minimum > iterator->usage_maximum)){ // usage min - max range smaller than report count, ignore remaining bit in report log_debug("Ignoring %u items without Usage", parser->required_usages); - parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; - parser->required_usages = 0; + iterator->report_pos_in_bit += iterator->global_report_size * iterator->required_usages; + iterator->required_usages = 0; } } else { - if (parser->required_usages == 0u){ - parser->available_usages = 0; + if (iterator->required_usages == 0u){ + iterator->available_usages = 0; } } - if (parser->available_usages) { + if (iterator->available_usages) { return; } - if (parser->required_usages == 0u){ - parser->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; + if (iterator->required_usages == 0u){ + iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; } else { - hid_find_next_usage(parser); - if (parser->available_usages == 0u) { - parser->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; + hid_find_next_usage(iterator); + if (iterator->available_usages == 0u) { + iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; } } } @@ -626,7 +576,7 @@ void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_ // HID Report Parser 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){ - btstack_hid_usage_iterator_init(parser, hid_descriptor, hid_descriptor_len, hid_report_type); + btstack_hid_usage_iterator_init(&parser->usage_iterator, hid_descriptor, hid_descriptor_len, hid_report_type); parser->report = hid_report; parser->report_len = hid_report_len; parser->have_report_usage_ready = false; @@ -637,8 +587,8 @@ void btstack_hid_parser_init(btstack_hid_parser_t * parser, const uint8_t * hid_ * @param parser */ bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ - while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(parser)){ - btstack_hid_usage_iterator_get_item(parser, &parser->descriptor__usage_item); + while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(&parser->usage_iterator)){ + btstack_hid_usage_iterator_get_item(&parser->usage_iterator, &parser->descriptor__usage_item); // ignore usages for other report ids if (parser->descriptor__usage_item.report_id != HID_REPORT_ID_UNDEFINED){ if (parser->descriptor__usage_item.report_id != parser->report[0]){ diff --git a/src/btstack_hid_parser.h b/src/btstack_hid_parser.h index 54033d3c7..926488646 100644 --- a/src/btstack_hid_parser.h +++ b/src/btstack_hid_parser.h @@ -115,6 +115,7 @@ typedef struct { hid_descriptor_item_t descriptor_item; } btstack_hid_descriptor_iterator_t; + typedef enum { BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM, BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE, @@ -122,33 +123,17 @@ typedef enum { } btstack_hid_usage_iterator_state_t; typedef struct { - uint16_t report_id; // 8-bit report ID or 0xffff if not set - uint16_t bit_pos; // position in bit - uint16_t usage_page; - uint16_t usage; - uint8_t size; // in bit - // cached values of relevant descriptor item (input,output,feature) - hid_descriptor_item_t descriptor_item; - int32_t global_logical_minimum; -} btstack_hid_usage_item_t; - -typedef struct { - // Descriptor const uint8_t * descriptor; uint16_t descriptor_len; btstack_hid_descriptor_iterator_t descriptor_iterator; - // Report - hid_report_type_t report_type; - const uint8_t * report; - uint16_t report_len; - // State btstack_hid_usage_iterator_state_t state; hid_descriptor_item_t descriptor_item; + hid_report_type_t report_type; uint16_t report_pos_in_bit; // usage pos and usage_page after last main item, used to find next usage @@ -158,7 +143,7 @@ typedef struct { // usage generator uint32_t usage_minimum; uint32_t usage_maximum; - uint16_t available_usages; + uint16_t available_usages; uint16_t required_usages; bool usage_range; uint8_t active_record; @@ -166,14 +151,35 @@ typedef struct { // global int32_t global_logical_minimum; int32_t global_logical_maximum; - uint16_t global_usage_page; + uint16_t global_usage_page; uint8_t global_report_size; uint8_t global_report_count; uint16_t global_report_id; - // for HID Parser +} btstack_hid_usage_iterator_t; + +typedef struct { + uint16_t report_id; // 8-bit report ID or 0xffff if not set + uint16_t bit_pos; // position in bit + uint16_t usage_page; + uint16_t usage; + uint8_t size; // in bit + + // cached values of relevant descriptor item (input,output,feature) + hid_descriptor_item_t descriptor_item; + int32_t global_logical_minimum; +} btstack_hid_usage_item_t; + + +typedef struct { + btstack_hid_usage_iterator_t usage_iterator; + + const uint8_t * report; + uint16_t report_len; + bool have_report_usage_ready; btstack_hid_usage_item_t descriptor__usage_item; + } btstack_hid_parser_t; @@ -220,20 +226,20 @@ bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * i * @param hid_descriptor_len * @param hid_report_type */ -void btstack_hid_usage_iterator_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type); +void btstack_hid_usage_iterator_init(btstack_hid_usage_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type); /** * @brief Checks if more usages are available * @param parser */ -bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser); +bool btstack_hid_usage_iterator_has_more(btstack_hid_usage_iterator_t * iterator); /** * @brief Get current usage item * @param parser * @param item */ -void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item); +void btstack_hid_usage_iterator_get_item(btstack_hid_usage_iterator_t * iterator, btstack_hid_usage_item_t * item); // HID Report Iterator diff --git a/test/hid_parser/hid_parser_test.cpp b/test/hid_parser/hid_parser_test.cpp index 67abfe46c..7f652c904 100644 --- a/test/hid_parser/hid_parser_test.cpp +++ b/test/hid_parser/hid_parser_test.cpp @@ -584,11 +584,11 @@ TEST(HID, GetReportSize){ TEST(HID, UsageIteratorBootKeyboard){ const uint8_t * hid_descriptor = hid_descriptor_keyboard_boot_mode; uint16_t hid_descriptor_len = sizeof(hid_descriptor_keyboard_boot_mode); - btstack_hid_parser_t parser; - btstack_hid_usage_iterator_init(&parser, hid_descriptor, hid_descriptor_len, HID_REPORT_TYPE_INPUT); - while (btstack_hid_usage_iterator_has_more(&parser)){ + btstack_hid_usage_iterator_t iterator; + btstack_hid_usage_iterator_init(&iterator, hid_descriptor, hid_descriptor_len, HID_REPORT_TYPE_INPUT); + while (btstack_hid_usage_iterator_has_more(&iterator)){ btstack_hid_usage_item_t item; - btstack_hid_usage_iterator_get_item(&parser, &item); + btstack_hid_usage_iterator_get_item(&iterator, &item); // printf("Report ID 0x%04x, bitpos %3u, usage page 0x%04x, usage 0x%04x, size %u\n", item.report_id, item.bit_pos, item.usage_page, item.usage, item.size); } } @@ -596,11 +596,11 @@ TEST(HID, UsageIteratorBootKeyboard){ TEST(HID, UsageIteratorCombo1){ const uint8_t * hid_descriptor = combo_descriptor_with_report_ids; uint16_t hid_descriptor_len = sizeof(combo_descriptor_with_report_ids); - btstack_hid_parser_t parser; - btstack_hid_usage_iterator_init(&parser, hid_descriptor, hid_descriptor_len, HID_REPORT_TYPE_INPUT); - while (btstack_hid_usage_iterator_has_more(&parser)){ + btstack_hid_usage_iterator_t iterator; + btstack_hid_usage_iterator_init(&iterator, hid_descriptor, hid_descriptor_len, HID_REPORT_TYPE_INPUT); + while (btstack_hid_usage_iterator_has_more(&iterator)){ btstack_hid_usage_item_t item; - btstack_hid_usage_iterator_get_item(&parser, &item); + btstack_hid_usage_iterator_get_item(&iterator, &item); // printf("Report ID 0x%04x, bitpos %3u, usage page 0x%04x, usage 0x%04x, size %u\n", item.report_id, item.bit_pos, item.usage_page, item.usage, item.size); } }