usb协议
可以简单认为host拥有一棵usb树,在这棵树上挂载usb节点。查询和连接指定的device时需要给出两个信息:
- vendorId
- productId
因此对于high-level api,有以下查找device的实现:
// 和递归查目录树是一样的
public UsbDevice findDevice(UsbHub hub, short vendorId, short productId)
{
for (UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices())
{
UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor();
if (desc.idVendor() == vendorId && desc.idProduct() == productId) return device;
if (device.isUsbHub())
{
device = findDevice((UsbHub) device, vendorId, productId);
if (device != null) return device;
}
}
return null;
}
操作流程
使用usb4java的通信流程如下:
graph TD
A[find device]
A-->B[claim iface]
B-->C{get endpoint}
C-->|UsbConst.OUT| D[outPipe]
C-->|UsbConst.IN| E[inPipe]
D-->F[open pipe]
E-->F[open pipe]
F-->G[syn- or asyn- submit byte data]
G-->H[close pipe]
H-->I[release iface]
上述endpoint之后分出in和out两种pipe,与usb的位定义有关。具体地,endpoint有一个字节的描述符,其中0:3位表示usb number;4:6位保留,第7位指示是发送还是接收。因此通过指定第7位的值(使用UsbConst)来获取in/out pipe。
如何收发字节数据
当pipe打开后,有两种方式收发数据:同步和异步submit。以下主要介绍异步submit是如何收发数据的。
首先submit需要传入一个byte数组:
byte[] data = new byte[1024];
inPipe.asyncSubmit(data);
该数组会被UsbIrp对象包装,然后塞到一个IrpQueue中。
final UsbIrp irp = createUsbIrp();
irp.setAcceptShortPacket(true);
irp.setData(data);
...
this.queue.add(irp);
队列检测到有包进入,启用一个线程处理:
public final void add(final T irp)
{
this.irps.add(irp);
// Start the queue processor if not already running.
if (this.processor == null)
{