很久沒有寫文章了,年前公司新開了一個項目,是和usb轉串口通訊相關的,需求是用安卓平板經過usb轉接後與好幾個外設進行通訊,一直忙到最近,才慢慢閒下來,趁着這個週末不忙,記錄下usb轉串口通訊開發的基本流程。javascript
咱們開發使用的是usb主機模式,即:安卓平板做爲主機,usb外設做爲從機進行數據通訊。整個開發流程能夠總結爲如下幾點:java
1.發現設備android
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
Map<String, UsbDevice> usbList = usbManager.getDeviceList();複製代碼
經過UsbManager這個系統提供的類,咱們能夠枚舉出當前鏈接的全部usb設備,咱們主要須要的是UsbDevice對象,關於UsbDevice這個類,官方是這樣註釋的:數組
This class represents a USB device attached to the android device with the android device acting as the USB host.複製代碼
是的,這個類就表明了android所鏈接的usb設備。函數
2.打開設備ui
接下來,咱們須要打開剛剛搜索到的usb設備,咱們能夠將平板與usb外設之間的鏈接想象成一個通道,只有把通道的門打開後,兩邊才能進行通訊。this
通常來講,在沒有定製的android設備上首次訪問usb設備的時候,默認咱們是沒有訪問權限的,所以咱們首先要判斷對當前要打開的usbDevice是否有訪問權限:spa
if (!usbManager.hasPermission(usbDevice)) {
usbPermissionReceiver = new UsbPermissionReceiver();
//申請權限
Intent intent = new Intent(ACTION_DEVICE_PERMISSION);
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
IntentFilter permissionFilter = new IntentFilter(ACTION_DEVICE_PERMISSION);
context.registerReceiver(usbPermissionReceiver, permissionFilter);
usbManager.requestPermission(usbDevice, mPermissionIntent);
}複製代碼
這裏咱們聲明一個廣播UsbPermissionReceiver,當接受到受權成功的廣播後作一些其餘處理:線程
private class UsbPermissionReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_DEVICE_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device.getDeviceName().equals(usbDevice.getDeviceName()) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
//受權成功,在這裏進行打開設備操做
} else {
//受權失敗
}
}
}
}
}
}複製代碼
接下來,咱們要找到具備數據傳輸功能的接口UsbInterface,從它裏邊兒找到數據輸入和輸出端口UsbEndpoint,通常狀況下,一個usbDevice有多個UsbInterface,咱們須要的通常是第一個,因此:code
usbInterface=usbDevice.getInterface(0);複製代碼
一樣的,一個usbInterface有多個UsbEndpoint,有控制端口和數據端口等,所以咱們須要根據類型和數據流向來找到咱們須要的數據輸入和輸出兩個端口:
for (int index = 0; index < usbInterface.getEndpointCount(); index++) {
UsbEndpoint point = usbInterface.getEndpoint(index);
if (point.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (point.getDirection() == UsbConstants.USB_DIR_IN) {
usbEndpointIn = point;
} else if (point.getDirection() == UsbConstants.USB_DIR_OUT) {
usbEndpointOut = point;
}
}
}複製代碼
最後,纔是真正的打開usb設備,咱們須要和usb外設創建一個UsbDeviceConnection,它的註釋很簡介的說明了它的用途:
This class is used for sending and receiving data and control messages to a USB device.複製代碼
它的獲取也很簡單,就一句代碼:
usbDeviceConnection = usbManager.openDevice(usbDevice);複製代碼
到這裏,理論上平板和usb外設之間的鏈接已經創建了,也能夠首發數據了,可是,咱們大部分狀況下還須要對usb串口進行一些配置,好比波特率,中止位,數據控制等,否則兩邊配置不一樣,收到的數據會亂碼。具體怎麼配置,就看你使用的串口芯片是什麼了,目前流行的有pl2303,ch340等,因爲篇幅問題,須要具體配置串口代碼的朋友私信我我發給你。
3.數據傳輸
到這裏,咱們已經能夠與usb外設進行數據傳輸了,首先來看怎麼向usb設備發送數據。
1.向usb外設發送數據複製代碼
在第二步中,咱們已經獲取了數據的輸出端口usbEndpointIn,咱們向外設發送數據就是經過這個端口來實現的。來看怎麼用:
int ret = usbDeviceConnection.bulkTransfer(usbEndpointOut, data, data.length, DEFAULT_TIMEOUT);複製代碼
bulkTransfer這個函數用於在給定的端口進行數據傳輸,第一個參數就是這次傳輸的端口,這裏咱們用的輸出端口,第二個參數是要發送的數據,類型爲字節數組,第三個參數表明要發送的數據長度,最後一個參數是超時,返回值表明發送成功的字節數,若是返回-1,那就是發送失敗了。
2.接受usb外設發送來的數據複製代碼
同理,咱們已經找到了數據輸入端口usbEndpointIn,由於數據的輸入是不定時的,所以咱們能夠另開一個線程,來專門接受數據,接受數據的代碼以下:
int inMax = inEndpoint.getMaxPacketSize();
ByteBuffer byteBuffer = ByteBuffer.allocate(inMax);
UsbRequest usbRequest = new UsbRequest();
usbRequest.initialize(connection, inEndpoint);
usbRequest.queue(byteBuffer, inMax);
if(connection.requestWait() == usbRequest){
byte[] retData = byteBuffer.array();
for(Byte byte1 : retData){
System.err.println(byte1);
}
}複製代碼
以上,就是usb轉串口通訊的基本流程,有些地方寫的不是很全面,好比接收usb外設數據的方法應該還有別的,不足之處歡迎指正。