最近在做一个投票系统的上位机。虽然是上位机,但还是要弄清楚下位机与自己的接口――HID。
因为windows下已经有一个usb监听程序――USB HOUND。所以,我选择先写好下位机的程序,成功发送数据后,再进行上位机程序的编写。
下位机程序,重点在于HID设备的描述符配置。什么是描述符?
HID 设备, |– 通过设备描述符来标识自己的设备信息,如设备ID、厂商名称、版本、配置数量等; |– 通过配置描述符集合来标识自己的配置信息,包括 | |– 配置描述符(总述)、 | `– 接口描述符(接口类型,鼠标,键盘,自定义设备等)、 | |– 端点描述符(端点读写类型,支持的数据包属性等)和 | `– HID描述符(HID版本、下级描述符信息等)。 |– 通过字符串描述符来定义自己的一些字符串,如厂商名称等; `– 通过报告描述符来标识数据流的格式,如数据用途(鼠标、键盘、自定义等)、长度、大小等。
网上的很多示例和介绍都使用c语言,但是,我遇到的源码,却是汇编编写的,所以我以我的项目为例,用汇编来介绍各个描述符结构,也算是个不一样的体验吧。
具体的描述介绍如下:
在里面,最重要的是VID和PID,它一般用来标识你的USB设备。VID需要向USB组织申请,PID则是公司内部自己定义。其实,我们还可以通过产品序列号来标识,但目前,我还没有添加这个功能,直接使用VID和PID识别的。
另外我们可以通过这份代码看到一些技巧,就是在填写描述符长度时,让编译器自己计算:deviceDescEnd – deviceDesc
我目前的设备是鼠标、键盘、自定义3种接口。可以支持三种端点同时传输数据,非常high~~
我的这个项目中,有3 种接口,原始代码已经实现了鼠标和键盘的接口描述符。感兴趣的读者也可以在网上查阅。有现成的示例代码。
从本文开始的那个介绍看出,接口之下是包含端点的,因此,接口描述符中有一项的端点数,这个端点数标明的是除默认控制端点0之外的数据输入输出端点数量。目前我只实现了一个数据输入(USB中所有的输入、输出的对象都是主设备,在我这里,指的是PC)。 后期我会添加一个数据输出端点。
端点描述符中的bmAttributes 是个比较重要的字段,标明了该端点的类型,端点有控制(0)、等时(1)、批量(2)、中断(3)四种类型。HID只有控制端点和中断端点两种类型。
这个没啥要紧的,我也不清楚,不详述了。
报告描述符相当复杂,但也是HID设备的精髓。它标识了HID设备与主机通讯的报告格式以及数据用途,数据是存放在报告中的。
报告描述符的每个条目都有个条目前缀,是如下格式:
,-----------------------. |7 6 5 4 3 2 1 0 | |-----------------------| | bTag | bType | bSize | `-----------------------'高 4 位bTag标识该条目的功能,具体的可以参看HID协议,第 2, 3 位为条目类型(0――主条目、1――全局条目、2――局部条目、3――保留),第 0, 1 位为条目大小,表示该前缀之后有多少个字节的内容。 比如 09H (00001001B) 表示这是一个局部条目,后跟一个字节。功能为用途页(0)。各种功能的定义可以参看HID协议或者其它示例,下面,我就以我写的自定义设备为例大致介绍一下报告描述符的设计:
entity2Desc: ; Custom HID device report descriptor DB 0005H, 0001H ; Usage Pg (Generic Desktop) 全局,功能为“用途页”。后跟的0001H表示这是通用桌面用途 DB 0009H, 0000H ; Usage (0) ; custom usage 局部,功能为“用途页”。后跟0000H表示这是自定义用途。 DB 00A1H, 0001H ; Collection: (Application) 主条目,功能为“开集合”,表示后面的条目都在集合 Application 下。 ; DB 0015H, 0000H ; Log Min (0) 全局,功能为“最小值”,表示数据的可以达到的逻辑最小值为0 DB 0025H, 00FFH ; Log Max (255) 全局,“最大值”,表示最大为255 (一个字节)。 DB 0019H, 0000H ; Usage Min (0) 局部,功能为“最小值”,表示局部用途,即上文定义的自定义用途最小值为0 DB 0029H, 00FFH ; Usage Max (255) 局部。。。。 ; ; we will send the remote ID and selection ; need 2 byte (16 bit) data space. DB 0095H, 0002H ; Report Count (2) 全局,功能为“数据数量”,表示每个报告中数据的数据有2个 DB 0075H, 0008H ; Report Size (8) 全局,功能为“数据大小”,表示每个数据大小为 8 个bit。 DB 0081H, 0002H ; Input: (Data, Variable, Absolute) 主,功能为“输入”, ; 02H (00000010B) 表示以上的数据定义是变量,独立(非数组),绝对值(无符号)的。 DB 00C0H ; End Collection 主条目,不跟内容,“关集合”。表示关闭上面打开的Application集合。 entity2DescEnd:通过这份报告描述符,我们就能知道,这个接口传输的数据是用于自定义用途的,而且是两个字节的数据。 当然,我这还是测试之用,到具体使用时,我会使用两个数据段,一个是 4 个字节的手持端ID数组,一个是1字节的手持端数据内容。 到时就会更复杂一些。
OK,剩下的工作就是编写这些描述符的发送函数了。我使用的是TI公司的代码,所以没有自己编写这些函数,就不误人子弟了。。 并且不同的芯片编写的代码也不一样。要看具体情况。有兴趣的读者就自己去体会吧~~