Android OTG (USB Hos) 程式設計
前言:最近在做一個汽車發動機故障檢測的專案,負責APP開發。汽車發動機將各種資料通過OTG傳輸到Android手機,APP可以實時顯示資料。
一、許可權
1. 宣告支援USB Hos模式
- 在AndroidManifest中宣告該應用支援USB Hos模式
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<uses-feature
android:name="android.hardware.usb.host" />
2. 宣告應用程式能夠獲得接入USB裝置時的通知
(1)指定USB裝置接入時通知
如果USB資訊寫在應用程式配置檔案裡,則APP只會響應指定的這個USB裝置
如果不指定USB裝置,則任何USB裝置接入時都能響應並啟動應用,但是能不能繼續執行就是另一回事了
- 在AndroidManifest中宣告指定的USB裝置,裝置資訊存放在resource=”@xml/device_filter” 資料夾下
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name ="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
- 這是我的USB裝置資訊
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1155"
product-id="22336"
/>
</resources>
(2)不指定USB裝置接入時通知
- 在AndroidManifest中宣告該應用能夠獲得USB裝置接入時的通知
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
</activity>
二、發現裝置
1. 列舉所有接入裝置
略
2. 列舉指定裝置
在主Activity中的OnCreate()中加入如下程式碼:
- 獲取指定USB裝置的Intent,通過的
get<type>Extra
方法獲得在AndroidManifest中靜態註冊的Intent傳遞的USB裝置資訊
Intent intent = getIntent();
usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
usbDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- 獲取USB裝置資訊
deviceName = usbDevice.getDeviceName();
deviceVendor = usbDevice.getVendorId();
deviceText.setText("#Device Info : "+usbDevice.toString()+"\n"+"#Device Name : "+
deviceName+"\n"+"#Device Vendor : "+deviceVendor);
注[1]:關於intent.getParcelableExtra()
三、與裝置通訊
1. 通訊許可權
在列舉完已經接入的USB裝置,並和指定裝置通訊前,獲得對該裝置的許可權是必須的。如果採用指定裝置接入並列舉的方法,則無需再請求明確的許可權,因為getIntent()時已經獲得了對該裝置的許可權;否則應當檢查是否有許可權,如果使用者拒絕了你訪問該裝置的請求,你會收到一個執行時錯誤
- 我的程式使用Intent發現接入的USB裝置並啟動應用程式,而且使用者允許應用程式處理該Intent,所以該應用可以自動的接收許可權。Intent靜態註冊見AndroidManifest中宣告,使用者允許接收許可權如圖:
2. 通訊
Android中與OTG(USB Hos)相關的API我的翻譯在Android API 翻譯之 UsbDevice,通訊主要就是呼叫這些API:UsbManager->UsbDevice->UsbInterface->UsbEndpoint->UsbDeviceConnection
注[2]:Android OTG API 示意圖
通過程式碼測試,發現我的OTG裝置有2個Interface,其中Interface-0有一個Endpoint-0(輸入);Interface-1有兩個Endpoint(其中Endpoint-0是輸入,Endpoint-1是輸出)。故在程式碼中呼叫Interface-1實現資料收發
- 與USB裝置連線並收發資料寫到了button點選事件裡
UsbInterface usbInterface = usbDevice.getInterface(1);
UsbEndpoint inEndpoint = usbInterface.getEndpoint(0);
UsbEndpoint outEndpoint = usbInterface.getEndpoint(1);
UsbDeviceConnection connection = usbManager.openDevice(usbDevice);
connection.claimInterface(usbInterface, true);
sendString = "0xa5";
sendBytes = HexString2Bytes(sendString);
int out = connection.bulkTransfer(outEndpoint, sendBytes, sendBytes.length, 5000);
displayToast("傳送:"+out+" # "+sendString+" # "+sendBytes);
receiveBytes = new byte[32];
int in = connection.bulkTransfer(inEndpoint, receiveBytes, receiveBytes.length, 10000);
receiveString = Bytes2HexString(receiveBytes);
displayToast("應答:"+in+" # "+receiveString+" # "+receiveBytes.length);
和USB通訊有幾點要說明:
USB通訊協議中有4中傳輸模式,分別是:
①Bulk Transaction
②Interrupt Transaction
③Control Transation
④Isochronous Transaction
我採用了Bulk Transaction的傳輸模式,關於這一部分的瞭解可以參考USB通訊協議Bulk Transaction顧名思義是大塊資料傳輸事務:
①in表示輸入事務處理:USB主機從總線上某個USB裝置上接收資料包;
②out表示輸出事務處理:USB主機把一個數據包輸出到總線上某個USB裝置的接收過程
四、備註
注1:關於getParcelableExtra()
Intent獲取: 當在startActivity中傳入一個隱式Intent時,首先通過對Intent解析,決定啟動哪一個Activity
資訊傳遞:獲取該Intent中的資料和動作,
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
中的UsbManager.EXTRA_DEVICE就是儲存在該Intent的extras bundle中的USB裝置資訊Parcelable意義:Parcelable屬於Android程式設計中程序間通訊(IPC)的一種機制,在兩個Activity間傳遞簡單的資料如String,可以直接通過intent.putExtra(String,s);在兩個Activity間傳遞類物件,則需要通過Parcelable介面
Parcelable的原理:將要傳遞的類內的屬性分解為儲存在Parcel中的基本型別,而這些型別是可以跨程序邊界封送的;使用時將要傳遞類直接implements Parcelable即可實現介面類
注2: USB裝置和USB裝置組
注3:Android中使用無線連線adb除錯
手機只有一個USB口,插上OTG裝置就無法看log…了?其實可以使用無線連線adb除錯,步驟如下:
下載一個有root許可權的終端應用,我下了一個終端模擬器,還挺好用,應該要root手機咯
通過終端模擬器對adb連線埠進行設定,輸入如下指令:
設定PC端,進入到Android-SDK/platforms目錄,執行如下命令:
adb connect ip.address:5555
通過點選手機wifi,就能查到本機ip,我的是192.168.1.100
設定無誤,就可以得到正確輸出:connect to …
這樣,就可以使用adb對手機進行除錯了,在Eclipse的裝置列表中也有device的資訊辣~(≧▽≦)/~
五、後記
Android OTG程式設計和BLE4.0其實是非常類似的,都屬於Android同外設的通訊,前者是串列埠通訊,後者是無線通訊。不妨將Android BLE (藍芽4.0) 程式設計和OTG程式設計進行比較學習。