From ad845db6a50c1d90e4f7cc45ca16a8861ee2da4d Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 22 May 2021 20:54:59 +0700 Subject: [PATCH] improve hid parser --- examples/host/cdc_msc_hid/src/hid_app.c | 50 +++++++++++++--------- src/class/hid/hid_host.c | 56 ++++++++----------------- src/class/hid/hid_host.h | 6 +-- 3 files changed, 50 insertions(+), 62 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index eab555fc..71904245 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -37,14 +37,16 @@ static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; +// Each HID instance can has multiple reports static uint8_t _report_count[CFG_TUH_HID]; -static tuh_hid_report_info_t _report_info[CFG_TUH_HID][MAX_REPORT]; +static tuh_hid_report_info_t _report_info_arr[CFG_TUH_HID][MAX_REPORT]; static void process_kbd_report(hid_keyboard_report_t const *report); static void process_mouse_report(hid_mouse_report_t const * report); void hid_app_task(void) { + // nothing to do } //--------------------------------------------------------------------+ @@ -55,21 +57,13 @@ void tuh_hid_mounted_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_ { printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); - // Parse report descriptor with built-in parser - _report_count[instance] = tuh_hid_parse_report_descriptor(_report_info[instance], MAX_REPORT, desc_report, desc_len); - - if (_report_count[instance]) - { - printf("Composite with %u reports", _report_count[instance]); - }else - { - printf("Single report"); - } - // Interface protocol const char* protocol_str[] = { "None", "Keyboard", "Mouse" }; // hid_protocol_type_t uint8_t const interface_protocol = tuh_hid_interface_protocol(dev_addr, instance); - printf(", Interface protocol = %s, ", protocol_str[interface_protocol]); + + // Parse report descriptor with built-in parser + _report_count[instance] = tuh_hid_parse_report_descriptor(_report_info_arr[instance], MAX_REPORT, desc_report, desc_len); + printf("HID has %u reports and interface protocol = %s\r\n", _report_count[instance], protocol_str[interface_protocol]); } void tuh_hid_unmounted_cb(uint8_t dev_addr, uint8_t instance) @@ -82,20 +76,36 @@ void tuh_hid_get_report_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* re (void) dev_addr; uint8_t const rpt_count = _report_count[instance]; - tuh_hid_report_info_t* rpt_info; + tuh_hid_report_info_t* rpt_info_arr = _report_info_arr[instance]; + tuh_hid_report_info_t* rpt_info = NULL; - if (rpt_count) + if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0) + { + // Simple report without report ID as 1st byte + rpt_info = &rpt_info_arr[0]; + }else { // Composite report, 1st byte is report ID, data starts from 2nd byte - // Note: report index = report ID - 1 - uint8_t idx = report[0] - 1; - rpt_info = &_report_info[instance][idx]; + uint8_t const rpt_id = report[0]; + + // Find report id in the arrray + for(uint8_t i=0; iusage_page == HID_USAGE_PAGE_DESKTOP ) diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 90a848fc..15533cf3 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -337,7 +337,7 @@ bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t co // Report Descriptor Parser //--------------------------------------------------------------------+ -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) { // Report Item 6.2.2.2 USB HID 1.11 union TU_ATTR_PACKED @@ -351,18 +351,16 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint }; } header; - uint8_t report_num = 0; - tuh_hid_report_info_t* info = report_info; + tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); - tu_memclr(report_info, arr_count*sizeof(tuh_hid_report_info_t)); + uint8_t report_num = 0; + tuh_hid_report_info_t* info = report_info_arr; // current parsed report count & size from descriptor // uint8_t ri_report_count = 0; // uint8_t ri_report_size = 0; uint8_t ri_collection_depth = 0; - uint16_t ri_usage_page = 0; - uint8_t ri_usage = 0; while(desc_len && report_num < arr_count) { @@ -394,6 +392,11 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint case RI_MAIN_COLLECTION_END: ri_collection_depth--; + if (ri_collection_depth == 0) + { + info++; + report_num++; + } break; default: break; @@ -404,11 +407,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint switch(tag) { case RI_GLOBAL_USAGE_PAGE: - // only take in account the "usage page" before starting COLLECTION - if ( ri_collection_depth == 0) - { - memcpy(&ri_usage_page, desc_report, size); - } + // only take in account the "usage page" before REPORT ID + if ( ri_collection_depth == 0 ) memcpy(&info->usage_page, desc_report, size); break; case RI_GLOBAL_LOGICAL_MIN : break; @@ -417,23 +417,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint case RI_GLOBAL_PHYSICAL_MAX : break; case RI_GLOBAL_REPORT_ID: - report_num++; - if (data8 <= arr_count) - { - uint8_t const idx = data8 - 1; - if ( info != &report_info[idx] ) - { - // copy info so far to its correct report ID, and update info pointer - report_info[idx] = *info; - info = &report_info[idx]; - } - - info->usage_page = ri_usage_page; - info->usage = ri_usage; - }else - { - TU_LOG2("HID Skip a report with ID (%u) larger than array count (%u)\r\n", data8, arr_count); - } + info->report_id = data8; break; case RI_GLOBAL_REPORT_SIZE: @@ -457,8 +441,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint switch(tag) { case RI_LOCAL_USAGE: - // only take in account the "usage" before starting COLLECTION - if ( ri_collection_depth == 0) ri_usage = data8; + // only take in account the "usage" before starting REPORT ID + if ( ri_collection_depth == 0 ) info->usage = data8; break; case RI_LOCAL_USAGE_MIN : break; @@ -482,16 +466,10 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint desc_len -= size; } - if ( report_num == 0 ) + for ( uint8_t i = 0; i < report_num; i++ ) { - report_info[0].usage_page = ri_usage_page; - report_info[0].usage = ri_usage; - } - - for ( uint8_t i = 0; (i < report_num) || (!i && !report_num); i++ ) - { - info = report_info+i; - TU_LOG2("%u: usage_page = %u, usage = %u\r\n", i, info->usage_page, info->usage); + info = report_info_arr+i; + TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); } return report_num; diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 3cf8dc70..1b8acda0 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -53,8 +53,9 @@ typedef struct { + uint8_t report_id; + uint8_t usage; uint16_t usage_page; - uint8_t usage; // TODO still use the endpoint size for now // uint8_t in_len; // length of IN report @@ -83,9 +84,8 @@ bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance); bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol); // Parse report descriptor into array of report_info struct and return number of reports. -// If return 0, this is a ingle report, otherwise it is composite report with 1st byte as ID. // For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; // Check if the interface is ready to use //bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance);