从零开始学USB(二十、USB接口HID类设备(二)_报表描述符Main类)

报表描述符定义了执行设备功能的数据格式和使用方法。
报表描述符和 USB 的其他描述符是不一样的,它不是一个简单的表格, 报表描述符是 USB 所有描述符中最复杂的 。报表描述符非常复杂而有弹性,因为它需要处理各种用途的设备。报表的数据必须以简洁的格式来储存,这样才不会浪费设备内的储存空间以及数据传输时的总线时间。
实际上可以这样理解, 报表内容的简洁,是通过报表描述符全面的、复杂的数据描述实现的 。
报表描述符必须先描述数据的大小与内容。报表描述符的内容与大小因设备的不同而不同,在进行报表传输之前,主机必须先请求设备的报表描述符,只有得到了报表描述符才可正确解析报表的数据。
报表描述符是报表描述项目( Item )的集合,每一个描述项目都有相对统一的数据结构,项目很多,通过编码实现。

(1)项目


报表描述符由描述 HID 设备的数据 项目(Item ) 组成。
项目的 第一个字节 (项目前缀)由三部分构成:

  1. 项目标志( item Tag ):说明项目的功能,
  2. 项目类型( item Type ):说明项目的数据类型,
  3. 项目长度( item Size ):说明项目的数据部分的长度。

HID 的项目有短项目和长项目两种,其中短项目的格式如下图。

短项目的数据字节数由 bSize 的值定义, bSize 为 0、 1、 2、 3 时 Data 部分的字节数分别为 0、 1、 2、 4 个字节。 (nn 为数据长度)短项目的项目类型由 bType 定义, bType 为 0、 1、 2 时分别为 Main 、 Global 和 Local类型。

 

长项目可以携带较多的数据,其格式如下图。
 

项目中的第一个字节为上图中的 特定值 时表明该项目是一个 长项目 。长项目中的bDataSize 说明 Data 部分的字节数, bLongItemT ag 在 HID 规范中没有定义。
下面是通过汇编实现的一个简单的报表描述符,描述符的每一行是一个项目,该描述符描述了一个 从设备接收 2 个字节的输入报表 和发送 2 个字节到设备的输出报表 。
 

(2)项目的分类

 

报表的项目有Main 、 Global 和 Local 三大类, 每一类都有多个不同的项目,实现不同的描述。

  • Main 类项目用于定义报表描述符中的数据项。也可以组合其中的若干数据项成为一个集合。 Main 项目可以分为带数据的Main 项目和不带数据的Main 项目。带数据项的Main用于生成报表中的数据项,包括Input 、 Output 和 Feature 项目。不带数据的Main 项目不生成报表中的数据项,包括Collection和 End Collection项目。
  • Global 类项目实现对数据的描述,用来识别报表并且描述报表内的数据,包括数据的功能、最大与最小允许值以及数据项的大小与数目等。改变由 Main 类项目生成的项目状态表。 Global 类项目描述对后续的所有项目有效,除非遇到有新的 Global 类项目。
  • Local 类项目定义控制的特征, 这一类项目的作用域不超过下一个 Main 项目, 所以在每一 Main 项目之前可能有多个 Local 项目。 Local 项目用于描述后面的 Input 、 Output 和Feature 项目。
     

2.1 Main项

 

Main item tagOne-Byte Prefix (nn represents
size value)
Valid Data 
Input1000 00 nn

Bit 0
Bit 1
Bit 2
Bit 3
Bit 4

		<p>Bit 5<br>
		Bit 6<br>
		Bit 7<br>
		Bit 8<br>
		Bit 31-9</p>
		</td>
		<td style="width:338px;">
		<p>{Data (0) | Constant (1)}<br>
		{Array (0) | Variable (1)}<br>
		{Absolute (0) | Relative (1)}<br>
		{No Wrap (0) | Wrap (1)}<br>
		{Linear (0) | Non Linear (1)}<br>
		{Preferred State (0) | No Preferred (1)}</p>

		<p>{No Null position (0) | Null state(1)}<br>
		Reserved (0)<br>
		{Bit Field (0) | Buffered Bytes (1)}<br>
		Reserved (0)</p>
		</td>
	</tr><tr><td style="width:150px;">Output</td>
		<td style="width:181px;">1001 00 nn</td>
		<td style="width:130px;">
		<p>Bit 0<br>
		Bit 1<br>
		Bit 2<br>
		Bit 3<br>
		Bit 4</p>

		<p>Bit 5<br>
		Bit 6<br>
		Bit 7<br>
		Bit 8<br>
		Bit 31-9</p>
		</td>
		<td style="width:338px;">
		<p>{Data (0) | Constant (1)}<br>
		{Array (0) | Variable (1)}<br>
		{Absolute (0) | Relative (1)}<br>
		{No Wrap (0) | Wrap (1)}<br>
		{Linear (0) | Non Linear (1)}<br>
		{Preferred State (0) | No Preferred (1)}</p>

		<p>{No Null position (0) | Null state(1)}<br>
		{Non Volatile (0) | Volatile (1)}<br>
		{Bit Field (0) | Buffered Bytes (1)}<br>
		Reserved (0)</p>
		</td>
	</tr><tr><td style="width:150px;">Feature</td>
		<td style="width:181px;">1011 00 nn</td>
		<td style="width:130px;">
		<p>Bit 0<br>
		Bit 1<br>
		Bit 2<br>
		Bit 3<br>
		Bit 4</p>

		<p>Bit 5<br>
		Bit 6<br>
		Bit 7<br>
		Bit 8<br>
		Bit 31-9</p>
		</td>
		<td style="width:338px;">
		<p>{Data (0) | Constant (1)}<br>
		{Array (0) | Variable (1)}<br>
		{Absolute (0) | Relative (1)}<br>
		{No Wrap (0) | Wrap (1)}<br>
		{Linear (0) | Non Linear (1)}<br>
		{Preferred State (0) | No Preferred (1)}</p>

		<p>{No Null position (0) | Null state(1)}<br>
		{Non Volatile (0) | Volatile (1)}<br>
		{Bit Field (0) | Buffered Bytes (1)}<br>
		Reserved (0)</p>
		</td>
	</tr><tr><td style="width:150px;">Collection</td>
		<td style="width:181px;">1010 00 nn</td>
		<td style="width:130px;">0x00<br>
		0x01<br>
		0x02<br>
		0x03<br>
		0x04<br>
		0x05<br>
		0x06<br>
		0x07-0x7F<br>
		0x80-0xFF</td>
		<td style="width:338px;">
		<p>Physical (group of axes)<br>
		Application (mouse, keyboard)<br>
		Logical (interrelated data)<br>
		Report<br>
		Named Array<br>
		Usage Switch<br>
		Usage Modifier<br>
		Reserved<br>
		Vendor-defined</p>
		</td>
	</tr><tr><td style="width:150px;">End Collection</td>
		<td style="width:181px;">1100 00 nn</td>
		<td style="width:130px;">
		<p>Not applicable.</p>
		</td>
		<td style="width:338px;">Closes an item collection.</td>
	</tr><tr><td style="width:150px;">Reserved</td>
		<td style="width:181px;">1101 00 nn to 1111 00 nn</td>
		<td style="width:130px;">Not applicable.</td>
		<td style="width:338px;">Reserved for future items.</td>
	</tr></tbody></table></div><p>&nbsp;</p>

 

  • 所有Main项的默认数据值为零(0)。
  • 输入项的数据大小可以为零(0)字节。 在这种情况下,可以假定项目的每个数据位的值为零。 这在功能上与使用item标记完全相同,该标记指定4字节数据项,后跟4个零字节。

 

2.2 Input、Output和Feature项目


输入,输出和功能项用于在报表中创建数据字段。

  • 输入项描述有关由一个或多个物理控件提供的数据的信息。 应用程序可以使用此信息来解释设备提供的数据。 在单个项目中定义的所有数据字段共享相同的数据格式。一个输入报表包含一个或多个 Input 项目,主机使用中断输入传输来请求输入报表。
  • 输出项用于在报告中定义输出数据字段。 一个输出报表包含一个或多个 Outpot项目。 输出报表包含控制状态的数据。此项类似于输入项,除了它描述发送到设备的数据 - 例如,LED状态。
  • 功能项描述可以发送到设备的设备配置信息。主机使用 Set_Report 与 Get_Report 请求来传送与接收特征报表。

 

在每一个 Input 、 Output 和 Feature 项目的前缀字之后是 32 位描述数据,目前最多定义了 9 个位,余的位则是保留。位 0~8 的定义中只有位 7 不能应用于 Input 项目,除此之外其他的位定义都适应于 Input 、 Output 和 Feature 项目。
 

参数功能描述
0Data | Constant0 | 1

数据表明该项目正在定义包含可修改设备数据的报告字段。

		<p>常量表示该项是报表中的静态只读字段,不能由主机修改(写入)。</p>
		</td>
	</tr><tr><td style="width:72px;">1</td>
		<td style="width:142px;">Array |Variable</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">数组: 报告全部控制的状态。 如在键盘报表中每一个键在报表中占一位,报表传输全部键的状态,可以同时按下任意多个键。<br>
		变量: 报告作用中的控制。 如在键盘报表中只报告按下的键的编号,可以同时按下的键的数目等于报表的计数( Global 类项目Report Count )</td>
	</tr><tr><td style="width:72px;">2</td>
		<td style="width:142px;">Absolute | Relative</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">绝对: 表示数值以一个固定值为基准。平板电脑通常提供绝对数据。<br>
		相对: 表示数据的改变以上一个读数为基准。 鼠标通常是报告相<br>
		对数据(鼠标的移动位置) 。</td>
	</tr><tr><td style="width:72px;">3</td>
		<td style="width:142px;">No Wrap | Wrap</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">指示数据在达到极高值或低值时是否“翻转”。 例如,可以360度自由旋转的刻度盘可能会输出0到10之间的值。如果是Wrap,在增加方向上通过10位置之后报告的下一个值将为0。</td>
	</tr><tr><td style="width:72px;">4</td>
		<td style="width:142px;">Linear | Nonlinear</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">
		<p>指示是否已以某种方式处理来自设备的原始数据,并且不再表示测量内容与报告的数据之间的线性关系。</p>

		<p>线形:表示测量的数据与报表的数据有线性的关系。</p>

		<p>非线性:表示测量的数据与报表的数据没有线性的关系。</p>
		</td>
	</tr><tr><td style="width:72px;">5</td>
		<td style="width:142px;">
		<p>PreferredState |</p>

		<p>No Preferred</p>
		</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">优选状态:表示控制在没有用户交互时会回到一个特定的状态。如按钮就有优选状态,在无操作时保持未按下的状态。(自动中心操纵杆)<br>
		非优选状态: 它维持在上一个用户选择的状态。 如交替的开关就没有优选状态。</td>
	</tr><tr><td style="width:72px;">6</td>
		<td style="width:142px;">No Null Position |<br>
		Null State</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">无空状态位置:表示控制永远在传送有效的数据。<br>
		空状态: 表示控制支持一个没有传送有效数据的状态。 如操纵杆可能具有一个多方向的按钮开关, 在没有按下时在空状态, 这时控制将传送一个在 Logical Minimum 与 Logical Maximum 范围之外的数值来表示它在空状态。</td>
	</tr><tr><td colspan="1" rowspan="2" style="width:72px;">7</td>
		<td style="width:142px;">Non volatile |<br>
		Volatile</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">不可变的: 表示设备只有在主机请求时才改变数值。 当主机传送一个报表并且不要改变不可变项目时, 如果该项目是定义成相对(Relative )的,数值 0 表示不改变数据,如果不可变项目是定义成绝对(Absolute ) 的, 超出范围外的数值则表示不改变数据。<br>
		可变的: 表示设备可以自己改变数值, 并不是必须主机传送报表要求给设备来改变数值。 例如设备控制面板可以由主机软件传送一个报表给设备,也可以由用户自己按设备上的实际按钮。</td>
	</tr><tr><td style="width:142px;">Reserved</td>
		<td style="width:121px;">0</td>
		<td style="width:464px;">数据位7未定义输入项,并保留供将来使用。</td>
	</tr><tr><td style="width:72px;">8</td>
		<td style="width:142px;">Bit Field |<br>
		Buffered Bytes</td>
		<td style="width:121px;">0 | 1</td>
		<td style="width:464px;">
		<p>表示控件发出固定大小的字节流。 数据字段的内容由应用程序确定。 缓冲区的内容不会被解释为单个数字量。 由缓冲字节项定义的报告数据必须在8位边界上对齐。 条形码阅读器的数据就是一个例子。</p>

		<p>位字段: 表示每一个位或是一个字节内的一组位可以代表一份数据。<br>
		缓冲字节: 表示信息包含一个或多个字节, 缓冲字节的报表大小必须是 8。</p>

		<p>&nbsp;</p>
		</td>
	</tr><tr><td colspan="3" rowspan="1" style="width:72px;">
		<p>9~31 位</p>
		</td>
		<td style="width:464px;">保留</td>
	</tr></tbody></table></div><ul><li>如果Input项是​​数组,则仅应用Data / Constant,Variable / Array和Absolute / Relative属性。</li>
<li><span style="color:#f33b45;">可以通过检查“报告大小”和“报告计数”值来确定项目中的数据字段数</span>。例如,报告大小为8位且报告计数为3的项目具有三个8位数据字段。</li>
<li>Array项返回的值是索引,因此建议:</li>
  1. 当没有声明数组中的控件时,Array字段返回0值。
  2. 逻辑最小值等于1。
  3. 逻辑最大值等于数组中的元素数。
  • 输入项定义可通过Control管道访问的输入报告,其中包含Get_Report(输入)请求。
  • 输入类型报告也通过中断输入管道以轮询速率发送。
  • 数据|常数,变量|数组,绝对|相对,非线性,自动换行和空状态数据与输入项的数据相同。
  • 输出项目使用Set_Report(输出)命令通过控制管道访问输出报告。
  • 输出类型报告可以选择通过中断输出管道发送。虽然功能相似,但输出和功能项目在以下方面有所不同:
  1. 功能项定义设备的配置选项,通常由控制面板应用程序设置。 由于它们会影响设备的行为(例如,按钮重复率,重置原点等),因此软件应用程序通常不会看到要素项。 相反,输出项表示向用户输出的设备(例如,LED,音频,触觉反馈等)。 软件应用程序可能会设置设备输出项。
  2. 功能项可以是其他项的属性。 例如,原点重置特征可以应用于一个或多个位置输入项。 与输出项类似,功能项组成功能报告可通过控制管道访问Get_Report(Feature)和Set_Report(Feature)请求。

 

2.2 Collection 和 End Collection 项目

Collection项标识两个或多个数据(输入,输出或特征)之间的关系。例如,鼠标可以描述为两到四个数据(x,y,按钮1,按钮2)的集合。 当Collection项打开一组数据时,End Collection项将关闭一个集合。

 

所有的报表类型都可以使用 Collection 与 End Collection 项目来将相关的 Main 类型项目组成群组。 这两个项目分别用于打开和关闭集合。 所有在 Collection 与 End Collection项目之间的 Main 类型项目都是 Collection 的一部分。
Collection 有 3 种类型: Application 、 Physical 与 Logical ,其项目的数据项的值分别为 1、 0 和 2。厂商也可以自己定义 Collection 类型,数据项的值为 80h~FFh 保留给厂商定义。 End Collection 项目无数据项。

Application Collection 包含有共同用途的项目或执行单一功能的项目。例如键盘的开机描述符将键盘的按键与 LED 指示灯数据集合成一个 Application Collection 。 所有的报表必须在一个 Application Collection 内。

Physical Collection 包含在一个单一几何点上的数据项目,可以将每个位置的数据集合成一个 Physical Collection 。在设备报告多个传感器的位置的时候,使用 PhysicalCollection 指明不同的数据来自不同的传感器。Logical Collection 形成一个数据结构,包含由 Collection 所连结的不同类型的项目。例如数据缓冲区的内容以及缓冲区内字节数目的计数。
 

 

Type of collectionValueDescription
Physical0x00物理集合用于表示在一个几何点处收集的数据点的一组数据项。 这对于可能需要将测量或感测的数据集与单个点相关联的感测设备是有用的。 它并不表示一组数据值来自一个设备,例如键盘。 在报告多个传感器位置的设备的情况下,物理集合用于显示来自每个单独传感器的数据。
Application0x01应用程序可能熟悉的一组主要项目。 它还可用于识别在单个设备中用于不同目的的项目组。 常见的例子是键盘或鼠标。 具有集成指点设备的键盘可以被定义为两个不同的应用程序集合。 数据报告通常(但不一定)与应用程序集合相关联(每个应用程序至少有一个报告ID)。
Logical0x02当一组数据项形成复合数据结构时,使用逻辑集合。 一个例子是数据缓冲区和数据的字节数之间的关联。 该集合建立计数和缓冲区之间的链接。
Report0x03定义包装报表中所有字段的逻辑集合。 此集合中将包含唯一的报告ID。 应用程序可以轻松确定设备是否支持某种功能。 请注意,可以为Report集合声明任何有效的Report ID值。
Named Array0x04命名数组是包含选择器用法数组的逻辑集合。 对于给定的功能,类似设备使用的选择器组可以变化。 在记录硬件寄存器时,字段的命名是常见的做法。 要确定设备是否支持Status等特定功能,应用程序可能必须先查询几个已知的Status选择器用法,然后才能确定设备是否支持Status。 命名数组用法允许命名包含选择器的Array字段,因此应用程序只需查询Status用法以确定设备是否支持状态信息。
Usage Switch0x05Usage Switch是一个逻辑集合,用于修改其包含的用法的含义。 此集合类型向应用程序指示在此集合中找到的用法必须是特殊的。 例如,不是在每个可能的功能上声明LED页面上的用法,而是可以将指示符用法应用于Usage Switch集合,并且现在可以将该集合中定义的标准用法识别为功能的指示符而不是功能本身。 请注意,此集合类型不用于标记序号集合,而是使用逻辑集合类型。
Usage Modifier0x06修改附加到包含集合的用法的含义。 用法通常定义控件的单个操作模式。 使用修饰符允许扩展控件的操作模式。 例如,LED通常打开或关闭。 对于特定状态,设备可能需要通用的闪烁方法或选择标准LED的颜色。 将LED使用附加到Usage Modifier集合将向应用程序指示该使用支持新的操作模式。
Reserved0x07~0x7F保留供将来使用。
 0x80~0xFF厂商自定义的

 

  • Collection项目和End Collection项目之间的所有Main项目都包含在集合中。 集合可能包含其他嵌套集合。
  • 集合项不会生成数据。 但是,Usage项标记必须与任何集合(例如鼠标或节流)关联。 集合项可以嵌套,除了顶级应用程序集之外,它们始终是可选的。
  • 如果遇到未知的供应商定义的集合类型,则应用程序必须忽略该集合中声明的所有主项。 请注意,在该集合中声明的全局项将影响状态表。
  • 如果未知用法附加到已知集合类型,则应忽略该集合的内容。 请注意,在该集合中声明的全局项将影响状态表。
  • 字符串和物理索引以及分隔符可能与集合相关联。

 

下面以最前面给出的一个HID报告描述符表,根据前面的学习来一一分析。

因为要用到所有的tag,所以下面先列出所有的tag

 


 
 
  1. HID_Report_desc_table:
  2. db 06h, A0h, FFh ; Usage Page(Vendor defined) 定义设备功能
  3. db 09h, A5h ; Usage(Vendor Defined) 定义用法
  4. db A1h, 01h ; Collection(Application) 开一个集合
  5. db 09H, A6h ; Usage(Vendor defined) 定义用法
  6. ; 输入报表
  7. db 09h, A7h ; Usgae(Vendor defined) 定义用法
  8. db 15h, 80h ; Logical Minimum 定义输入最小值 =- 128
  9. db 25h, 7Fh ; Logical Maximum 定义输入最大值 =+ 127
  10. db 75h, 08h ; Report Size 定义报表数据项大小 = 8
  11. db 95h, 02h ; Report Count 定义报表数据项个数 = 2
  12. db 81h, 02h ; Input(Data,Variable,Absolute) 输入项目
  13. ; 输出报表
  14. db 09h, A9h ; Usgae(Vendor defined) 定义用法
  15. db 15h, 80h ; Logical Minimum 定义输入最小值 =- 128
  16. db 25h, 7Fh ; Logical Maximum 定义输入最大值 =+ 27
  17. db 75h, 08h ; Report Size 定义报表数据项大小 = 8
  18. db 95h, 02h ; Report Count 定义报表数据向个数 = 2
  19. db 91h, 02h ; Output(Data,Variable,Absolute) 输出项目
  20. db C0h ; End Collection 关闭集合

按照短项目来分析。

Glibal和Local项相关的细节本节先不描述了,下一节描述,下面例子主要看输入,输入项相关的。

 

第二行,06 A0 FF 其中0x06对应着Global类项目中的Usage Page项,数据共2字节。数据0xFFA0表明由厂商定义,

第三行,09 A5  其中0x09对应着Local类项的Usage项,数据共一个字节。数据0xA5看后面的Local项章节。

第四行,A1 01 其中0xA1对应着Main类项的Collection项,数据共一个字节。数据0x01表示(Application)本章2.2节。

第五行,09 A6 其中0x09对应着Local类项的Usage项,数据共一个字节。数据0xA6看后面的Local项章节。

 

第七行,09 A7 其中0x09对应着Local类项的Usage项,数据共一个字节。数据A7看后面的Local项章节。

第八行,15 80 其中0x15对应着Global类项的Logical Minimum项,数据共一个字节。数据看后面的Global章节。

第九行,25 7F 其中0x15对应着Global类项的Logical  Maximum项,数据共一个字节。数据看后面的Global章节。

第十行,75 08 其中0x75对应着Global类项的Report Size项,数据共一个字节。指的是报表数据大小5个字节。

第十一行,95 02 其中0x95对应着Global类项的Report Count项,数据共一个字节。指的是是报表个数为2。

第十二行,81 02其中81对对应着Main类项的Input项,数据共一个字节。指的输入数据是变量。

 

第十四行,09 A9 其中0x09对应着Local类项的Usage项,数据共一个字节。数据A9看后面的Local项章节。

第十五行,15 80 其中0x15对应着Global类项的Logical Minimum项,数据共一个字节。数据看后面的Global章节。

第十六行,25 7F 其中0x15对应着Global类项的Logical  Maximum项,数据共一个字节。数据看后面的Global章节。

第十七行,75 08 其中0x75对应着Global类项的Report Size项,数据共一个字节。指的是报表数据大小5个字节。

第十八行,95 02 其中0x95对应着Global类项的Report Count项,数据共一个字节。指的是是报表个数为2。

第十九行,91 02其中81对对应着Main类项的Output项,数据共一个字节。指的输出数据是变量。

 

第二十行,C0 表示结束集合。

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/qq_16777851/article/details/86321149

    • 0
      点赞
    • 3
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值