从毕业那会就一直想花时间搞搞了。至今零零散散基础学习了3轮,都是知难而退了,还记得上次是学到报告描述符就没兴趣再学下去了,上上一次是大概知道一下枚举的过程就转而干其他事了。
学一个东西其实就不能被它吓到,得站在巨人的肩膀上先总览一下,不能从太基础的东西学起,因为花了一天又一天,时间会压的你很沉,慢慢遇到点难度就没放弃了。
USB这块的基础代码库都算是比较完善的,从STM32的官网就能下载到例程,慢慢动手改参数,看看每个参数改了之后的变化,基本改了一遍就会大概清晰了。比如把一个鼠标改成一个键盘设备,在比如把一个鼠标改成复合型设备,就是带两个接口的设备,等等。反正学习就是不断地尝试。
参考资源:
STM32 USB full speed device libraryhttps://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32121.html#overviewUSB 简介 - USB中文网 (usbzh.com)http://www.usbzh.com/article/detail-33.htmlUSB HID报告描述符教程 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/27568561
报告描述符:
HID设备最重要的就是报告描述符,描述HID接口设备的类型以及具体每个位置的数据所代表的意义,比如可以描述鼠标左键所对应的数据是哪个位,鼠标滚动对应的数据是修改哪个值。总之,报告描述符就是用来描述HID接口的.
复合设备:
laiyuanHID复合设备(键盘、鼠标)的实现 - USB中文网 (usbzh.com)
在使用一些USB键盘或鼠标的时候,特别是一些电竟高档HID设备时,经常发现这些设备会额外定义一些特别的快捷键,使得这些设备不仅有基础设备(如键盘,鼠标)的功能,也有一些特别的快捷功能(如系统声音的放大放小)。甚至更有一些复杂的设备,只需要一个USB接口,就同时支持鼠标键盘功能或在键盘的额外区域支持触模板功能。对于这种复杂的HID设备,是怎么实现的呢?这里有两种方法:
- 第一种方法是使用多个接口多个报表描述符来实现。
- 第二种方法是使用一个接口一个报表描述符实现,这个报表描述符中包括多个应用功能集合。
我们知道,对于USB设设接口描述符的定义,其实就是设备的功能。一个普通的USB设备一般有几个接口描述符,它就有几个功能。不同的接口对应着不同的接口描述符。对于HID设备,这个接口中描述符也有一个与之对应的报表描述符。这样我们可以在一个USB设备中实现多个接口,每个接口对应的报表描述符实现不同的HID设备功能,如对于这些报表描述符实现与之对应的键盘功能,鼠标功能,触摸屏功功能。通过这种方法实现的设备在windows中的设备管理器中的硬件ID会到MI处。如对于PID,VID分别为0x1234,0x5678,bcdDevice为0xabcd的USB设备,,供如接口0实现键盘功能,接口1实现鼠标功能。那么这些特定的HID设备对应的硬件设备树如下:
- USB通用驱动usbccgp.sys(USB\VID_1234&PID_5678&REV_ABCD)
- USB 输入设备 (USB\VID_1234&PID_5678&REV_ABCD&MI_00)
- USB键盘(HID\VID_1234&PID_5678&REV_ABCD&MI_00)
- USB 输入设备 (USB\VID_1234&PID_5678&REV_ABCD&MI_01)
- USB鼠标(HID\VID_1234&PID_5678&REV_ABCD&MI_01)
- USB 输入设备 (USB\VID_1234&PID_5678&REV_ABCD&MI_00)
第一种的方式比较和普通的USB HID设备类似,只是多了一套接口描述符和HID报表描述符而已。关于接口描述符与HID报表描述符之间枚举的对应关系可见本站文章 USB复合HID设备报告描述符的区分 USB复合HID设备报告描述符的区分 - USB中文网
第二种方法是使用一个报表描述符包含多个应用集合实现。这样在windows系统中枚举出来的设备硬件设备树关系如下:
- USB 输入设备 (USB\VID_1234&PID_5678&REV_ABCD)
- USB鼠标(HID\VID_1234&PID_5678&REV_ABCD&Col_00)
- USB键盘(HID\VID_1234&PID_5678&REV_ABCD&Col_01)
其对应的报表描述符结构构如下:
05 01 //USAGE_PAGE (Generic Desktop)
09 02 //USAGE (MOUSE)
a1 01 //COLLECTION (Application)
85 01 //REPORTID 01
...
0xc0 //END_COLLECTION
05 01 //USAGE_PAGE (Generic Desktop)
09 06 //USAGE (Keyboard)
a1 01 //COLLECTION (Application)
85 02 //REPORTID 02
...
0xc0 //END_COLLECTION
这里需要使用ReportId来区分数据来源。