mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
more host hid API
adding hid parser
This commit is contained in:
parent
641f55f1f1
commit
9ddc3bfd6d
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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<size; i++) TU_LOG2("%02X ", desc_report[i]);
|
||||
TU_LOG2("\r\n");
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case RI_TYPE_MAIN:
|
||||
break;
|
||||
|
||||
case RI_TYPE_GLOBAL:
|
||||
break;
|
||||
|
||||
case RI_TYPE_LOCAL:
|
||||
break;
|
||||
|
||||
// error
|
||||
default: break;
|
||||
}
|
||||
|
||||
desc_report += size;
|
||||
desc_len -= size;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Instance helper
|
||||
// Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get Device by address
|
||||
|
@ -46,9 +46,20 @@
|
||||
#define CFG_TUH_HID_REPORT_MAX 4
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_HID_REPORT_DESCRIPTOR_BUFSIZE
|
||||
#define CFG_TUH_HID_REPORT_DESCRIPTOR_BUFSIZE 256
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
uint8_t count; // number of info
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t usage_page;
|
||||
uint8_t usage;
|
||||
|
||||
// TODO still use the endpoint size for now
|
||||
uint8_t in_len; // length of IN report
|
||||
uint8_t out_len; // length of OUT report
|
||||
} info[CFG_TUH_HID_REPORT_MAX];
|
||||
} tuh_hid_report_info_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Multiple devices)
|
||||
@ -63,13 +74,25 @@ uint8_t tuh_n_hid_instance_count(uint8_t dev_addr);
|
||||
// Check if HID instance is mounted
|
||||
bool tuh_n_hid_n_mounted(uint8_t dev_addr, uint8_t instance);
|
||||
|
||||
// Get boot protocol check out hid_protocol_type_t for possible value
|
||||
uint8_t tuh_n_hid_n_boot_protocol(uint8_t dev_addr, uint8_t instance);
|
||||
|
||||
// Check if current mode is Boot (true) or Report (false)
|
||||
bool tuh_n_hid_n_boot_mode(uint8_t dev_addr, uint8_t instance);
|
||||
|
||||
// Get Report information parsed from report descriptor. Data must not be modified by application
|
||||
// If report information does not match the actual device descriptor, that is because the built-in parser
|
||||
// has its limit. Application could use tuh_hid_descriptor_report_cb() callback to parse descriptor by itself.
|
||||
tuh_hid_report_info_t const* tuh_n_hid_n_get_report_info(uint8_t dev_addr, uint8_t instance);
|
||||
|
||||
// Check if the interface is ready to use
|
||||
bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance);
|
||||
|
||||
// Get Report from device
|
||||
bool tuh_n_hid_n_get_report(uint8_t dev_addr, uint8_t instance, void* report, uint16_t len);
|
||||
|
||||
|
||||
// Set Report using control endpoint
|
||||
//bool tuh_n_hid_n_set_report_control(uint8_t dev_addr, uint8_t instance, void* report, uint16_t len);
|
||||
|
||||
//------------- -------------//
|
||||
|
||||
@ -93,10 +116,10 @@ TU_ATTR_WEAK void tuh_hid_mounted_cb (uint8_t dev_addr, uint8_t instance);
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
TU_ATTR_WEAK void tuh_hid_unmounted_cb(uint8_t dev_addr, uint8_t instance);
|
||||
|
||||
// Invoked when received Report from device
|
||||
// Invoked when received Report from device via either regular or control endpoint
|
||||
TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t xferred_bytes);
|
||||
|
||||
// Invoked when Sent Report to device
|
||||
// Invoked when Sent Report to device via either regular or control endpoint
|
||||
TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t xferred_bytes);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
Loading…
x
Reference in New Issue
Block a user