- 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。一、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的插入和拔出是以系统广播的形式发送的,只要我们注册这个广播即可。
123456789101112131415161718192021222324252627<codeclass="hljs java">@OverrideprotectedvoidonResume() {super.onResume();IntentFilter usbFilter =newIntentFilter();usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);registerReceiver(mUsbReceiver, usbFilter);}@OverrideprotectedvoidonPause() {super.onPause();unregisterReceiver(mUsbReceiver);}privatefinalBroadcastReceiver mUsbReceiver =newBroadcastReceiver() {publicvoidonReceive(Context context, Intent intent) {String action = intent.getAction();tvInfo.append("BroadcastReceiver inn");if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {tvInfo.append("ACTION_USB_DEVICE_ATTACHEDn");}elseif(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {tvInfo.append("ACTION_USB_DEVICE_DETACHEDn");}}};</code>三、Usb插入时启动程序
有些应用场景是,Usb插入后启动特定程序处理特定问题。
我们的做法就是在Manifest中某个Activity加入Usb插入的action。1234<codeclass=" hljs xml"> <intent-filter><action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"></action></intent-filter><meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"android:resource="@xml/usbfilter"></meta-data></code>在usbfilter中加入厂商id和产品id的过滤,如下:
1234<codeclass=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--><resources><usb-device vendor-id="1234"product-id="5678"></usb-device></resources></code>结果就是,当此型号设备通过Usb连接到系统时,对应的Activity就会启动。
四、UsbManager的初始化
1<codeclass="hljs fix">mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);</code>五、列出Usb设备
12345678<codeclass="hljs avrasm"> HashMap<string,usbdevice> deviceHashMap = mUsbManager.getDeviceList();Iterator<usbdevice> iterator = deviceHashMap.values().iterator();while(iterator.hasNext()) {UsbDevice device = iterator.next();tvInfo.append("ndevice name: "+device.getDeviceName()+"ndevice product name:"+device.getProductName()+"nvendor id:"+device.getVendorId()+"ndevice serial: "+device.getSerialNumber());}</usbdevice></string,usbdevice></code>六、USB使用权限
安卓系统对USB口的使用需要得到相应的权限,而这个权限要用户亲自给才行。
首先我们会确认一下上一节中的device是否已经获得权限,如果没有就要主动申请权限:1234567891011<codeclass="hljs scss">//先判断是否为自己的设备//注意:支持十进制和十六进制//比如:device.getProductId() == 0x04D2if(device.getProductId() ==1234&& device.getVendorId() ==5678) {if(mUsbManager.hasPermission(device)) {//do your work}else{mUsbManager.requestPermission(device,mPermissionIntent);}}</code>我们仍然使用广播来获得权限赋予情况。
1<codeclass="hljs java">publicstaticfinalString ACTION_DEVICE_PERMISSION ="com.linc.USB_PERMISSION";</code>注册广播
123<codeclass="hljs cs"> mPermissionIntent = PendingIntent.getBroadcast(this,0,newIntent(ACTION_DEVICE_PERMISSION),0);IntentFilter permissionFilter =newIntentFilter(ACTION_DEVICE_PERMISSION);registerReceiver(mUsbReceiver,permissionFilter);</code>接收器的代码:
123456789101112131415161718<codeclass="hljs java">privatefinalBroadcastReceiver mUsbReceiver =newBroadcastReceiver() {publicvoidonReceive(Context context, Intent intent) {String action = intent.getAction();tvInfo.append("BroadcastReceiver inn");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!!!");}}}}};</code>七、通信
UsbDevice有了权限,下面就可以进行通信了。
这里要用到:UsbInterface、UsbEndpoint(一进一出两个endpoint,双向通信)、UsbDeviceConnection。
注意:通信的过程不能在UI线程中进行。
得到授权后,将做一些通信前的准备工作,如下:1234567891011121314151617181920212223242526272829303132333435363738<codeclass="hljs cs">privatevoidinitCommunication(UsbDevice device) {tvInfo.append("initCommunication inn");if(1234== device.getVendorId() &&5678== device.getProductId()) {tvInfo.append("initCommunication in right devicen");intinterfaceCount = device.getInterfaceCount();for(intinterfaceIndex =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(inti =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 nulln");mUsbEndpointIn =null;mUsbEndpointOut =null;mUsbInterface =null;}else{tvInfo.append("nendpoint out: "+ mUsbEndpointOut +",endpoint in: "+mUsbEndpointIn.getAddress()+"n");mUsbInterface = usbInterface;mUsbDeviceConnection = mUsbManager.openDevice(device);break;}}}}</code>发送数据如下:
1<codeclass="hljs cs">result = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, mData, (int)buffSize,1500);//需要在另一个线程中进行</code>八、其他
作为一个普通的开发者,如果没有USB设备,那么调试程序是个问题。
可以使用AdbTest程序用OTG线连接两个手机或平板试试。
有USB设备的同事,会根据设备的通信协议规则去编码。这里面要用到byte与其他类型转换,以及十六进制的问题。
具体问题具体分析吧。这篇文章磕磕绊绊,就先到这里了
。
最后
以上就是朴实爆米花最近收集整理的关于Android实战技巧之四十九:Usb通信之USB Host 零 USB背景知识一、Android中的USB二、USB插入事件三、Usb插入时启动程序四、UsbManager的初始化五、列出Usb设备六、USB使用权限七、通信八、其他的全部内容,更多相关Android实战技巧之四十九:Usb通信之USB内容请搜索靠谱客的其他文章。
发表评论 取消回复