1、最近在公司调试USB - HID ,给客户进行二次开发,其中就涉及Windows 平台和Android 平台和Linux 平台。
在Window 平台早已完成而且网上资料也是最多的,现在公司目前产品大多用于一些Android 平板上,因此,Android USB Host 进行一番研究。
这篇文章,也是记录这其中遇到最大的问题,足足搞了一个多星期才想通。百度都翻遍了,还是还是没有找打答案,最终,把USB- HID 类协议翻看一遍,才解决问题。
2、Android USB Host与HID通讯,就目前Google Developer提供的方法有bulkTransfer()与controlTransfer(),看是简简单单的两个方法,要实现真正的通讯可谓要难倒一大片人,我一开始就是这样,这对和我一样不懂HID及外设等底层通讯原理的人更是一个头两个大,况且不同的HID具体通讯机制也不同,因设备而异,可见USB 真的不是一般的复杂。
百度找遍了,也没有发现一个系统介绍两个方法的使用和两个方法具体参数是怎么得到,为此,特地写下这篇文章,记录一下,也防止以后自己忘记,也让方便其他人。
/**
* Performs a control transaction on endpoint zero for this device.
* The direction of the transfer is determined by the request type.
* If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
* {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
* and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
* is a read.
*
* This method transfers data starting from index 0 in the buffer.
* To specify a different offset, use
* {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}.
*
*
* @param requestType request type for this transaction
* @param request request ID for this transaction
* @param value value field for this transaction
* @param index index field for this transaction
* @param buffer buffer for data portion of transaction,
* or null if no data needs to be sent or received
* @param length the length of the data to send or receive
* @param timeout in milliseconds
* @return length of data transferred (or zero) for success,
* or negative value for failure
*/
public int controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout);
1、看看谷歌官方介绍可以知道,这个是设备使用控制管道和端点0,进行传输的方法。
2、这个方法一共7个参数,而最难理解的却是前面4个,为了理解这个4各参数,我翻遍百度,足足找了一个多星期也没有搞明白。
最后,实在没有办法,在看USB 协议中,有关HID 部分。
仔细观察可以发现,这个7个参数,和Linux的libusb库中一个关于控制传输的函数类似
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
3、后来查看网上一片文章发现,其实Android版本上其实已经把这个libusb搞上去了,我说难怪这个相似。大神博客
在USB HID类中,只有两个种通讯方式,一种使用控制管道(默认管道,即端点0) ,进行双向通讯的控制传输,和使用单一的中端管道的中端传输。
网上好多文章都讲解前面4个参数的,但是个人感觉他们都没有讲到位,其中比较好的几篇
Android controlTransfer 参数解析 这篇文章看似将的很有条理,其实作者也没有区分,这个其实讲个标准USB 通讯,不是USB - HID的。
Android USB Host 与 HID 之通讯方法(bulkTransfer()与controlTransfer()方法使用) 这篇文章讲的是USB - HID 类的,但是还是描述模模糊糊。
有关Android Usb Host开发 这篇文章是翻看百度看过最好的一篇文章,讲清楚4个参数的计算方式,但是还是没有讲清楚这4参数的具体由来,
因此,我在这位大神文章的基础上,整理一下,我最近的研究结果。
4、借用大神的原话:
int requestType:确定数据流的方向、请求类型以及接收端;由于是与HID通信,所以它只能是0010 0001和1010 0001,再把它转为16进制(别告诉我不会16进制)填上去就可以了。对于这个参数,比特位7是指数据传输的方向:从主机到设备(OUT)为0,从设备到主机(IN)为1;比特位6到5是指请求类型:USB标准请求为00,USB类请求为01,厂商的自定义请求为10;比特位4到0是指接收端:指向设备(00000)、专属接口(00001)、端点(00010)、设备中的其它元件(00011)。
int request:这个参数是对应的请求号。在我的demo中,使用到的请求是Set Report(因为在我的demo中需要发送报表命令请求数据,所以才用Set Report;不同情况要不同请求),其对应的值就是0x09(查一下就知道了)了。
int value:可将请求传递给设备,有两个字节。对应于Set Preport,高字节是报告类型(02为输出,03为特征),低字节是报告ID(默认为0)。
int index:可将请求传递给设备,有两个字节。典型的应用是传递索引或者诸如接口或端点号的偏移量(这些需要查询自己的设备信息了,我这里的HID的接口索引值为0)。
5、解析,个人补充,准备开奖了:
1、其实,这个4个参数,一共8个字节,是对应于USB - HID 设备类的特殊USB 请求方式的8字节数据。
关于USB 请求方式,可以查看我的另一篇文章《USB -HID 学习总结》。
2、HID设备类特定的命令(请求)有6个, 它们分别是 Get_Report、Get_Idle、Get_Protocol、 Set_Report、Set_Idle和Set_Protocol
(1)requestType: 定义请求类型
因此,对于requestType, 只有两种方式分别是0xA1(输入) 和 0x21(输出), 对于请图中的 位6-5 可以在一个USBTreeView 软件中看到,usb设备的种类。
如下图:
(2)request: 定义请求的内容
HID 特殊请求类如下图:
那么如果确定请求的类型呢????
首先要明白,USB HID 是以报告的形式进行通讯的,对于使用默认端点0的控制管道通讯,则一般有两个
即:SET_ERPORT 和 GET_REPORT 取值 0x09 和 0x01
一般,SET_REPORT 用于主机Host 向 Hid从机发送报告数据, GET_REPORT 用于从机向主机返回报告数据。
(3)value:
对于第3个参数,这篇文章有仔细的说明点击打开链接。
高字节说明描述符的类型
0x21:HID描述符
0x22:报告描述符
0x23:物理描述符
低字节非0时被用来选定物理描述符
对于GET_REPORT 和 SET_REPORT请求,
高字节表示报告类型 0x01: input (输入报告) 0x02: output (输出报告) 0x03: feature (特征报告) Other: reserved
低字节表示Report ID(报告ID)
对于报告ID, 需要注意的一点是,如果设备查看不到报告ID, 则默认为0(至于为什么为0, 这是HID 协议规定的 )如下图:
又有一个问题了,怎么查看HID 设备的Report ID( 报告ID) 和 使用请求的报告类型 呢????,这就还是需要那个强大的软件了,USBTreeView 查看HID 设备的Report Descriptor (报告描述符), 在HID 设备类协议中有提到,报告在这里意思是数据传输(data transfer),而报告描述符是对这些传输的数据作用途(usage)上的说明。
如下图,我近期调试使用的HID 设备:
(4)index: 2 字节数值,根据不同的 bRequest 有不同的意义
对于GET_REPORT 和 SET_REPORT,一般为HID的interface索引值,一般为0
(5)buffer、length、timeout 三个参数,谷歌官方也给出解释,分别是:
输出流缓冲区(即报告内容),和 输出流长度(报告长度)及超时时间
其中,buffer 是从索引0开始的,
对于length(报告长度),可以从HID设备的报告描述符中获取到(又一次提到报告描述符,可见其重要性),如下图
针对上面的说明,列出的我的使用controlTranfer() 方法配置的参数
(1)主机发送 SET_REPORT -> Host主机到HID从机
int outLength = mConnection.controlTransfer(0x21, 0x09, 0x301, 0, outputStream, 0x100 - 1, timeOut);
(2)HID从机 响应 GET_REPORT
int recLength = mConnection.controlTransfer(0xA1, 0x01, 0x302, 0, inputStream, 0x100 - 1, timeOut);
3、几个HID 特定请求的参数
主机通过控制端点获取一个Report
域 |
值 |
bmRequestType |
0xA1 |
bRequest |
0x01 |
wValue |
高字节表示报告类型 0x01: input 0x02: output 0x03: feature Other: reserved 低字节表示ReportID,如不使用设为0 |
wIndex |
HID的interface索引值 |
wLength |
Report长度 |
Data |
Report内容 |
主机发送一个Report给设备,用以设置input,output或者feature
域 |
值 |
bmRequestType |
0x21 |
bRequest |
0x09 |
wValue |
高字节表示报告类型 0x01: input 0x02: output 0x03: feature Other: reserved 低字节表示ReportID,如不使用设为0 |
wIndex |
HID的interface索引值 |
wLength |
Report长度 |
Data |
Report内容 |
域 |
值 |
bmRequestType |
0xA1 |
bRequest |
0x02 |
wValue |
高字节0 低字节表示ReportID,如不使用设为0 |
wIndex |
HID的interface索引值 |
wLength |
1 |
Data |
空闲速率 |
域 |
值 |
bmRequestType |
0x21 |
bRequest |
0x0A |
wValue |
高字节新的速率 低字节表示ReportID,如不使用设为0 |
wIndex |
HID的interface索引值 |
wLength |
0 |
Data |
无 |
域 |
值 |
bmRequestType |
0xA1 |
bRequest |
0x03 |
wValue |
0 |
wIndex |
HID的interface索引值 |
wLength |
1 |
Data |
0=Boot Protocol 1=Report Protocol |
域 |
值 |
bmRequestType |
0x21 |
bRequest |
0x0B |
wValue |
0=Boot Protocol 1=Report Protocol |
wIndex |
HID的interface索引值 |
wLength |
0 |
Data |
无 |
参考文章
关于Android USB Host 中,controlTransfer()方法的参数解析就这么多了,这可以说明一个HID类就这么复杂,可见整个USB 体系的强大。
这里还是需要感谢网上一些大神的无私分享,才有今天的总结。
下一篇将讲述bulkTransfer()方式参数解析。