zoukankan      html  css  js  c++  java
  • Android实战技巧之四十九:Usb通信之USB Host

    零 USB背景知识

    USB是一种数据通信方式,也是一种数据总线。并且是最复杂的总线之中的一个。
    硬件上,它是用插头连接。

    一边是公头(plug)。一边是母头(receptacle)。比如。PC上的插座就是母头,USB设备使用公头与PC连接。
    眼下USB硬件接口分三种,普通PC上使用的叫Type。原来诺基亚功能机时代的接口为Mini USB;眼下Android手机使用的Micro USB。

    Host
    USB是由Host端控制整个总线的数据传输的。

    单个USB总线上,仅仅能有一个Host。


    OTG
    On The Go,这是在USB2.0引入的一种mode,提出了一个新的概念叫主机协商协议(Host Negotiation Protocol)。同意两个设备间商议谁去当Host。

    预了解很多其它USB知识,请參考USB官网以及以下这篇文章:
    http://www.crifan.com/files/doc/docbook/usb_basic/release/html/usb_basic.html

    一、Android中的USB

    Android对Usb的支持是从3.1開始的。显然是加强Android平板的对外扩展能力。而对Usb使用很多其它的,是Android在工业中的使用。

    Android工业板子一般都会提供多个U口和多个串口,它们是连接外设的手段与桥梁。

    以下就来介绍一下Android Usb使用模式之中的一个的USB Host。

    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

    二、USB插入事件

    Usb的插入和拔出是以系统广播的形式发送的。仅仅要我们注冊这个广播就可以。

        @Override
        protected void onResume() {
            super.onResume();
            IntentFilter usbFilter = new IntentFilter();
            usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
            usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
            registerReceiver(mUsbReceiver, usbFilter);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            unregisterReceiver(mUsbReceiver);
        }
    
        private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                tvInfo.append("BroadcastReceiver in
    ");
    
               if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                    tvInfo.append("ACTION_USB_DEVICE_ATTACHED
    ");
                } else if(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                    tvInfo.append("ACTION_USB_DEVICE_DETACHED
    ");
                }
            }
        };

    三、Usb插入时启动程序

    有些应用场景是,Usb插入后启动特定程序处理特定问题。
    我们的做法就是在Manifest中某个Activity增加Usb插入的action。

     <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/usbfilter" />

    在usbfilter中增加厂商id和产品id的过滤,例如以下:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <usb-device vendor-id="1234" product-id="5678" />
    </resources>

    结果就是,当此型号设备通过Usb连接到系统时,相应的Activity就会启动。

    四、UsbManager的初始化

    mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);

    五、列出Usb设备

            HashMap<String,UsbDevice> deviceHashMap = mUsbManager.getDeviceList();
            Iterator<UsbDevice> iterator = deviceHashMap.values().iterator();
            while (iterator.hasNext()) {
                UsbDevice device = iterator.next();
                tvInfo.append("
    device name: "+device.getDeviceName()+"
    device product name:"
                        +device.getProductName()+"
    vendor id:"+device.getVendorId()+
                        "
    device serial: "+device.getSerialNumber());
            }

    六、USB使用权限

    安卓系统对USB口的使用须要得到相应的权限,而这个权限要用户亲自给才行。
    首先我们会确认一下上一节中的device是否已经获得权限,假设没有就要主动申请权限:

                //先推断是否为自己的设备
                //注意:支持十进制和十六进制
                //比方:device.getProductId() == 0x04D2
                if(device.getProductId() == 1234 && device.getVendorId() == 5678) {
                    if(mUsbManager.hasPermission(device)) {
                        //do your work
                    } else {
                        mUsbManager.requestPermission(device,mPermissionIntent);
                    }
                }
    

    我们仍然使用广播来获得权限赋予情况。

    public static final String ACTION_DEVICE_PERMISSION = "com.linc.USB_PERMISSION";

    注冊广播

            mPermissionIntent = PendingIntent.getBroadcast(this,0,new Intent(ACTION_DEVICE_PERMISSION),0);
            IntentFilter permissionFilter = new IntentFilter(ACTION_DEVICE_PERMISSION);
            registerReceiver(mUsbReceiver,permissionFilter);

    接收器的代码:

     private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                tvInfo.append("BroadcastReceiver in
    ");
                if (ACTION_DEVICE_PERMISSION.equals(action)) {
                    synchronized (this) {
                        UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            if (device != null) {
                                tvInfo.append("usb EXTRA_PERMISSION_GRANTED");
                            }
                        } else {
                            tvInfo.append("usb EXTRA_PERMISSION_GRANTED null!!!");
                        }
                    }
                } 
            }
        };

    七、通信

    UsbDevice有了权限,以下就能够进行通信了。
    这里要用到:UsbInterface、UsbEndpoint(一进一出两个endpoint,双向通信)、UsbDeviceConnection。
    注意:通信的过程不能在UI线程中进行。
    得到授权后,将做一些通信前的准备工作,例如以下:

    private void initCommunication(UsbDevice device) {
            tvInfo.append("initCommunication in
    ");
            if(1234 == device.getVendorId() && 5678 == device.getProductId()) {
                tvInfo.append("initCommunication in right device
    ");
                int interfaceCount = device.getInterfaceCount();
                for (int interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) {
                    UsbInterface usbInterface = device.getInterface(interfaceIndex);
                    if ((UsbConstants.USB_CLASS_CDC_DATA != usbInterface.getInterfaceClass())
                            && (UsbConstants.USB_CLASS_COMM != usbInterface.getInterfaceClass())) {
                        continue;
                    }
    
                    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) {
                                mUsbEndpointIn = ep;
                            } else {
                                mUsbEndpointOut = ep;
                            }
                        }
                    }
    
                    if ((null == mUsbEndpointIn) || (null == mUsbEndpointOut)) {
                        tvInfo.append("endpoint is null
    ");
                        mUsbEndpointIn = null;
                        mUsbEndpointOut = null;
                        mUsbInterface = null;
                    } else {
                        tvInfo.append("
    endpoint out: " + mUsbEndpointOut + ",endpoint in: " +
                                mUsbEndpointIn.getAddress()+"
    ");
                        mUsbInterface = usbInterface;
                        mUsbDeviceConnection = mUsbManager.openDevice(device);
                        break;
                    }
                }
            }
        }

    发送数据例如以下:

    result = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, mData, (int)buffSize, 1500);//须要在还有一个线程中进行

    八、其它

    作为一个普通的开发人员,假设没有USB设备。那么调试程序是个问题。
    能够使用AdbTest程序用OTG线连接两个手机或平板试试。
    有USB设备的同事,会依据设备的通信协议规则去编码。这里面要用到byte与其它类型转换。以及十六进制的问题。


    详细问题详细分析吧。这篇文章磕磕绊绊。就先到这里了。

    參考:
    1、endpoint的介绍:http://blog.chinaunix.net/uid-25314474-id-3040231.html

  • 相关阅读:
    四级英语day9
    123
    像程序员一样思考
    Kali
    OS X
    Effective Java
    DHU ACM OJ
    Ambari
    Hadoop
    Hadoop2
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7397087.html
Copyright © 2011-2022 走看看