报告描述符(Report Descriptor),由设备端(Device)描述给主机端(Host),后续设备端通过中断端点发送的数据的用途(Usage)说明或称描述数据格式及意义。它在连接建立初期就发送给主机端,主机端依据报告描述符去解析来自中断端点的数据。简单来说,报告描述符就是描述连接建立之后,设备端发送给主机端的数据帧中每一字节(bytes)每一位(bits)所代表的意义。
要想了解HID设备描述符,不得不去细读一下官方的两个文档,可以到官方下载:《Device Class Definition for human interface device (HID)》《Universal Serial Bus HID Usage Tables》这两份文件,其中一份是HID 协议,另一个是HID报告描述符(USAGE_PAGE & USAGE)的内容定义。报告描述符的直管组织结构为:
HID报告描述符的解析器就是按照上面这个组织形式,一层一层的进行解析的。一个报告描述符可以由多个Report组成,当超过1个Report时,需要用collection去组合,collection可以嵌套collection,每个Report都可以有多个用途(Usage).其它Main item/Report size/Report count/Logical minium等都是用于修饰Usage。
我们把一个HID的报告描述符比喻成一个公司,那么Collection就是一个部门,部门可以嵌套部门,部门里面有很多人,这里的人就是描述符中的Report,而Usage就是这个人身上的技能。对于单独的report,可以认为他就是一个光杆司令。
鼠标的报告描述符
uint8_t report_desc[] =
{
0x05, 0x01, //USAGE_PAGE (Generic Desktop)
0x09, 0x02, //USAGE (Mouse)
0xa1, 0x01, //COLLECTION (Application)
0x85, 0x01, //REPORT_ID (1)
0x09, 0x01, //USAGE (Pointer)
0xa1, 0x00, //COLLECTION (Physical)
0x05, 0x09, //Usage Page (Buttons)
0x19, 0x01, //Usage Minimum (01)
0x29, 0x03, //Usage Minimum (03)
0x15, 0x00, //Logical Minimum (0)
0x25, 0x01, //Logical Minimum (1)
0x95, 0x03, //Report Count (3)
0x75, 0x01, //Report Size (1)
0x81, 0x02, //Input (Data, Variable, Absolute)
0x95, 0x01, //Report Count (1)
0x75, 0x05, //Report Size (5)
0x81, 0x01, //Input (Constant)
0x05, 0x01, //USAGE_PAGE (Generic Desktop)
0x09, 0x30, //USAGE (x)
0x09, 0x31, //USAGE (y)
0x15, 0x00, //Logical Minimum (0)
0x26, 0x38, 0x04, //Logical Minimum (1080)
0x75, 0x10, //Report Size (16)
0x95, 0x03, //Report Count (2)
0x81, 0x02, //Input (Data, Variable, Relative)
0xc0, //END_COLLECTION
0xc0, //END_COLLECTION
};
上面的代码是一个鼠标的报告描述符,看起来他就是一个大数组,为什么按照两列来排列呢?这是由于他的结构导致的,这样写出来比较利于人来阅读。他的每一行都是一个条目,其结构形式为:条目标签(item tag) + 条目数据(item data)。
短条目
比如第一行的 0x05,0x01, 其中条目标签就是0x05,数据就是0x01。在上面的这一个条目中,Tag大小固定,短条目(short item)为1Byte,长条目(long item tag)为3Byte(长条目不常用,暂时研究了)。对于一个短条目(short item),其 item tag部分又分三个部分:标签(Tag)、数据大小(DataSize)和类型(type),bSize(2bits) + bType(2bits) + bTag(4bits) = 1byte。
bSize:描述数据内容的大小,占2bit,可以表示0-4个字节。bType:描述条目类型,占2bit,共3个选项以及1个保留项
b00 = Main (主要类型)
b01 = Global (全局类型)
b10 = Local (局部类型)
b11 = Reserved (保留)
bTag:描述各条目类型下的各细分条目,占4bit,最多15个选项。接下来,我们分别看Main,Global和Local三种类型。
短条目bTag选项 - Main项标签
下面是对短条目的一个描述列表
Input/Output/Feature
Input/Output/Feature具有相通的选项数据定义(input/output都是相对主机端而言的)Input(e.g. 0x81 , 0x**),输入报告 ,是设备端将设备操作发送到主机,这种报告通常通过中断端点发送到主机,以此保障一个固定周期的输入报告,它也可以控制端点的get report(input)来传输。Output(e.g. 0x91, 0x**),输出报告,是主机端将软件需求发送给设备,输出报告通常以控制端点的set report(output)来传输,只需要响应软件的实际需求即可,它也可以使用中断端点来传输数据。Feature(e.g.0xb1, 0x**),特征报告,是主机端发送到设备端的数据组态格式,特征报告只能以get report()/set report()来获取或设置设备的特征值。
Input、Output、Feature项可选值表
常用的是bit0和bit1两个选项。比如上面鼠标报告符中的:0x81, 0x01, //Input (Constant) ,其中0x01就表示bit0被置1了。
Collection/End Collection组合
项目实际应用中,一个设备通常不止一个功能点,以上述鼠标示例为例,具有3个按钮(左键、右键、中键),X/Y轴方向位移,滚轮等。它们各自具有不同的数据格式,聚集组成鼠标各个功能,此时我们需要Collection/End Collection去集合组织这些数据格式。某些设备还可能具有多组Collection,表明它有多方面的功能集合,例如某些手绘板同时具有触摸板、键鼠功能或某些键盘上有触摸功能。Collection选项数据定义在下文有表格详细列出说明,size为1个字节。End Collection通常不跟随数据,0xC0既可,表明Collection作用域的结束。
Collection项可选值表
Collection 的数据名称很难有一个准则来给定,《Universal Serial Bus HID Usage Tables》文档中将各种用途种类(usage type)列出,使用者必须依据用途种类来指定Collection 的数据名称。例如鼠标,键盘和游戏杆的用途种类为CA,所以要用Collection (Application),而指针为CP,所以用Collection (Physical)。我想原因应该是HID标准设备是逐步被发明定义出来的。
下一篇再学习 短条目bTag选项中的Global标签。