1. 程式人生 > >Android OTG (USB Hos) 程式設計

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通訊有幾點要說明:

  1. USB通訊協議中有4中傳輸模式,分別是:
    ①Bulk Transaction
    ②Interrupt Transaction
    ③Control Transation
    ④Isochronous Transaction
    我採用了Bulk Transaction的傳輸模式,關於這一部分的瞭解可以參考USB通訊協議

  2. Bulk Transaction顧名思義是大塊資料傳輸事務:

①in表示輸入事務處理:USB主機從總線上某個USB裝置上接收資料包;
②out表示輸出事務處理:USB主機把一個數據包輸出到總線上某個USB裝置的接收過程

四、備註

注1:關於getParcelableExtra()

  1. Intent獲取: 當在startActivity中傳入一個隱式Intent時,首先通過對Intent解析,決定啟動哪一個Activity

  2. 資訊傳遞:獲取該Intent中的資料和動作,intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) 中的UsbManager.EXTRA_DEVICE就是儲存在該Intent的extras bundle中的USB裝置資訊

  3. Parcelable意義:Parcelable屬於Android程式設計中程序間通訊(IPC)的一種機制,在兩個Activity間傳遞簡單的資料如String,可以直接通過intent.putExtra(String,s);在兩個Activity間傳遞類物件,則需要通過Parcelable介面

  4. Parcelable的原理:將要傳遞的類內的屬性分解為儲存在Parcel中的基本型別,而這些型別是可以跨程序邊界封送的;使用時將要傳遞類直接implements Parcelable即可實現介面類

注2: USB裝置和USB裝置組

USB裝置

USB裝置

注3:Android中使用無線連線adb除錯

手機只有一個USB口,插上OTG裝置就無法看log…了?其實可以使用無線連線adb除錯,步驟如下:

  1. 下載一個有root許可權的終端應用,我下了一個終端模擬器,還挺好用,應該要root手機咯

  2. 通過終端模擬器對adb連線埠進行設定,輸入如下指令:

    這裡寫圖片描述

  3. 設定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程式設計進行比較學習。