安卓开发中的USB转串口通讯
本文使用GitHub上开源的”hoho.android.usbserial”USB串口库。该库基于“Android USB Host API”,驱动完全由java开发,无需root,不限内核,很是方便。
简介Anddroid USB Host API
原文链接
android.hardware.usb包下提供了USB开发的相关类。
我们需要了解UsbManager、UsbDevice、UsbInterface、UsbEndpoint、UsbDeviceConnection、UsbRequest、UsbConstants。
1、UsbManager:获得Usb的状态,与连接的Usb设备通信。
2、UsbDevice:Usb设备的抽象,它包含一个或多个UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(endpoint)发送和接收数据。
3、UsbInterface:定义了设备的功能集,一个UsbDevice包含多个UsbInterface,每个Interface都是独立的。
4、UsbEndpoint:endpoint是interface的通信通道。
5、UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
6、UsbRequest:usb 请求包。可以在UsbDeviceConnection上异步传输数据。注意是只在异步通信时才会用到它。
7、UsbConstants:usb常量的定义,对应linux/usb/ch9.h
安卓串口库(hoho.android.usbserial)
该库包含了CH34X系列等多款USB串口芯片的驱动,且提供UsbSerialDriver接口供用户自定义驱动.
常用的类及接口:
1.UsbSerialDriver接口
该接口的实现类作为USB串口的驱动,需要重写其中的getDevice方法和getPorts方法,其中getDevice()返回一个”原始设备”实例(详见Android USB Host API),getPorts()返回所有可用的UsbSerialPort实例.
2.UsbSerialProber类
从类名可以看出,该类用于探测可用的USBSerial设备,可以使用它来获取当前可用的USBSerial设备列表.
-方法getDefaultProber用于获取默认的Prober实例
-方法findAllDrivers用于获取所有的UsbSerialDriver列表
/**
* Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers}
* from the currently-attached {@link UsbDevice} hierarchy. This method does
* not require permission from the Android USB system, since it does not
* open any of the devices.
*
* @param usbManager
* @return a list, possibly empty, of all compatible drivers
*/
public List findAllDrivers(final UsbManager usbManager);
1
2
3
4
5
6
7
8
9
10
-方法probeDevice用于根据兼容UsbDevice获取单个UsbSerialDevice实例
/**
* Probes a single device for a compatible driver.
*
* @param usbDevice the usb device to probe
* @return a new {@link UsbSerialDriver} compatible with this device, or
* {@code null} if none available.
*/
public UsbSerialDriver probeDevice(final UsbDevice usbDevice);
1
2
3
4
5
6
7
8
3.UsbSerialPort接口
该接口提供了所有的与USB串口设备通讯的方法,通过UsbSerialDriver.getPorts()可以获取该UsbSerialDriver实例的所有端口实例.
4.SerialInputOutputManager类
这是一个实现了Runnable接口的类,从类名可以看出,该类提供了对串口设备I/O的管理.通过一个UsbSerialPort实例作为参数来构造一个管理器实例,使用时应该为该管理器绑定一个SerialInputOutputManager.Listener实例,该Listener使用回调的方式提供串口数据和串口异常数据
UsbSerialInputOutputManager.Listener提供了两个抽象方法:onNewData(byte[] data)和OnRunError(Exception e).当有收到新数据时将会调用onNewData方法,数据data作为参数传回;运行错误发生时调用onRunError方法,返回异常类实例e.
writeAsync()方法用来”线程安全”的向输出流写数据.
1.获取支持的USB Devices列表。
首先初始化一个UsbManager的实例,然后用该UsbManger实例做参数,调用UsbSerialProber实例的findAllDrivers方法获取所有的UsbSerialDrivers实例.因为最终需要UsbSrialPort进行通讯,所以在获取所有的UsbSerialDrivers实例后应该调用它的getPorts方法获取其端口
贴上代码:
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
final List<UsbSerialDriver> drivers =
UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager);
final List<UsbSerialPort> result = new ArrayList<UsbSerialPort>();
for (final UsbSerialDriver driver : drivers) {
final List<UsbSerialPort> ports = driver.getPorts();
Log.d(TAG, String.format("+ %s: %s port%s",
driver, Integer.valueOf(ports.size()), ports.size() == 1 ? "" : "s"));
result.addAll(ports);
}
1
2
3
4
5
6
7
8
9
10
11
2.与串口设备通讯
首先初始化USBSerialPort并且为其设置必要的参数,使用该UsbSerialPort实例来构建一个SerialInputOutputManager对象(manager),并以此对象构建线程并执行.调用manager的writeAsync()方法来写数据,重写onNewData方法来处理读入的数据.
-为sPort设置必要的参数并开启端口:
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbDeviceConnection connection = usbManager.openDevice(sPort.getDriver().getDevice());
//初始化一个connection以实现USB通讯,详见Android USB Host API
try {
//开启端口
sPort.open(connection);
//为sPort设置参数
sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
} catch (IOException e) {
Log.e(TAG, "Error setting up device: " + e.getMessage(), e);
try {
sPort.close();
} catch (IOException e2) {
// Ignore.
}
sPort = null;
return;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-构建SerialInputOutputManager对象并创建执行线程
//Git的源码中使用了ExecutorService来异步执行线程
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
//构建Manager对象并为其设置监听器
private SerialInputOutputManager mSerialIoManager = new SerialInputOutputManager(sPort, mListener);
private final SerialInputOutputManager.Listener mListener =
new SerialInputOutputManager.Listener() {
@Override
public void onRunError(Exception e) {
Log.d(TAG, "Runner stopped.");
}
@Override
public void onNewData(final byte[] data) {
SerialConsoleActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
SerialConsoleActivity.this.updateReceivedData(data);
}
});
}
};