从 Android USB 配件读取数据的更好方法

Lev*_* M. 5 java usb android accessory

我正在用 Java 编写一个 Android 应用程序,该应用程序使用 Android 配件 API 与 USB 配件进行通信。

谷歌文档并没有给出实际读取和写入数据,只是如何打开附件进行通信的例子。

它还说明了两件事:

  1. 通信应该在后台线程中完成,而不是在 UI 线程上。
  2. 读取缓冲区的长度应至少为 16384 字节,因为这是 Android Open Accessory 协议的最大消息长度。

我实现了这样的阅读:

/** boiler plate from example docs: **/
fileDescriptor = usbManager.openAccessory(accessory);

if (fileDescriptor != null) {
    FileDescriptor fd = fileDescriptor.getFileDescriptor();
    inputStream = new FileInputStream(fd);
    readBuffer = new byte[16384];
    // ... some more code that is not relevant for reading data ... //
}

/** my code in separate thread: **/

int read;

while ((read = inputStream.read(readBuffer)) >= 0) {
    // ... parse message and do stuff with it ... //
}
Run Code Online (Sandbox Code Playgroud)

这段代码有效,我从附件中获得了正确的数据,但它给我的应用程序逻辑带来了问题:

  1. 读取函数可以无限期地阻塞等待更多数据。
  2. 它有时会在缓冲区中返回多个消息,背靠背,所以我不知道它何时或如何决定附件已完成发送并应返回累积的字节。
  3. 我还需要向附件发送数据,但是从两个单独的线程读取和写入 USB 会导致错误。

我无法控制附件上运行的代码,它是一个封闭的产品,但我知道它的协议:它发送带有 2 个字节前缀的消息,指示消息的大小。

所以,我试过:

read = inputStream.read(readBuffer, 0, 2);

if (read == 2) {
    int size = (readBuffer[0] & 0xff) + ((readBuffer[1] & 0xff) << 8);
    read = inputStream.read(readBuffer, 2, size);
}
Run Code Online (Sandbox Code Playgroud)

第一次读取返回预期的消息大小,但第二次读取总是抛出 java.io.IOException: read failed: EIO (I/O error)

我还尝试available()在调用之前使用方法read来尝试找出可以读取的字节数,但这会引发IllegalArgumentException异常。

所以,我的问题是:

除了盲目地给read函数最大缓冲区并等待它返回之外,还有其他方法可以从Android Accessory读取数据吗?

如果没有,read如果在指定的时间范围内没有收到任何字节,是否至少有一种方法可以使函数超时?

有没有办法直接使用 Android Accessory 上的批量传输 API,Android USB Host API 允许的方式?

如果这一切都不可能,那么确保对附件的读取和写入不会相互干扰的正确逻辑是什么?

我正在使用的协议不能保证一对一的来回发送和接收。配件可以随时接收用户输入并将其发送到 Android 设备,而 Android 设备即使没有从配件收到任何数据,也需要向配件发送数据,因此简单的互斥锁是行不通的。