本帖最后由 lb8820265 于 2020-9-13 19:13 编辑
HID(human interface device)也就是人机接口设备,我们常见的鼠标键盘游戏手柄等都是HID,操作系统自带HID驱动的,有USB接口的,也有蓝牙接口的,都是相似的通信协议。因此这里参考USB接口的HID协议进行介绍。主要参考https://www.usb.org/hid网站中的两篇文档《Device Class Definition for HID 1.11 》《HID Usage Tables 1.2 》,可以直接在官网下载,也可以从本文附件中下载。
HID有自己协议,叫做报告描述符,用来描述发送的数据代表的含义(并不是发送的数据),包括是什么设备:鼠标、键盘、手柄等,和每一字节的含义。下面以键盘的报告描述符为例具体介绍。
参考例程:
nRF5_SDK_15.3.0_59ac345\examples\ble_peripheral\ble_app_hids_keyboard
main.c函数中的报告描述符如下表。
报告描述符
|
简介
|
0x05, 0x01, // Usage Pg (Generic Desktop)
|
这是一个global类Usage Page作用数据
|
0x09, 0x06, // Usage (Keyboard)
|
表示这是一个键盘
|
0xA1, 0x01, // Collection: (Application)
|
表示下面所包含的是对键盘的解释
|
0x05, 0x07, // Usage Pg (Key Codes)
|
定义的是按键码
|
0x19, 0xE0, // Usage Min (224)
0x29, 0xE7, // Usage Max (231)
|
按键码分别是 224~231,共总有 8 个按键码
|
0x15, 0x00, // Log Min (0)
0x25, 0x01, // Log Max (1)
|
按键码的值是 0 和 1,分别代表放开和按下
|
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
|
用 8 个 bit 分别表示 8 个按键的状态
|
0x81, 0x02, // Input: (Data, Variable,Absolute)
|
将这 8 个 bit 添加到本报告中
|
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input: (Constant)
|
另外再预留 8 个 bit 备用,暂时没用
|
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
|
定义 5 个 1bit
|
0x05, 0x08, // Usage Pg (LEDs)
|
这是 LED
|
0x19, 0x01, // Usage Min (1)
0x29, 0x05, // Usage Max (5)
|
5 个 bit 分别对应 LED1~LED5
|
0x91, 0x02, // Output: (Data, Variable,Absolute)
|
将这 5 个 bit 添加到本报告中,LED 需要作为 OUT
|
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output: (Constant)
|
再增加 3 个 bit,与上面 5 个 bit 组成一个字节
|
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
|
定义 6 个字节
|
0x15, 0x00, // Log Min (0)
0x25, 0x65, // Log Max (101)
|
每个字节的取值范围是 0~101
|
0x05, 0x07, // Usage Pg (Key Codes)
|
这个也是键盘码
|
0x19, 0x00, // Usage Min (0)
0x29, 0x65, // Usage Max (101)
|
分别是键盘码 0~键盘码 101
|
0x81, 0x00, // Input: (Data, Array)
|
将这 6 个字节添加到本报告中,表示同时可产生 6 个键值。
|
0xC0, // End Collection
|
结束
|
表中左边每一列由一个或者两个数字组成,第一个数字是前缀,第二个是数据(可无)
例如:0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x05表示前缀,0x01为数据部分,先看前缀,0x05转换成二进制,就是00000101,按照HID类协议的定义,这个字节被分成3个部分:(参考hid1_11.pdf)
bit0~bit1代表的是这个前缀后面跟的数据长度,两位可以表示最大4字节的数据,即bsize
bit2~bit3代表的是这个前缀的类型,总共可以有三种类型:00=main,01=global,10=local,11=reserved;
bit4~bit7代表前缀的tag,这里根据bit2~bit3的不同类型有不同的定义,例如global类型下的定义如下图。(参考hid1_11.pdf)
0000就表示Usage Page。所以前缀0x05代表的含义就是:一个global类型Usage Page作用数据量为1的前缀。
那我们做一个练习题:第二行出现的0x09,二进制就是:00001001,这就是local类型Usage Page作用数据量为1的前缀(local类型具体可以查看hid1_11.pdf的Local Items章节)。
下面来看数据0x01的作用
前缀是global类型Usage Page作用,那么这就要查看Usage Page作用的具体介绍。(参考hut1_2.pdf)
0x01表示Generic Desktop,表示桌面控制类型的设备,但具体是什么设备就要看第二行。
前面介绍了第二行0x09表示local类型Usage Page作用,参数为0x06,0x06表示键盘,查表如下。
这里主要就是介绍报告描述符的查阅方法,其他的描述符同样可以按照上述方法进行查阅。
键盘描述符的后定义的是发送数据的类型与格式。如下:
翻译出来就是,该协议支持一次最多发送6个按钮(键值0~101),支持最多同时按下8个功能按键(键值224~231)。键值表详见附件。
举例
例如我想要发送向上按钮,查表得出向上的键值是0x52(82),所以发送的8Byte数据为。
Byte0
|
Byte1
|
Byte2
|
Byte3
|
Byte4
|
Byte5
|
Byte6
|
Byte7
|
0x00
|
0x00
|
0x52
|
0x00
|
0x00
|
0x00
|
0x00
|
0x00
|
例如我想发送Ctrl+A,查表得出左Ctrl的键值为0xE0(224),也就是第一字节的第一位为1,A的键值为4。所以发送的8Byte数据为。
Byte0
|
Byte1
|
Byte2
|
Byte3
|
Byte4
|
Byte5
|
Byte6
|
Byte7
|
0x80
|
0x00
|
0x04
|
0x00
|
0x00
|
0x00
|
0x00
|
0x00
|