最近项目中有需要连接 USB 设备,App 运行在平板之上,只有一个 type-c 接口,只能通过 type-c 转串口进行连接,所以 App 直接接触的是 USB 设备。
使用 USB 设备遵照Google 官方文档开发即可。
配置清单
1 | <manifest ...> |
device_filter 可过滤具有指定属性的所有 USB 设备:
1 |
|
使用设备
- 发现连接的 USB 设备,具体方法是使用 Intent 过滤器在用户连接 USB 设备时接收通知,或者枚举已连接的 USB 设备。
- 请求用户授予连接到 USB 设备的权限(如果尚未获得权限)。
- 通过在适当的接口端点读取和写入数据来与 USB 设备通信。
1 | object UsbDeviceManager { |
封装
USB 有多种芯片,针对不同的芯片可能需要做识别,在 Github 上找到一个库UsbSerial,针对 USB 设备做了许多的封装,硬件同事提供的转串口工具为 CH34X 系列,该库也支持。参照文档使用起来很方便。
1 | public class UsbDeviceCommunicator extends BaseCommunicator { |
抽象
因为串口的不一致性,项目中有 3 中流传输方式:蓝牙、串口、USB。数据读取解析方式完全一致,所以抽象出 Communicator:
1 | public interface Communicator { |
BaseCommunicator:
1 | public abstract class BaseCommunicator implements Communicator { |
另外 2 个子类:
1 | public class SerialBoxCommunicator extends BaseCommunicator { |
小坑
UsbDeviceCommunicator 中,获取 mInputStream 时,包装 BufferedInputStream 使用的 bufferSize 设置为 32。三方库封装的 SerialInputStream 读取数据都是通过 usbConnection.bulkTransfer 来实现的:
1 | /** |
length 代表的读取数据的长度,会堵塞,直到读满 buffer。而 FileInputStream 的 read 方法为:
1 | /* |
len 代表最大可读取的字节数,不会一直堵塞,直到读满 buffer。 所以需要将 BufferedInputStream 的 bufferSize 设置小一点(默认8192),否则使用默认值一直读满 8192 个字节会等待较久的时间,不符合每 200ms 发送一次 64 byte 的实际场景。
另外,当没有 DevicePermission 时会弹窗,如果一直弹不太合适,所以有一个绕过弹窗验证的思路,可以参考一下,待验证。