From 9ddc3bfd6dc1450d30c16c0a1d07240ea74a13bf Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 May 2021 01:02:47 +0700 Subject: [PATCH] more host hid API adding hid parser --- examples/host/cdc_msc_hid/src/tusb_config.h | 6 +- src/class/hid/hid.h | 60 +++++++- src/class/hid/hid_host.c | 148 +++++++++++++++----- src/class/hid/hid_host.h | 35 ++++- 4 files changed, 196 insertions(+), 53 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 01296cd2..fd043279 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -86,11 +86,7 @@ // Max number of reports per interface // E.g composite HID with keyboard + mouse + gamepad will have 3 reports -#define CFG_TUH_HID_REPORT_MAX 4 - -// Max buffer -#define CFG_TUH_HID_REPORT_DESCRIPTOR_BUFSIZE 256 - +#define CFG_TUH_HID_REPORT_MAX 4 #ifdef __cplusplus } diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 351a4d60..f0ad0360 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -479,6 +479,7 @@ typedef enum //--------------------------------------------------------------------+ // REPORT DESCRIPTOR //--------------------------------------------------------------------+ + //------------- ITEM & TAG -------------// #define HID_REPORT_DATA_0(data) #define HID_REPORT_DATA_1(data) , data @@ -488,18 +489,31 @@ typedef enum #define HID_REPORT_ITEM(data, tag, type, size) \ (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) -#define RI_TYPE_MAIN 0 -#define RI_TYPE_GLOBAL 1 -#define RI_TYPE_LOCAL 2 +// Report Item Types +enum { + RI_TYPE_MAIN = 0, + RI_TYPE_GLOBAL = 1, + RI_TYPE_LOCAL = 2 +}; + +//------------- Main Items - HID 1.11 section 6.2.2.4 -------------// + +// Report Item Main group +enum { + RI_MAIN_INPUT = 8, + RI_MAIN_OUTPUT = 9, + RI_MAIN_COLLECTION = 10, + RI_MAIN_FEATURE = 11, + RI_MAIN_COLLECTION_END = 12 +}; -//------------- MAIN ITEMS 6.2.2.4 -------------// #define HID_INPUT(x) HID_REPORT_ITEM(x, 8, RI_TYPE_MAIN, 1) #define HID_OUTPUT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_MAIN, 1) #define HID_COLLECTION(x) HID_REPORT_ITEM(x, 10, RI_TYPE_MAIN, 1) #define HID_FEATURE(x) HID_REPORT_ITEM(x, 11, RI_TYPE_MAIN, 1) #define HID_COLLECTION_END HID_REPORT_ITEM(x, 12, RI_TYPE_MAIN, 0) -//------------- INPUT, OUTPUT, FEATURE 6.2.2.5 -------------// +//------------- Input, Output, Feature - HID 1.11 section 6.2.2.5 -------------// #define HID_DATA (0<<0) #define HID_CONSTANT (1<<0) @@ -527,7 +541,7 @@ typedef enum #define HID_BITFIELD (0<<8) #define HID_BUFFERED_BYTES (1<<8) -//------------- COLLECTION ITEM 6.2.2.6 -------------// +//------------- Collection Item - HID 1.11 section 6.2.2.6 -------------// enum { HID_COLLECTION_PHYSICAL = 0, HID_COLLECTION_APPLICATION, @@ -538,7 +552,24 @@ enum { HID_COLLECTION_USAGE_MODIFIER }; -//------------- GLOBAL ITEMS 6.2.2.7 -------------// +//------------- Global Items - HID 1.11 section 6.2.2.7 -------------// + +// Report Item Global group +enum { + RI_GLOBAL_USAGE_PAGE = 0, + RI_GLOBAL_LOGICAL_MIN = 1, + RI_GLOBAL_LOGICAL_MAX = 2, + RI_GLOBAL_PHYSICAL_MIN = 3, + RI_GLOBAL_PHYSICAL_MAX = 4, + RI_GLOBAL_UNIT_EXPONENT = 5, + RI_GLOBAL_UNIT = 6, + RI_GLOBAL_REPORT_SIZE = 7, + RI_GLOBAL_REPORT_ID = 8, + RI_GLOBAL_REPORT_COUNT = 9, + RI_GLOBAL_PUSH = 10, + RI_GLOBAL_POP = 11 +}; + #define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, 1) #define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, n) @@ -573,6 +604,21 @@ enum { #define HID_POP HID_REPORT_ITEM(x, 11, RI_TYPE_GLOBAL, 0) //------------- LOCAL ITEMS 6.2.2.8 -------------// + +enum { + RI_LOCAL_USAGE = 0, + RI_LOCAL_USAGE_MIN = 1, + RI_LOCAL_USAGE_MAX = 2, + RI_LOCAL_DESIGNATOR_INDEX = 3, + RI_LOCAL_DESIGNATOR_MIN = 4, + RI_LOCAL_DESIGNATOR_MAX = 5, + // 6 is reserved + RI_LOCAL_STRING_INDEX = 7, + RI_LOCAL_STRING_MIN = 8, + RI_LOCAL_STRING_MAX = 9, + RI_LOCAL_DELIMITER = 10, +}; + #define HID_USAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, 1) #define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, n) diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 60ee667d..862026b5 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -35,14 +35,15 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -/* "KEYBOARD" : in_len=8 , out_len=1, usage_page=0x01, usage=0x06 # Generic Desktop, Keyboard - "MOUSE" : in_len=4 , out_len=0, usage_page=0x01, usage=0x02 # Generic Desktop, Mouse - "CONSUMER" : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01 # Consumer, Consumer Control - "SYS_CONTROL" : in_len=1 , out_len=0, usage_page=0x01, usage=0x80 # Generic Desktop, Sys Control - "GAMEPAD" : in_len=6 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad - "DIGITIZER" : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02 # Digitizers, Pen - "XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad - "RAW" : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF +/* + "KEYBOARD" : in_len=8 , out_len=1, usage_page=0x01, usage=0x06 # Generic Desktop, Keyboard + "MOUSE" : in_len=4 , out_len=0, usage_page=0x01, usage=0x02 # Generic Desktop, Mouse + "CONSUMER" : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01 # Consumer, Consumer Control + "SYS_CONTROL" : in_len=1 , out_len=0, usage_page=0x01, usage=0x80 # Generic Desktop, Sys Control + "GAMEPAD" : in_len=6 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad + "DIGITIZER" : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02 # Digitizers, Pen + "XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad + "RAW" : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF */ typedef struct { @@ -57,22 +58,14 @@ typedef struct uint8_t boot_protocol; // None, Keyboard, Mouse bool boot_mode; // Boot or Report protocol - uint8_t report_count; // Number of reports - struct { - uint8_t usage_page; - uint8_t usage; - - // TODO just use the endpint size for now - uint8_t in_len; // length of IN report - uint8_t out_len; // length of OUT report - }reports[CFG_TUH_HID_REPORT_MAX]; + tuh_hid_report_info_t report_info; // Parsed Report ID for convenient API uint8_t rid_keyboard; uint8_t rid_mouse; uint8_t rid_gamepad; uint8_t rid_consumer; -}hidh_interface_t; +} hidh_interface_t; typedef struct { @@ -104,6 +97,23 @@ bool tuh_n_hid_n_mounted(uint8_t dev_addr, uint8_t instance) return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0); } +uint8_t tuh_n_hid_n_boot_protocol(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return hid_itf->boot_protocol; +} + +bool tuh_n_hid_n_boot_mode(uint8_t dev_addr, uint8_t instance) +{ + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + return hid_itf->boot_mode; +} + +tuh_hid_report_info_t const* tuh_n_hid_n_get_report_info(uint8_t dev_addr, uint8_t instance) +{ + return &get_instance(dev_addr, instance)->report_info; +} + bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) { TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance)); @@ -190,6 +200,7 @@ void hidh_close(uint8_t dev_addr) // Enumeration //--------------------------------------------------------------------+ +static void parse_report_descriptor(hidh_interface_t* hid_itf, uint8_t const* desc_report, uint16_t desc_len); static bool config_set_idle_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); @@ -235,23 +246,25 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de if ( HID_PROTOCOL_KEYBOARD == desc_itf->bInterfaceProtocol) { + TU_LOG2(" Boot Keyboard\r\n"); // TODO boot protocol may still have more report in report mode - hid_itf->report_count = 1; + hid_itf->report_info.count = 1; - hid_itf->reports[0].usage_page = HID_USAGE_PAGE_DESKTOP; - hid_itf->reports[0].usage = HID_USAGE_DESKTOP_KEYBOARD; - hid_itf->reports[0].in_len = 8; - hid_itf->reports[0].out_len = 1; + hid_itf->report_info.info[0].usage_page = HID_USAGE_PAGE_DESKTOP; + hid_itf->report_info.info[0].usage = HID_USAGE_DESKTOP_KEYBOARD; + hid_itf->report_info.info[0].in_len = 8; + hid_itf->report_info.info[0].out_len = 1; } else if ( HID_PROTOCOL_MOUSE == desc_itf->bInterfaceProtocol) { + TU_LOG2(" Boot Mouse\r\n"); // TODO boot protocol may still have more report in report mode - hid_itf->report_count = 1; + hid_itf->report_info.count = 1; - hid_itf->reports[0].usage_page = HID_USAGE_PAGE_DESKTOP; - hid_itf->reports[0].usage = HID_USAGE_DESKTOP_MOUSE; - hid_itf->reports[0].in_len = 8; - hid_itf->reports[0].out_len = 1; + hid_itf->report_info.info[0].usage_page = HID_USAGE_PAGE_DESKTOP; + hid_itf->report_info.info[0].usage = HID_USAGE_DESKTOP_MOUSE; + hid_itf->report_info.info[0].in_len = 5; + hid_itf->report_info.info[0].out_len = 0; } else { @@ -326,19 +339,23 @@ bool config_set_idle_complete(uint8_t dev_addr, tusb_control_request_t const * r bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { TU_ASSERT(XFER_RESULT_SUCCESS == result); - uint8_t const itf_num = (uint8_t) request->wIndex; - uint8_t const inst = get_instance_id_by_itfnum(dev_addr, itf_num); - //hidh_interface_t* hid_itf = get_instance(dev_addr, inst); + + uint8_t const itf_num = (uint8_t) request->wIndex; + uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); + hidh_interface_t* hid_itf = get_instance(dev_addr, instance); + + uint8_t const* desc_report = usbh_get_enum_buf(); + uint16_t const desc_len = request->wLength; if (tuh_hid_descriptor_report_cb) { - tuh_hid_descriptor_report_cb(dev_addr, inst, usbh_get_enum_buf(), request->wLength); + tuh_hid_descriptor_report_cb(dev_addr, instance, desc_report, desc_len); } - // TODO Report descriptor parser + parse_report_descriptor(hid_itf, desc_report, desc_len); // enumeration is complete - if (tuh_hid_mounted_cb) tuh_hid_mounted_cb(dev_addr, inst); + if (tuh_hid_mounted_cb) tuh_hid_mounted_cb(dev_addr, instance); // notify usbh that driver enumeration is complete usbh_driver_set_config_complete(dev_addr, itf_num); @@ -346,8 +363,69 @@ bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t co return true; } +// Parse Report Descriptor to tuh_hid_report_info_t +static void parse_report_descriptor(hidh_interface_t* hid_itf, uint8_t const* desc_report, uint16_t desc_len) +{ + enum + { + USAGE_PAGE = 0x05, + USAGE = 0x09, + USAGE_MIN = 0x19, + USAGE_MAX = 0x29, + LOGICAL_MIN = 0x15, + LOGICAL_MAX = 0x25, + REPORT_SIZE = 0x75, + REPORT_COUNT = 0x95 + }; + + // Short Item 6.2.2.2 USB HID 1.11 + union TU_ATTR_PACKED + { + uint8_t byte; + struct TU_ATTR_PACKED + { + uint8_t size : 2; + uint8_t type : 2; + uint8_t tag : 4; + }; + } header; + + while(desc_len) + { + header.byte = *desc_report++; + + uint8_t const tag = header.tag; + uint8_t const type = header.type; + uint8_t const size = header.size; + + desc_len--; + + TU_LOG2("tag = %d, type = %d, size = %d, data = ", tag, type, size); + for(uint32_t i=0; i