USB通信
USB HID通讯学习
C#和USB HID进行通讯,实现发送、接收数据主要是通过两个函数实现的FileStream.Write(...)(发送数据)、FileStream.Read(...)(接收数据)。Write和Read是同步,BeginWrite和BeginRead是异步。
学习思路:先学会如何看懂USB通信协议,然后再去研究对应的WIN32API。
HID设备描述符
HID设备连接到USB主机后,主机通过发送Get_Descriptor请求读取HID设备的描述符,了解描述符对了解USB设备是至关重要的。在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。
USB报告描述符(Report Descriptor)
USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符。是描述一个报告以及报告里面的数据是用来干什么用的。通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数据。更详细的说明请参看USB HID协议,该协议可从Http://www.usb.org下载。
文章推荐:
Repoert Id
OUT
向HID写数据时,每个包传输的第一个*byte*为写数据(*OUT*)*report ID*,上、下位机必须一致。
IN
HID返回数据时,每个包的第一个byte也必须是读数据(IN)report ID,在下位机中,IN report ID的定义一定要和发送包的第一个byte相一致,否则读取错误。
操作流程
- 设置设备的VID、PID,初始化
HIDInterface.HidDevice hidDevice = new HIDInterface.HidDevice();
- 获取所有连接的hid设备路径
GetHidDeviceList ()
- 打开文件CreateFile()返回指定文件的句柄
- 返回HID设备对象指定的集合的属性
HidD_GetAttributes()
- 获取序列号字符串例程返回顶级集合的嵌入式字符串,该集合标识集合物理设备的序列号
HidD_GetSerialNumberString()
- 创建一个
FileStream
文件流,对文件流进行读写操作**Write()``Read ()``BeginRead()
BeginWrite()
**
- 每次调用 BeginRead 时都必须调用一次 EndRead。 无法结束一个读取进程就开始另一个读取可能导致死锁等不希望出现的行为。
- 对于 BeginWrite 中的每个 IAsyncResult,必须正好调用一次 EndWrite。 EndWrite 将一直被阻止到 I/O 操作完成时。
文章推荐:
官方文档学习
HID概念
HID由两个基本概念组成,即报告描述符和报告。报告是设备和软件客户端之间交换的实际数据。报告描述符描述了设备支持的格式和含义。
报告书
应用程序和HID设备通过报告交换数据。共有三种报告类型:输入报告,输出报告和功能报告。
报告类型 | 描述 |
---|---|
输入报告 | 从HID设备发送到应用程序的数据,通常是在控件状态更改时。 |
输出报告 | 从应用程序发送到HID设备(例如,键盘上的LED)的数据。 |
功能报告 | 可以手动读取和/或写入的数据,通常与配置信息有关。 |
报告描述符中定义的每个顶级集合可以包含零(0)个或更多每种类型的报告。
使用表
在USB-IF工作组发布了HID用法表是描述什么HID设备被允许这样做的报告描述符的一部分。这些HID用法表包含一个带有用法说明的列表,这些说明描述了报告描述符中描述的特定项目的预期含义和用途。例如,为鼠标的左键定义了用法。报告描述符可以定义应用程序在报告中可以找到鼠标左键当前状态的位置。用法表分为几个名称空间,称为“用法页”。每个“用法”页面都描述了一组相关的用法,以帮助组织文档。用法页面和用法的组合定义了用法ID,该ID唯一标识用法表中的特定用法。
https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/
问题总结
操作流程问题
- 不要把所有的设备都打开,找到需要的节约资源
- CreateFile打开成功以后,如果出现异常,常见的问题就是参数传错了,对比API文档多试试
- 打开成功以后再向里面输入输出数据
数据格式问题
- report ID is 0x07. report ID是07,方法有错误,最后计算成了08,report ID不能错需要 互相对应
- 键盘设置软件关闭掉,否则端口抢占拿不到数据
报文解析
如何查看报文
如何计算长度
如何找到对应设备
数据格式
- 带有IN 可以正常返回数据,OUT的只能返回reportId ffff
- 发送 提交数据的时候数据格式,缓冲区大小,数据长度需要注意,不能写错
其他问题
问题一:
当使用供应商定义的HID报告时,是否可以发送小于报告中指定的最大大小的数据包?我已经将HID输入报告设置为64字节计数,只要我将64字节的数据包发送到PC,一切都很好,但是如果我发送的字节数更少的数据包,则PC永远不会收到它。
问题二:
我发现自己做错了。
这是一个可行的示例:
1)插入具有接口的HID兼容设备(我使用的第一个没有!)。
2)使用HidD_GetHidGuid获取HID GUID。
3)调用SetupDiGetClassDevs,然后(可选)使用SetupDiEnumDeviceInfo和SetupDiGetDeviceRegistryProperty查看结果。
4)调用SetupDiEnumDeviceInterfaces,确保使用GUID参数。我在那里使用NULL,希望它将为我提供最完整的接口集,但是却给出错误259。
问题三:
GetHidDeviceList无法获取hid设备列表,项目配置修改为X86