Android USB通信

1.說在前面的話

這次做了一個項目,要求android端與外接設備進行通信,用到的是otg線連接開發板。然而網上有關USB host通信的資料很少,這裏我就把自己的想法以及遇到的坑說一下吧(鄙視鄙視鄙視)。
2.Android Studio 配置
2.1Manifest配置

    <!--android作爲host端的權限-->
    <uses-feature android:name="android.hardware.usb.host" android:required="true" />


     <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                <meta-data
                    android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                    android:resource="@xml/usbfilter">
                </meta-data>
            </activity>


這裏的action是外接設備被檢測的動作,下面的usbfilter是過濾文件,裏面存放外接設備的vendor-id和product-id。
2.2Usbfilter配置

    <resources xmlns:android="http://schemas.android.com/apk/res/android">
        <usb-device vendor-id="1234" product-id="1234" />
    </resources>


配置這個主要爲了過濾出你的設備,然後再android端會提示你打開相應的app。這兩個id可以在電腦上面獲取,將你的設備利用usb線插入電腦,然後再設備管理器裏面找到你的設備,右鍵屬性,在詳細信息中查看你的硬件id(上面顯示的是16進制的),將他轉換成10進制的數字就可以了。或者利用這個軟件進行查詢。
3.通信

    public class MainActivity extends AppCompatActivity {
     
        private static final String TAG = MainActivity.class.getSimpleName();
        private EditText et_content;
        private TextView tv_receive;
        private Button btn_send, btn_receive;
     
        private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
        private HashMap<String, UsbDevice> deviceList;  //設備列表
        private UsbManager usbManager;  //USB管理器:負責管理USB設備的類
        private UsbDevice usbDevice;   //找到的USB設備
        private UsbInterface usbInterface;  //代表USB設備的一個接口
        private UsbDeviceConnection deviceConnection;  //USB連接的一個類。用此連接可以向USB設備發送和接收數據,這裏我們使用這個類下面的塊傳輸方式
        private UsbEndpoint usbEpIn;  //代表一個接口的某個節點的類:讀數據節點
        private UsbEndpoint usbEpOut;  //代表一個接口的某個節點的類:寫數據節點
        private PendingIntent intent; //意圖
     
        private byte[] sendBytes;  //要發送信息字節
        private byte[] receiveBytes;  //接收到的信息字節
     
        private Message message = new Message();
        private DataUtil dataUtil = new DataUtil();
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
     
            intent = PendingIntent.getBroadcast(this,0,new Intent(ACTION_USB_PERMISSION),0);
            registerReceiver(broadcastReceiver, new IntentFilter(ACTION_USB_PERMISSION));
     
            initUsbDevice();
            initView();
            initListener();
        }
     
        //初始化USB設備
        private void initUsbDevice() {
            usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
            deviceList = usbManager.getDeviceList();
            Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
            while (deviceIterator.hasNext()) {
                UsbDevice device = deviceIterator.next();
                //找到指定的設備
                if (device.getVendorId() == 2588 && device.getProductId() == 9030) {
                    usbDevice = device;
                    Log.e(TAG, "找到設備");
                }
            }
            findInterface();
        }
     
        //獲取設備接口
        private void findInterface() {
     
            if (usbDevice == null) {
                Log.e(TAG, "沒有找到設備");
                return;
            }
     
            for (int i = 0; i < usbDevice.getInterfaceCount(); i++) {
                //一個設備上面一般只有一個接口,有兩個端點,分別接受和發送數據
                UsbInterface uInterface = usbDevice.getInterface(i);
                usbInterface = uInterface;
                Log.e(TAG, usbInterface.toString());
                break;
            }
     
            getEndpoint(usbInterface);
     
            if (usbInterface != null) {
                UsbDeviceConnection connection = null;
                //判斷是否有權限
                if (usbManager.hasPermission(usbDevice)) {
                    Log.e(TAG, "已經獲得權限");
                    connection = usbManager.openDevice(usbDevice);
                    Log.e(TAG, connection == null ? "true" : "false");
                    if (connection == null) {
                        Log.e(TAG, "設備連接爲空");
                        return;
                    }
                    if (connection != null && connection.claimInterface(usbInterface, true)) {
                        deviceConnection = connection;
                        Log.e(TAG, deviceConnection == null ? "true" : "false");
                    } else {
                        connection.close();
                    }
                    
                } else {
                    Log.e(TAG, "正在獲取權限...");
                    usbManager.requestPermission(usbDevice, intent);
                    if (usbManager.hasPermission(usbDevice)) {
                        Log.e(TAG, "獲取權限");
                    } else {
                        Log.e(TAG, "沒有權限");
                    }
     
                }
            } else {
                Log.e(TAG, "沒有找到接口");
            }
        }
     
        //獲取端點
        private void getEndpoint (UsbInterface usbInterface) {
            for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                UsbEndpoint ep = usbInterface.getEndpoint(i);
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        usbEpOut = ep;
                        Log.e(TAG, "獲取發送數據的端點");
                    } else {
                        usbEpIn = ep;
                        Log.e(TAG, "獲取接受數據的端點");
                    }
                }
            }
        }
     
        //初始化
        private void initView() {
            et_content = (EditText) findViewById(R.id.et_content);
            tv_receive = (TextView) findViewById(R.id.tv_receive);
            btn_send = (Button) findViewById(R.id.btn_send);
            btn_receive = (Button) findViewById(R.id.btn_receive);
        }
     
     
        //初始化監聽
        private void initListener() {
            btn_send.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
     
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Log.e(TAG, usbDevice.getDeviceName());
                            Log.e(TAG, usbEpIn.getEndpointNumber() + "------" + usbEpOut.getEndpointNumber());
     
                            Log.e(TAG, deviceConnection == null ? "true" : "false");
                            byte[] sendData = new byte[4];
                            sendData[0] = (byte) 0x31;
                            sendData[1] = (byte) 0x32;
                            sendData[2] = (byte) 0x33;
                            sendData[3] = (byte) 0x34;
     
                            Log.e(TAG, sendData[0] + "");
                            int result = deviceConnection.bulkTransfer(usbEpOut, sendData, sendData.length, 3000);
                            Log.e(TAG, "發送狀態碼:" + result);
     
                            receiveBytes = new byte[1024];
                            result = deviceConnection.bulkTransfer(usbEpIn, receiveBytes, receiveBytes.length, 3000);
                            Log.e(TAG, "接受狀態碼:" + result);
                            Log.e(TAG, receiveBytes[0] + "" );
     
                            deviceConnection.releaseInterface(usbInterface);
                        }
                    }).start();
                }
            });
        }
     
        private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.e(TAG, intent.getAction());
                if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
                    boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
                    Log.e("granted", granted + "");
                }
            }
        };
     
        //取消廣播
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(broadcastReceiver);
        }
    }


這裏貼出所有代碼,記住接收和發送信息的處理要在子線程中運行。
4.爬坑


剛剛開始做項目的時候,那叫一個酸爽,很多坑。首先要注意你是以那種方式通信,host還是accessory,然後再去Manifest裏面添加相應的權限。其次明確你的傳輸方式,塊傳輸還是控制傳輸,兩個函數的參數都不一樣,最後收發信息的處理邏輯最好放到子線程中運行,防止app掛掉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章