Android设备与USB设备的连接通讯

来源:互联网 发布:崇祯为什么不南迁知乎 编辑:程序博客网 时间:2024/04/27 15:58

        关于Android与USB设备的连接,所能搜索到的资料特别的少,但恰恰接到了一个这样的需求,使用android平板通过USB与一个外接设备进行通讯,这个设备是一个压力感应器,在压力发生变化时可以测到相应的压力值,Android设备通过USB对设备进行供电并与该设备进行通讯,将测量到的数据读取下来并进行保存分析。这是一个典型的Android设备作为USBHost、外接设备作为USBDevice的Host Mode。关于Android所提供的USB连接模式,可以参考:http://developer.android.com/guide/topics/connectivity/usb/index.html,这里对两种连接模式都做了比较详细的介绍,不再赘述。下面主要针对我所遇到的问题做一些分析。

首先看Host mode所需要用的的类:

UsbManager:Allows you to enumerate and communicate with connected USB devices.字面含义就是允许你列举并与已连接的USB设备进行交互,其实就是一个USB管理器,可以通过它来获取已连接的USB Device列表。使用上很简单:UsbManager manager = (UsbManager) getSystemService(USB_SERVICE);就可以获取到一个实例。

USBDevice:Represents a connected USB device and contains methods to access its identifying information, interfaces, and endpoints.表示一个已连接的USB设备,包含获取它的识别信息、接口和端点的方法。获取一个USBDevice列表的方法:HashMap<String, UsbDevice> devices = um.getDeviceList();。

UsbInterface:Represents an interface of a USB device, which defines a set of functionality for the device. A device can have one or more interfaces on which to communicate on.表示一个为该设备定义了一个函数集的USB设备接口。一个设备可以拥有一个或多个用来交互的接口。获取一个设备的接口数量:int interfaceCount = device.getInterfaceCount();,如果使用index为0的interface则可以:UsbInterface ui = device.getInterface(0); 。

UsbEndpoint:Represents an interface endpoint, which is a communication channel for this interface. An interface can have one or more endpoints, and usually has input and output endpoints for two-way communication with the device. 表示一个接口端点,该端点作为这个接口的一个交互channel,一个接口可以拥有一个或多个端点,通常有输入和输出端点为一个设备提供两种交互方式。

UsbDeviceConnection:Represents a connection to the device, which transfers data on endpoints. This class allows you to send data back and forth sychronously or asynchronously.表示在通过端点与设备传输数据的一个连接,该类允许你同步或异步的发送信息出去或者回来。

在获取一个UsbEndpoint时,务必要执行conn.claimInterface(UsbInterface intf, boolean force)方法。在使用中

if(!um.hasPermission(device)){//判断是否拥有该设备的连接权限,如果没有则请求权限
    um.requestPermission(device, this.createPendingResult(0, null, 0));
}

if(manager.hasPermission(device)){//如果已经拥有该设备的连接权限
    conn = manager.openDevice(device);//打开一个UsbDeviceConnection
}

if(conn==null){
      Toast.makeText(this, "USB设备连接不可用!", Toast.LENGTH_SHORT).show();
      return false;
}
if(conn.claimInterface(ui, true)){//This must be done before sending or receiving data on any UsbEndpoints belonging to the interface.
      point = ui.getEndpoint(1);
      dataPoint = ui.getEndpoint(0);
      return true;
 }

如果配置正确的话,通过上面的几个类,应该可以成功的获得了一个可用的UsbEndpoint。

但需要注意的是,这时需要声明USB设备的信息,

<?xml version="1.0" encoding="utf-8"?>

<resources>

     <usb-devicevendor-id="1234"product-id="5678"class="255"subclass="66"protocol="1"/>

</resources>

具体的这些id需要根据所连接的设备而有所不同,这个资源文件必须声明在res/xml/device_filter.xml中

完成这个声明以后,一般的,在USB设备接入时,系统如果检测到该设备,如果此时需要提示则应该

<manifest ...>

     <uses-featureandroid:name="android.hardware.usb.host"/>

     <uses-sdkandroid:minSdkVersion="12"/>

    ... <application>

        <activity ...> ...

            <intent-filter>

                <actionandroid:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>

            </intent-filter>

            <meta-dataandroid:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"android:resource="@xml/device_filter"/>

        </activity>

    </application>

</manifest>

表示,在device_filter文件中的声明的设备连接到Android设备时,会触发连接的提示。

如果上面的连接正常,那么就可以与设备进行数据的传输了。

一般地,都会启动一个线程来完成这项工作。

request.initialize(conn, dataPoint);//初始化请求
ByteBuffer bb =ByteBuffer.allocate(2);//数据接收的ByteBuffer,具体大小要根据不同的设备而有所不同
while(canStop){
    request.queue(bb, 2);
    byte[] dst = new byte[2];
    int accessRes = conn.bulkTransfer(point, access, 2, 1000);//发送USB外设所能执行的命令
    if(accessRes<0){
        return;
    }
    if(request == conn.requestWait()){//请求完成,如果发生错误则方法返回null
        dst = bb.array();//返回的数据

    }

}

UsbRequest:Represents an asynchronous request to communicate with a device through aUsbDeviceConnection.表示通过一个UsbDeviceConnection实例与设备进行交互的一个异步请求。

在这个数据传输的过程中,需要发送命令和接收数据,发送命令的方法有两个:

controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)

Performs a control transaction on endpoint zero for this device.
参数requestType,该事务的请求类型,参数request,该事务的请求ID,参数value,该事务的值,参数index,该事务的索引,参数buffer,该事务的数据buffer,如果没有数据需要被发送或接收,可以为null,参数length,发送或接收数据的长度,参数timeout,超时时间,单位毫秒
另外一个是,
bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout)
Performs a bulk transaction on the given endpoint.
参数endpoint,需要通过哪个端点来发送数据,参数buffer,要发送或接收的数据buffer,参数length,要发送或接收的数据长度,参数timeout,超时时间,单位毫秒
如果返回值为负值,则说明失败,否则返回发送成功数据的长度。
在发送完毕后,应当使用UsbDeviceConnection的requestWait()方法来等待响应获取返回的数据。
        至此,整个连接设备与数据交互的过程就可以算完成了,具体到发送什么样的命令,根据所连接设备的不同自然也是不同的,整个流程大致就如上面所说。Google也提供了一个Demo,如果没有下载的话可以在这里下载
原创粉丝点击