OTG – Android USB Hos
OTG在Android3.1及以上被支持。也就是minSdkVersion为12.
API概述
UsbManager
允许您枚举已连接的USB设备并且与其进行“交流”。
UsbDevice
代表了一个已连接的USB的设备并且包含具有该设备验证信息,接口和接入点的方法。
UsbInterface
代表了一个USB设备的一个接口,该接口定义了一系列关于设备的函数。一个设备在进行“交流”的时候可以有一个或者多个接口。
UsbEndpoint
代表一个接口的接入点,该接入点就是这个接口的通信信道。一个接口可以有一个或者多个这样的接入点,而且一般都是有输入和输出双向通信的接入点。
UsbDeviceConnection
代表该设备的一个连接,用来在接入点上传输数据。这个类允许您能用同步或者异步的方式发送和返回数据。
UsbRequest
在通过UsbDeviceConnection和设备进行“交流”的一个异步请求。
UsbConstants
关于在linux内核中linux/usb/ch9.h的相关定义的USB常量。
在大多数情况中,跟USB设备通信时,需要使用所有这些类(使用异步通信,只需要使用UsbRequest类)。使用UsbManager对象来获取期望的UsbDevice对象。有了这个UsbDevice对象时,就需要查找对应的UsbInterface对象和基于该接口通信的UsbEndpoint对象。一旦获取了正确的端点,就可以打开UsbDeviceConnect对象来跟USB设备进行通信了。
Android清单要求
在使用USB主机模式API工作之前,你需要把以下介绍的内容添加到你的应用程序清单中:
1. 因为不是所有的Android设备都保证支持USB主机模式,所以要在你的应用程序声明中包含元素,以声明你的应用程序要使用android.hardware.usb.host功能。
2. 把应用程序的最小SDK设置为API Level 12或更高的版本。在较早的API版本中不存在USB主机模式API。
3. 如果你希望你的应用程序能够获得接入USB设备时的通知,那么还要在你的主Activity中指定用android.hardware.usb.action.USB_DEVICE_ATTACHED类型的Intent来配对的和元素。元素要指向一个外部的XML资源文件,该文件声明了希望检测的设备的识别信息。
在这个XML资源文件中,要用元素来声明你想要过滤的USB设备。以下列出了元素的属性。通常,使用vendor-id和product-id来指定你所希望过滤的特定的设备,并且使用class、subclass和protocol来指定你所希望过滤的USB设备组,如大容量存储设备或数码相机。你可以不指定任何属性,或所有全部属性。不指定任何属性,就会跟所有USB设备匹配,如果应用程序需要,就可以这样做:
A. vendor-id
B. product-id
C. class
D. subclass
E. protocol(设备或接口)
在res/xml目录中保存这个资源文件。该资源文件的名称(不含.xml扩展名)必须跟元素中指定的名称相同。XML资源文件的格式请看下例。
1
|
<? xml version = "1.0" encoding = "utf-8" ?>
|
2
|
< manifest xmlns:android = "http://schemas.android.com/apk/res/android"
|
3
|
package = "com.example.testusb"
|
4
|
android:versionCode = "1"
|
5
|
android:versionName = "1.0"
|
6
|
>
|
7
|
8
|
< uses-sdk
|
9
|
android:minSdkVersion = "12"
|
10
|
android:targetSdkVersion = "17" />
|
11
|
|
12
|
< uses-feature android:name = "android.hardware.usb.host" />
|
13
|
14
|
< application
|
15
|
android:allowBackup = "true"
|
16
|
android:icon = "@drawable/ic_launcher"
|
17
|
android:label = "@string/app_name"
|
18
|
android:theme = "@style/AppTheme" >
|
19
|
< activity
|
20
|
android:name = "com.example.testusb.TestUSB"
|
21
|
android:label = "@string/app_name" >
|
22
|
< intent-filter >
|
23
|
< action android:name = "android.intent.action.MAIN" />
|
24
|
< category android:name = "android.intent.category.LAUNCHER" />
|
25
|
</ intent-filter >
|
26
|
<!-- 当你需要希望你的应用能够被连接的设备所提示,需要针对intent-filter和meta-data加上android.hardware.usb.action.USB_DEVICE_ATTACHED意图 -->
|
27
|
< intent-filter >
|
28
|
< action android:name = "android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
29
|
</ intent-filter >
|
30
|
31
|
<!-- 用于过滤具体USB设备,其中device_filter是个xml文件 -->
|
32
|
< meta-data android:name = "android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
33
|
android:resource = "@xml/device_filter" />
|
34
|
</ activity >
|
35
|
|
36
|
</ application >
|
37
|
38
|
</ manifest >
|
资源文件应该保存在res/xml/device_filter.xml
1
|
<? xml version = "1.0" encoding = "utf-8" ?>
|
2
|
< resources >
|
3
|
<!-- 如果你不确定你需要检测的设备vendor-id和product-id,可以所有的参数都为空,将获得所有已连接的USB设备。
|
4
|
否则请对应上相应参数。 -->
|
5
|
< usb-device vendor-id = "65535" product-id = "65535" class = "255" subclass = "66" protocol = "1" />
|
6
|
</ resources >
|
可以在Windows上查看USB设备的VID和PID,需要注意的是,在Windows上VID和PID都是十六进制数,需要转换为10进制。
声明: 本文由( 上善若水 )原创编译,转载请保留链接: OTG – Android USB Host(一)
发现设备
可以使用两种方法来发现设备:
1.使用Intent过滤器,过滤用户接入USB设备时所发出的通知;
2.列举已经接入的USB设备。
如果你希望你的程序能够自动的检测你所期望的USB设备,需要使用Intent过滤器,如我们刚才在AndroidManifest.xml中添加的过滤器。
在Activity中,可以从这样的意图中获取UsbDevice:
1
|
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
如果你你希望过滤所有的USB设备,或者应用程序没有过滤对应的Intent对象,那么可以使用列举:
1
|
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
2
|
HashMap<String, UsbDevice> map = usbManager.getDeviceList();
|
3
|
for (UsbDevice device : map.values()){
|
4
|
Log.i(TAG, "dName: " + device.getDeviceName());
|
5
|
Log.i(TAG, "vid: " + device.getVendorId() + "\t pid: " + device.getProductId());
|
6
|
usbDevice = device;
|
7
|
//Other code
|
8
|
}
|
或者使用迭代,获取每一个设备:
1
|
HashMap<String, UsbDevice> deviceList = usbManager .getDeviceList();
|
2
|
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
|
3
|
while (deviceIterator.hasNext()){
|
4
|
UsbDevice device = deviceIterator.next();
|
5
|
//Other code
|
6
|
}
|
获取跟设备通信的权限
在跟USB设备进行通信之前,你的应用程序必须要获取用户的许可。
注意:如果你的应用程序使用Intent过滤器来发现接入的USB设备,而且用户允许你的应用程序处理该Intent,那么它会自动的接收权限,否则,在你的应用程序接入该设备之前,必须明确的申请权限。
明确的申请权限在某些情况下是必须的,如你的应用程序列举已经接入的USB设备并想要跟其中的一个设备通信的时候。在试图跟一个设备通信之前,你必须要检查是否有访问设备的权限。否则,如果用户拒绝了你访问该设备的请求,你会收到一个运行时错误。
要明确的获取这个权限,首先要创建一个广播接收器。这个接收器用于监听你调用requestPermission()方法时,系统所发出的Intent对象。调用requestPermission()方法时,系统会显示一个对话框,询问用户是否允许跟该USB设备进行连接。下列代码演示如何创建这个广播接收器:
1
|
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" ;
|
2
|
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
|
3
|
4
|
public void onReceive(Context context, Intent intent) {
|
5
|
String action = intent.getAction();
|
6
|
Log.e(TAG, action);
|
7
|
|
8
|
if (ACTION_USB_PERMISSION.equals(action)) {
|
9
|
synchronized ( this ) {
|
10
|
usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
11
|
//允许权限申请
|
12
|
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false )) {
|
13
|
if (usbDevice != null ){
|
14
|
//call method to set up device communication
|
15
|
}
|
16
|
} else {
|
17
|
Log.d(TAG, "permission denied for device " + usbDevice);
|
18
|
}
|
19
|
}
|
20
|
}
|
21
|
};
|
注册接收的广播,并放在onCreate中:
1
|
//注册广播
|
2
|
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
|
3
|
registerReceiver(mUsbReceiver, filter);
|
申请权限:
1
|
PendingIntent pi = PendingIntent.getBroadcast( this , 0 , new Intent(ACTION_USB_PERMISSION), 0 );
|
2
|
if (usbManager.hasPermission(usbDevice)){
|
3
|
//Other code
|
4
|
} else {
|
5
|
//没有权限询问用户是否授予权限
|
6
|
usbManager.requestPermission(usbDevice, pendingIntent); //该代码执行后,系统弹出一个对话框,
|
7
|
//询问用户是否授予程序操作USB设备的权限
|
8
|
}
|
当用户回应这个对话框时,你的广播接收器就会收到一个包含用一个boolean值来表示结果的EXTRA_PERMISSION_GRANTED字段的意图。在您连接设备之前检查这个字段的值是否为true。
跟设备进行通信:
我们可以同步或者异步的和USB设备进行“交流”。在任意一种情况之下,您都应该创建一个新的线程来进行数据传输,这样就不会阻塞您的主线程了。要想正确的设置好和一个设备之间的连接,您需要获得该设备正确的UsbInterface和UsbEndpoint来和您进行“交流”以及通过UsbDeviceConnection在这个接入点上发送请求。一般来说,您的代码应该这样:
1.检查一个UsbDevice对象的属性,例如产品ID,供应商ID,或者是关于设备的类,以此来确认您是否希望和该设备进行“交流”。
2.当您确信您希望和该设备进行“交流”时,找到关于该设备正确的UsbInterface以及和该接口所对应的UsbEndpoint。接口可以有一个或者多个接入点,而且一般都会有一个双向通信的输入和输出接入点。
3.当您找到正确的接入点时,在该接入点时打开一个UsbDeviceConnection。
4.您可以通过bulkTransfer()和controlTransfer()这两个方法在接入点上传输您所需要传递的数据。您最好在另起一个新的线程来进行这个步骤以避免阻塞主线程。想要详细地了解关于Android中使用线程的信息,详见线程和进程。
1
|
private Byte[] bytes;
|
2
|
private static int TIMEOUT = 3000 ;
|
3
|
private boolean forceClaim = true ;
|
4
|
5
|
UsbInterface usbInterface = usbDevice.getInterface( 0 );
|
6
|
//USBEndpoint为读写数据所需的节点
|
7
|
UsbEndpoint inEndpoint = usbInterface.getEndpoint( 0 ); //读数据节点
|
8
|
UsbEndpoint outEndpoint = usbInterface.getEndpoint( 1 ); //写数据节点
|
9
|
UsbDeviceConnection connection = usbManager.openDevice(usbDevice);
|
10
|
connection.claimInterface(usbInterface, true );
|
11
|
|
12
|
//发送数据
|
13
|
byte [] byte2 = new byte [ 64 ]; //发送与接收字节数与设备outputreport有关
|
14
|
int out = connection.bulkTransfer(outEndpoint, bytes, bytes.length, TIMEOUT);
|
15
|
Log.e(TAG, "out:" + out);
|
16
|
|
17
|
//读取数据1 两种方法读取数据
|
18
|
int ret = connection.bulkTransfer(inEndpoint, byte2, byte2.length, TIMEOUT);
|
19
|
Log.e(TAG, "ret:" +ret);
|
20
|
21
|
//还有第二种读取方式,未验证。
|
22
|
int outMax = outEndpoint.getMaxPacketSize();
|
23
|
int inMax = inEndpoint.getMaxPacketSize();
|
24
|
ByteBuffer byteBuffer = ByteBuffer.allocate(inMax);
|
25
|
UsbRequest usbRequest = new UsbRequest();
|
26
|
usbRequest.initialize(connection, inEndpoint);
|
27
|
usbRequest.queue(byteBuffer, inMax);
|
28
|
if (connection.requestWait() == usbRequest){
|
29
|
byte [] retData = byteBuffer.array();
|
30
|
}
|
终止通信:
当您在完成和设备的“交流”之后,又或者该设备被移除了,通过调用releaseInterface()和close()的方法来关闭UseInterface和UsbDeviceConnection。为了监听分离这样的事件,您需要创建一个如下的广播接收器:
1
|
BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
|
2
|
public void onReceive(Context context, Intent intent) {
|
3
|
String action = intent.getAction();
|
4
|
|
5
|
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
|
6
|
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
7
|
if (device != null ) {
|
8
|
// call your method that cleans up and closes communication with the device
|
9
|
}
|
10
|
}
|
11
|
}
|
12
|
};
|
在您的应用中创建这个广播接收器,不是在manifest文件中,允许您的应用只能在它运行的时候处理这样的设备分离事件。这样的话,设备分离这个事件就只向正在运行的应用广播,而不是向所有的应用进行广播。
总结:
我在发送数据的时候,返回的是2,接收返回-1,一直不清楚需要发送的数据是什么格式需要哪些命令,在网上查找了很久也没有找到。
也就只能做到设备接通,但是通信不算成功。
暂时没有时间深入研究了,有兴趣的同学可以查看一下Android的示例代码:Adb test sample,显示了怎样进行异步块数据数据传输,MissleLauncher sample显示了如何监听异步的中断端点。
声明: 本文由( 上善若水 )原创编译,转载请保留链接: OTG – Android USB Host(三)
OTG – Android USB Hos相关推荐
- Android OTG (USB Hos) 编程
前言:最近在做一个汽车发动机故障检测的项目,负责APP开发.汽车发动机将各种数据通过OTG传输到Android手机,APP可以实时显示数据. 一.权限 1. 声明支持USB Hos模式 在Androi ...
- android usb otg,android usb otg需要什么权限
USB OTG功能如何打开及实现 USB OTG U盘 Keyboard Mouse 1.检查HW原理图,确认是否支持OTG功能(vbus是否供上电,IDDIG pin连接是否正确) 若HW确认支持O ...
- Android USB OTG U盘读写相关使用最全总结
Android USB OTG U盘读写相关使用最全总结 https://blog.csdn.net/qq_29924041/article/details/80141514 androidOTG ( ...
- Android usb otg通讯总结 HiD通讯直接来取吧
最近在搞一个Android的通过otg与设备进行usb通讯的功能HID. 过程中遇到了一个大坑,就是usb发数据的时候,第一次显示发送成功(返回值大于1),但是设备并没有收到实际的数据,把usb重新拔 ...
- 基于AOA协议的android USB通信
摘 要:AOA协议是Google公司推出的用于实现Android设备与外围设备之间USB通信的协议.该协议拓展了Android设备USB接口的功能,为基于Android系统的智能设备应用于数据采集和设 ...
- Android USB转串口编程
安卓手机的对外通信接口就只有USB跟音频口,我们可采用其进行与外设进行通信.今天,我们来讲讲安卓手机利用USB接口与外设进行通信.此时,有两种情况. 第一:USB(手机)<--->USB( ...
- Android+usb+spi,Android设备如何使用USB的硬件接口
你知道Android设备如何使用USB的硬件接口吗?下面将由学习啦小编带大家来解答这个疑问吧,希望对大家有所收获! 如何处理硬件接口问题 最近业界的发展显示,智能手机/便携系统与自动化系统或机械系统之 ...
- android usb 手柄吃鸡,游戏手柄怎么用,吃鸡游戏手柄怎么用
如何使用游戏手柄 游戏中还有设置选项,通常需要将"键盘"更改为"手柄". 我买了游戏手柄,如何使用? _ 分析如下:1.看一下控制面板,控制面板上的硬件和声音设 ...
- android usb gadget分析
Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...
最新文章
- ucontext实现的用户级多线程框架3(实现echo服务器)
- GO语言有哪些优势?怎样入门?
- 数学问题当中的一些基本计数问题
- win10子系统linux编译ffmpeg
- 美国新WiFi技术功耗低于蓝牙LE和Zigbee
- 微信web-view 开发_在不到7个月的时间里我如何成为一名Web开发人员-以及如何
- 计算机视觉论文-2021-07-06
- Fiddler之文件代理
- redhat solutions
- burpsuite的基本操作_burpsuite安装与基本使用
- GPS NMEA码详解
- java --运用hhs 框架,tomcat 访问mysql 数据库 连接 失败后,自动 重新连接怎么做?
- 分享一下前几个月我做的超炫的登录页面
- Live2D_2.X基本功能
- python实现生日悖论分析
- 运行项目报错 proxy error: could not proxy request...
- PHP Fatal error: Uncaught Error: Class ‘\Elasticsearch\Serializers\SmartSerializer‘ not found in /h
- 解读IPD流程体系的“三驾马车”
- 七:Grafana-Sierra Plot用法
- 海外服务器CDN加速与双线服务器有什么不同?