初学HID可能会对文件中的设备描述符不解
可以理解这是一种用十六进制数据写的脚本语言,通过该脚本语言传递给上位设备。该语言描述了一个HID设备(可以是鼠标,键盘,游戏手柄,或者是蓝牙自拍杆)的一些基本情况,如按键数量,数据的最大最小值,携带的功能等等。
以下是一个设备描述符的例子:
const u8 rep_map_data [CUSTOMHID_SIZ_REPORT_DESC] =
{
0x05, 0x01,
0x09, 0x02,
0xa1, 0x01,
0x09, 0x01,
0xa1, 0x00,
0x05, 0x09,
0x19, 0x01,
0x29, 0x03,
0x15, 0x00,
0x25, 0x01,
0x95, 0x03,
0x75, 0x01,
0x81, 0x02,
0x95, 0x01,
0x75, 0x05,
0x81, 0x03,
0x05, 0x01,
0x09, 0x30,
0x09, 0x31,
0x09, 0x38,
0x15, 0x81,
0x25, 0x7f,
0x75, 0x08,
0x95, 0x03,
0x81, 0x06,
0xc0,
0xc0
};
根据HID协议,该描述符内部的数据组,如{0x05,0x01},称为条目(目前我们用的都是两个字节的短条目)。条目由一个字节的前缀和可选的数据字节组成,可选的数据字节最大为4,最小为0。
前缀是如下三段数据组成的一个字节:
7 6 5 4 | 3 2 | 1 0 |
---|---|---|
bTag | bType | bSize |
bType表示该条目的类型。类型有三种:0为主条目,1为全局条目,2为局部条目。
bSize用来表示条目的数据字节数量0表示0个字节,1表示1个字节,2表示2个字节,3表示4个字节。
bTag表示该条目的功能。
其中主条目的数值对应的功能如下表:
数值 | 功能 | 数值 | 功能 |
---|---|---|---|
8 | input | 9 | output |
b | feature | ||
0xa1 | collection | 0xc0 | End collection |
其中全局条目的数值对应的功能如下表:
数值 | 功能 | 数值 | 功能 |
---|---|---|---|
0 | Usage Page | 1 | Logical Mini |
2 | Logical Maxi | 3 | Physical Mini |
4 | Physical Maxi | 7 | Report Size |
8 | Report ID | 9 | Report Count |
其中局部条目的数值对应的功能如下表:
数值 | 功能 | 数值 | 功能 |
---|---|---|---|
0 | Usage | 1 | Usage Mini |
2 | Usage Maxi |
主条目的功能是定义该数据域的。Collection开集合,End Collection闭集合。
全局条目主要是定义数据域的长度,数量,报告的ID。
根据上述表格,可以翻译上面的代码中的数据,
如{0x05,0x01},0x05(b00000101)可以分解为:bTag为0,bType为01,bSize为01,所以是用途页,全局条目,数据长度为1,后面的0x01就是数据。
如{0x09,0x01},0x09(b00001001)可以分解为:bTag为0,bType为2,bSize为01,所以局部用途页的条目,数据长度为1,后面的0x01就是数据。
查询《hut1_3_0.pdf》可知,对于全局用途条目(global usage page item )而言,数据0x01表示Generic Desktop Page (0x01),意为通用桌面设备。全局用途条目的数据表示如下图(部分):
局部用途条目(local usage page item),数据0x01表示设备为Pointer。局部用途条目的数据表示如下图(部分):
同理,代码中的数据如{0x19, 0x01,},0x19(b00011001)可以解读为bTag为01,bType为2,bSize为1,意思该条目是局部条目,数据量为1,功能为表示逻辑最小值。根据数据0x01,最小值为1。
于是,通过上述方法,我们可以解读HID设备描述符。
附:hid设备描述符的代码写法
#define ITEM_SIZE(x) ((x) & 0x03)
#define TYPE_MAIN (0)
#define TYPE_GLOBAL (0x04)
#define TYPE_LOCAL (0x08)
/* MAIN */
#define TAG_MAIN_INPUT (0x80)
#define TAG_MAIN_OUTPUT (0x90)
#define TAG_MAIN_FEATURE (0xB0)
#define TAG_MAIN_COLLECTION (0xA0)
#define TAG_MAIN_COL_END (0xC0)
/* GLOBAL */
#define TAG_GLOBAL_USAGE_PAGE (0x00)
#define TAG_GLOBAL_LOG_MIN (0x10)
#define TAG_GLOBAL_LOG_MAX (0x20)
#define TAG_GLOBAL_PHY_MIN (0x30)
#define TAG_GLOBAL_PHY_MAX (0x40)
#define TAG_GLOBAL_UNIT_EXP (0x50)
#define TAG_GLOBAL_UNIT (0x60)
#define TAG_GLOBAL_RPT_SIZE (0x70)
#define TAG_GLOBAL_RPT_ID (0x80)
#define TAG_GLOBAL_RPT_CNT (0x90)
#define TAG_GLOBAL_PUSH (0xA0)
#define TAG_GLOBAL_POP (0xB0)
/* LOCAL */
#define TAG_LOCAL_USAGE_ID (0x00)
#define TAG_LOCAL_USAGE_MIN (0x10)
#define TAG_LOCAL_USAGE_MAX (0x20)
#define TAG_LOCAL_DES_IDX (0x30)
#define TAG_LOCAL_DES_MIN (0x40)
#define TAG_LOCAL_DES_MAX (0x50)
#define TAG_LOCAL_NA (0x60)
#define TAG_LOCAL_STR_IDX (0x70)
#define TAG_LOCAL_STR_MIN (0x80)
#define TAG_LOCAL_STR_MAX (0x90)
#define TAG_LOCAL_Delimiter (0xA0)
#define USAGE_PAGE_2(x) (TAG_GLOBAL_USAGE_PAGE | TYPE_GLOBAL | ITEM_SIZE(2)), (uint8_t)((x) & 0x00ff), (uint8_t)((x)>>8)
#define USAGE_PAGE(x) (TAG_GLOBAL_USAGE_PAGE | TYPE_GLOBAL | ITEM_SIZE(1)), (x)
#define USAGE_ID(x) (TAG_LOCAL_USAGE_ID | TYPE_LOCAL | ITEM_SIZE(1)), (x)
#define LOGICAL_MIN(x) (TAG_GLOBAL_LOG_MIN | TYPE_GLOBAL | ITEM_SIZE(1)), (x)
#define LOGICAL_MAX(x) (TAG_GLOBAL_LOG_MAX | TYPE_GLOBAL | ITEM_SIZE(1)), (x)
#define LOGICAL_MAX_2(x) (TAG_GLOBAL_LOG_MAX | TYPE_GLOBAL | ITEM_SIZE(2)), (uint8_t)((x) & 0x00ff), (uint8_t)((x)>>8)
#define REPORT_ID(x) (TAG_GLOBAL_RPT_ID | TYPE_GLOBAL | ITEM_SIZE(1)), (x)
#define REPORT_SIZE(x) (TAG_GLOBAL_RPT_SIZE | TYPE_GLOBAL | ITEM_SIZE(1)), (x)
#define REPORT_CNT(x) (TAG_GLOBAL_RPT_CNT | TYPE_GLOBAL | ITEM_SIZE(1)), (x)
#define COLLECTION_END (TAG_MAIN_COL_END | TYPE_MAIN)
#define COLLECTION(x) (TAG_MAIN_COLLECTION | TYPE_MAIN | ITEM_SIZE(1)), (x)
#define FEATURE(x) (TAG_MAIN_FEATURE | TYPE_MAIN | ITEM_SIZE(1)), (x)
#define OUTPUT(x) (TAG_MAIN_OUTPUT | TYPE_MAIN | ITEM_SIZE(1)), (x)
#define INPUT(x) (TAG_MAIN_INPUT | TYPE_MAIN | ITEM_SIZE(1)), (x)
//e.g:
const uint8_t CustomHID_ReportDescriptor[122] =
{
USAGE_PAGE(0x0D),
USAGE_ID(0x01),
COLLECTION(0x01),
//0x05, 0x0D, /* USAGE_PAGE (Vendor Page: 0x008D -- SCALE ) */
//0x09, 0x01, /* USAGE (Demo Kit) */
//0xa1, 0x01, /* COLLECTION (Application) */
/* 6 */
/* Led 1 */
REPORT_ID(0x01),
//0x85, 0x01, /* REPORT_ID (1) */
USAGE_ID(1),
//0x09, 0x01, /* USAGE (LED 1) */
LOGICAL_MIN(0),
//0x15, 0x00, /* LOGICAL_MINIMUM (0) */
LOGICAL_MAX(1),
//0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
REPORT_SIZE(8),
//0x75, 0x08, /* REPORT_SIZE (8) */
REPORT_CNT(1),
//0x95, 0x01, /* REPORT_COUNT (1) */
FEATURE(0x82),
//0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
REPORT_ID(1),
//0x85, 0x01, /* REPORT_ID (1) */
USAGE_ID(1),
//0x09, 0x01, /* USAGE (LED 1) */
OUTPUT(0x82),
//0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
/* 26 */
/* Led 2 */
REPORT_ID(2),
//0x85, 0x02, /* REPORT_ID 2 */
USAGE_ID(2),
//0x09, 0x02, /* USAGE (LED 2) */
LOGICAL_MIN(0),
//0x15, 0x00, /* LOGICAL_MINIMUM (0) */
LOGICAL_MAX(1),
//0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
REPORT_SIZE(8),
//0x75, 0x08, /* REPORT_SIZE (8) */
REPORT_CNT(1),
//0x95, 0x01, /* REPORT_COUNT (1) */
FEATURE(0x82),
//0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
REPORT_ID(2),
//0x85, 0x02, /* REPORT_ID (2) */
USAGE_ID(2),
//0x09, 0x02, /* USAGE (LED 2) */
OUTPUT(0x82),
//0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
/* 46 */
/* key Push Button */
REPORT_ID(3),
//0x85, 0x05, /* REPORT_ID (5) */
USAGE_ID(3),
//0x09, 0x05, /* USAGE (Push Button) */
LOGICAL_MIN(0),
//0x15, 0x00, /* LOGICAL_MINIMUM (0) */
LOGICAL_MAX(1),
//0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
REPORT_SIZE(1),
//0x75, 0x01, /* REPORT_SIZE (1) */
INPUT(0x82),
//0x81, 0x82, /* INPUT (Data,Var,Abs,Vol) */
USAGE_ID(3),
//0x09, 0x05, /* USAGE (Push Button) */
REPORT_SIZE(1),
//0x75, 0x01, /* REPORT_SIZE (1) */
FEATURE(0x82),
//0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
REPORT_SIZE(7),
//0x75, 0x07, /* REPORT_SIZE (7) */
INPUT(0x83),
//0x81, 0x83, /* INPUT (Cnst,Var,Abs,Vol) */
REPORT_ID(3),
//0x85, 0x05, /* REPORT_ID (2) */
REPORT_SIZE(7),
//0x75, 0x07, /* REPORT_SIZE (7) */
FEATURE(0x83),
//0xb1, 0x83, /* FEATURE (Cnst,Var,Abs,Vol) */
/* 74 */
/* Tamper Push Button */
REPORT_ID(4),
//0x85, 0x06, /* REPORT_ID (6) */
USAGE_ID(4),
//0x09, 0x06, /* USAGE (Tamper Push Button) */
LOGICAL_MIN(0),
//0x15, 0x00, /* LOGICAL_MINIMUM (0) */
LOGICAL_MAX(1),
//0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
REPORT_SIZE(1),
//0x75, 0x01, /* REPORT_SIZE (1) */
INPUT(0x82),
//0x81, 0x82, /* INPUT (Data,Var,Abs,Vol) */
USAGE_ID(4),
//0x09, 0x06, /* USAGE (Tamper Push Button) */
REPORT_SIZE(1),
//0x75, 0x01, /* REPORT_SIZE (1) */
FEATURE(0x82),
//0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
REPORT_SIZE(7),
//0x75, 0x07, /* REPORT_SIZE (7) */
INPUT(0x83),
//0x81, 0x83, /* INPUT (Cnst,Var,Abs,Vol) */
REPORT_ID(4),
//0x85, 0x06, /* REPORT_ID (6) */
REPORT_SIZE(7),
//0x75, 0x07, /* REPORT_SIZE (7) */
FEATURE(0x83),
//0xb1, 0x83, /* FEATURE (Cnst,Var,Abs,Vol) */
/* 102 */
/* ADC IN */
REPORT_ID(5),
//0x85, 0x07, /* REPORT_ID (7) */
USAGE_ID(5),
//0x09, 0x07, /* USAGE (ADC IN) */
LOGICAL_MIN(0),
//0x15, 0x00, /* LOGICAL_MINIMUM (0) */
LOGICAL_MAX_2(0x00ff),
//0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
REPORT_SIZE(8),
//0x75, 0x08, /* REPORT_SIZE (8) */
INPUT(0x82),
//0x81, 0x82, /* INPUT (Data,Var,Abs,Vol) */
REPORT_ID(5),
//0x85, 0x07, /* REPORT_ID (7) */
USAGE_ID(5),
//0x09, 0x07, /* USAGE (ADC in) */
FEATURE(0x82),
//0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
/* 121 */
COLLECTION_END /* END_COLLECTION */
}; /* CustomHID_ReportDescriptor */
参考文章:
https://www.usb.org/document-library/hid-usage-tables-13
https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
BLE HID 协议-----蓝牙鼠标 代码流程分析
usb_hid描述符简介
USB HID report descriptor
USB-HID设备6-HID报告描述符详解