btstack_hid_parser: add function that calculates report size for given report type and ID from report descriptor

This commit is contained in:
Milanka Ringwald 2018-10-09 16:44:49 +02:00
parent 6cdc2862f6
commit fada717989
4 changed files with 141 additions and 45 deletions

View File

@ -54,50 +54,6 @@
* btstack_hid_parser.c
*/
typedef enum {
Main=0,
Global,
Local,
Reserved
} TagType;
typedef enum {
Input=8,
Output,
Coll,
Feature,
EndColl
} MainItemTag;
typedef enum {
UsagePage,
LogicalMinimum,
LogicalMaximum,
PhysicalMinimum,
PhysicalMaximum,
UnitExponent,
Unit,
ReportSize,
ReportID,
ReportCount,
Push,
Pop
} GlobalItemTag;
typedef enum {
Usage,
UsageMinimum,
UsageMaximum,
DesignatorIndex,
DesignatorMinimum,
DesignatorMaximum,
StringIndex,
StringMinimum,
StringMaximum,
Delimiter
} LocalItemTag;
const int hid_item_sizes[] = { 0, 1, 2, 4 };
#ifdef HID_PARSER_PRETTY_PRINT
@ -193,7 +149,7 @@ static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_
}
// parse descriptor item and read up to 32-bit bit value
static void btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
void btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){
// parse item header
if (hid_descriptor_len < 1) return;
uint16_t pos = 0;
@ -451,3 +407,65 @@ void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usag
}
}
}
int btstack_hid_get_report_size_for_id(int report_id, btstack_hid_report_type_t report_type, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){
int total_report_size = 0;
int report_size = 0;
int report_count = 0;
int current_report_id = 0;
while (hid_descriptor_len){
int valid_report_type = 0;
hid_descriptor_item_t item;
// printf("item: 0x%02x (%p)\n", *hid_descriptor, hid_descriptor);
btstack_hid_parse_descriptor_item(&item, hid_descriptor, hid_descriptor_len);
switch (item.item_type){
case Global:
switch ((GlobalItemTag)item.item_tag){
case ReportID:
current_report_id = item.item_value;
break;
case ReportCount:
if (current_report_id != report_id) break;
report_count = item.item_value;
break;
case ReportSize:
if (current_report_id != report_id) break;
report_size = item.item_value;
break;
default:
break;
}
break;
case Main:
if (current_report_id != report_id) break;
// printf("tag %d, report_type %d\n", item.item_tag, report_type);
switch ((MainItemTag)item.item_tag){
case Input:
if (report_type != BTSTACK_HID_REPORT_TYPE_INPUT) break;
valid_report_type = 1;
break;
case Output:
if (report_type != BTSTACK_HID_REPORT_TYPE_OUTPUT) break;
valid_report_type = 1;
break;
case Feature:
if (report_type != BTSTACK_HID_REPORT_TYPE_FEATURE) break;
valid_report_type = 1;
break;
default:
break;
}
if (!valid_report_type) break;
total_report_size += report_count * report_size;
report_size = 0;
report_count = 0;
break;
default:
break;
}
hid_descriptor_len -= item.item_size;
hid_descriptor += item.item_size;
}
return (total_report_size + 7)/8;
}

View File

@ -50,6 +50,49 @@
extern "C" {
#endif
typedef enum {
Main=0,
Global,
Local,
Reserved
} TagType;
typedef enum {
Input=8,
Output,
Coll,
Feature,
EndColl
} MainItemTag;
typedef enum {
UsagePage,
LogicalMinimum,
LogicalMaximum,
PhysicalMinimum,
PhysicalMaximum,
UnitExponent,
Unit,
ReportSize,
ReportID,
ReportCount,
Push,
Pop
} GlobalItemTag;
typedef enum {
Usage,
UsageMinimum,
UsageMaximum,
DesignatorIndex,
DesignatorMinimum,
DesignatorMaximum,
StringIndex,
StringMinimum,
StringMaximum,
Delimiter
} LocalItemTag;
typedef struct {
int32_t item_value;
uint16_t item_size;
@ -140,6 +183,22 @@ int btstack_hid_parser_has_more(btstack_hid_parser_t * parser);
*/
void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value);
/**
* @brief Parses descriptor item
* @param item
* @param hid_descriptor
* @param hid_descriptor_len
*/
void btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len);
/**
* @brief Parses descriptor and returns report size for given report ID and report type
* @param report_id
* @param report_type
* @param hid_descriptor_len
* @param hid_descriptor
*/
int btstack_hid_get_report_size_for_id(int report_id, btstack_hid_report_type_t report_type, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor);
/* API_END */
#if defined __cplusplus

1
test/hid_parser/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
hid_parser_test

View File

@ -218,6 +218,8 @@ const uint8_t keyboard_report1[] = { 0x01, 0x00, 0x04, 0x05, 0x06, 0x00, 0x00, 0
const uint8_t combo_report1[] = { 0x01, 0x03, 0x02, 0x03 };
const uint8_t combo_report2[] = { 0x02, 0x01, 0x00, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00 };
static void expect_field(btstack_hid_parser_t * parser, uint16_t expected_usage_page, uint16_t expected_usage, int32_t expected_value){
// printf("expected - usage page %02x, usage %04x, value %02x (bit pos %u)\n", expected_usage_page, expected_usage, expected_value, parser->report_pos_in_bit);
CHECK_EQUAL(1, btstack_hid_parser_has_more(parser));
@ -326,6 +328,22 @@ TEST(HID, Combo2){
CHECK_EQUAL(0, btstack_hid_parser_has_more(&hid_parser));
}
TEST(HID, GetReportSize){
int report_size = 0;
const uint8_t * hid_descriptor = combo_descriptor_with_report_ids;
uint16_t hid_descriptor_len = sizeof(combo_descriptor_with_report_ids);
// report_size = btstack_hid_get_report_size_for_id(1, BTSTACK_HID_REPORT_TYPE_INPUT, hid_descriptor_len, hid_descriptor);
// CHECK_EQUAL(3, report_size);
hid_descriptor = hid_descriptor_keyboard_boot_mode;
hid_descriptor_len = sizeof(hid_descriptor_keyboard_boot_mode);
report_size = btstack_hid_get_report_size_for_id(0, BTSTACK_HID_REPORT_TYPE_OUTPUT, hid_descriptor_len, hid_descriptor);
CHECK_EQUAL(1, report_size);
report_size = btstack_hid_get_report_size_for_id(0, BTSTACK_HID_REPORT_TYPE_INPUT, hid_descriptor_len, hid_descriptor);
CHECK_EQUAL(8, report_size);
}
int main (int argc, const char * argv[]){
// hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
return CommandLineTestRunner::RunAllTests(argc, argv);