参考资料
起源
- 啊,这个没得办法,工作需求,得看。头大哈。
Androud USB口通信基础知识了解
- 想要做到相机相片拉取得相关功能那么得先了解USB整个得工作流程和方式
USB连接模式
-
主机模式: 主机模式下,Android 设备充当主机。设备示例包括数码相机、键盘、鼠标和游戏控制器。针对各类应用和环境设计的 USB 设备仍可与能够与设备正常通信的 Android 应用互动。
-
配件模式:配件模式下,外部 USB 硬件充当 USB 主机。配件示例可能包括机器人控制器、扩展坞、诊断和音乐设备、自助服务终端、读卡器等等。这样,不具备主机功能的 Android 设备就能够与 USB 硬件互动。Android USB 配件必须设计为与 Android 设备兼容,并且必须遵守 Android 配件通信协议。
调试注意事项 -
调试使用 USB 配件或主机功能的应用时,您很可能需要将 USB 硬件连接到 Android 设备。这样,您将无法通过 USB 将 adb 连接到 Android 设备。您仍可通过网络连接访问 adb。要通过网络连接启用 adb,请执行以下操作:
- 通过 USB 将 Android 设备连接到计算机。
- 在 SDK platform-tools/ 目录中,在命令提示符下输入 adb tcpip 5555。
- 输入 adb connect <device-ip-address>:5555。您现在应该已连接到 Android 设备,并且可以发出常规的 adb 命令(如 adb logcat)。
- 要设置设备来监听 USB,请输入 adb usb。
-
Android 3.1(API 级别 12)或更高版本的平台直接支持 USB 配件和主机模式。USB 配件模式还作为插件库向后移植到 Android 2.3.4(API 级别 10)中,以支持更广泛的设备。设备制造商可以选择是否在设备的系统映像中添加该插件库。
-
这里只需要Android的主机模式。
USB传输模式
- 控制传输模式:控制传输用于在外设初次连接时对器件进行配置;对外设的状态进行实时检测;对控制命令的传送等;也可以在器件配置完成后被客户软件用于其它目的。Endpoint 0信道只可以采用控制传送的方式。 银行交互设备,密码键盘
- 块传送模式:块传送用于进行批量的、非实时的数据传输。如一台 USB 扫描仪即可采用块传送的模式,以保证资料连续地、在硬件层次上的实时纠错地传送。采用块传送方式的信道所占用的 USB 带宽,在实时带宽分配中具有最高的优先级
- 同步传输模式:同步传输适用于那些要求资料连续地、实时地、以固定的数据传输率产生、传送并消耗的场合,如数字录像机等。为保证数据传输的实时性,同步传输不进行资料错误的重试,也不在硬件层次上响应一个握手资料包,这样有可能使数据流中存在资料错误的隐患。为保证在同步传输数据流中致命错误的几率小到可以容忍的程度,而数据传输的延迟又不会对外设的性能造成太大的影响,厂商必须为使用同步传输的信道选择一个合适的带宽(即必须在速度和品质之间做出权衡)。
- 中断传输模式:对于那些小批量的、点式、非连续的数据传输应用的场合,如用于人机交互的鼠标、键盘、游戏杆等,中断传输的方式是最适合的
- 上述得四种就是基本得传输模式了,其中块传输模式和同步传输模式是需要好好看得,因为相机拉取相片得情况分为两种
- 相机空闲,拉取已经拍摄好得图片。
- 相机工作,实时同步拉取每次拍摄得图片。
- 所以真个设计需要两个不同的服务,一个拉取旧照片,一个实时传输新照片,而且展示得时候新照片需要有一定有优先,或者干脆分为不同得布局展示。大概吧。
API概览
| 类 | 说明 |
|---|---|
| UsbManager | 您可以枚举连接的 USB 设备并与之通信。 |
| UsbDevice | 表示连接的 USB 设备,并包含用于访问其标识信息、接口和端点的方法。 |
| UsbInterface | 表示 USB 设备的接口,它定义设备的一组功能。设备可以具有一个或多个用于通信的接口。 |
| UsbEndpoint | 表示接口端点,是此接口的通信通道。一个接口可以具有一个或多个端点,并且通常具有用于与设备进行双向通信的输入和输出端点。 |
| UsbDeviceConnection | 表示与设备的连接,可在端点上传输数据。借助此类,您能够以同步或异步方式反复发送数据。 |
| UsbRequest | 表示通过其与设备通信的异步请求。 |
| UsbConstants | 定义与 Linux 内核的 linux/usb/ch9.h 中的定义相对应的 USB 常量。 |
- 在大多数情况下,您需要在与 USB 设备通信时使用所有这些类(只有在进行异步通信时才需要 UsbRequest)。一般来说,您需要获取 UsbManager 才能检索所需的 UsbDevice。当您有了设备后,需要找到相应的 UsbInterface 和该接口的 UsbEndpoint 以进行通信。获得正确的端点后,打开 UsbDeviceConnection 以与 USB 设备通信。
Android manifest设置
- 由于并非所有 Android 设备都保证支持 USB 主机 API,因此请添加 <uses-feature> 元素来声明您的应用使用 android.hardware.usb.host 功能。
- 将应用的最低 SDK 设置为 API 级别 12 或更高级别。USB 主机 API 在更早的 API 级别中不存在。
- 如果您希望应用接收有关连接的 USB 设备的通知,请为主 Activity 中的 android.hardware.usb.action.USB_DEVICE_ATTACHED Intent 指定 <intent-filter> 和 <meta-data> 元素对。<meta-data> 元素指向外部 XML 资源文件,用于声明有关要检测的设备的标识信息。
在 XML 资源文件中,为要过滤的 USB 设备声明 <usb-device> 元素。下表介绍了 <usb-device> 的属性。一般来说,如果您想过滤某个特定设备,请使用供应商 ID 和产品 ID;如果您想过滤一组 USB 设备(例如大容量存储设备或数码相机),请使用类、子类和协议。您可以指定所有这些属性,也可以不指定任何属性。如果不指定任何属性,则会与每个 USB 设备进行匹配,因此只在应用需要时才这样做:
usb_device.xml
<resources>
<usb-device
vendor-id = ""
product-id = ""
class = ""
subclass = ""
protocol = ""
/>
</resources>
将资源文件保存在 res/xml/ 目录中。资源文件名称(不含 .xml 扩展名)必须与您在 <meta-data> 元素中指定的名称相同。
<activity
android:exported="false"
android:name=".usb.UsbActivity">
<intent-filter>
<action android:name="android.hadware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device"/>
</activity>
使用
- 当用户将 USB 设备连接到 Android 设备时,Android 系统可以确定您的应用是否对连接的设备感兴趣。如果是,您可以根据需要设置与该设备的通信。为此,您的应用必须执行以下操作:
- 发现连接的 USB 设备,具体方法是使用 Intent 过滤器在用户连接 USB 设备时接收通知,或者枚举已连接的 USB 设备。
- 请求用户授予连接到 USB 设备的权限(如果尚未获得权限)。
- 通过在适当的接口端点读取和写入数据来与 USB 设备通信。
- 使用流程大概为以下几步:
- 找到特定设备UsbDevice(需要根据具体的vendorId和productId)
- 检测USB权限
- 找接口对象UsbInterface
- 找usb通信通道
- 打开USB设备
- usb建立连接
- USB数据传输
- USB通讯结束后关闭usb
发现设备
- 您的应用可以通过使用 Intent 过滤器在用户连接 USB 设备时接收通知,或者枚举已连接的 USB 设备来发现设备。如果您希望应用自动检测所需的设备,那么使用 Intent 过滤器就非常有用。如果您想获取所有连接的设备的列表,或者您的应用没有 Intent 过滤器,那么枚举连接的 USB 设备就非常有用。
Intent 过滤器
- 要让您的应用发现特定的 USB 设备,您可以指定一个 Intent 过滤器,用于过滤 android.hardware.usb.action.USB_DEVICE_ATTACHED Intent。除了此 Intent 过滤器外,您还需要指定一个资源文件来指定 USB 设备的属性,例如产品 ID 和供应商 ID。当用户连接与您的设备过滤器匹配的设备时,系统会向其显示一个对话框,询问他们是否要启动您的应用。如果用户接受,您的应用会自动获得访问设备的权限,直到设备断开连接
- intent过滤器就是上面给出的manifest相关设置。
- 然后在连接外界设备的时候,如果是你intnet过滤器中指定的设备,那么就会弹出询问框,然后打开你设置意图的相关Activity。
- 在Activity中,可以从itent中获取所连接的设备UsbDevice;
/**
* 通过intent过滤器 打开的界面intent中会包含设备相关信息
*/
private void initDevice() {
UsbDevice device = getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
}
- 同一个usb接口热插拔一次,DeviceID是会变化的,标记一个USB接口的唯一性,我们通常用vendor-id和product-id。
枚举设备
- 如果应用有兴趣在运行时检查当前连接的所有 USB 设备,则可以枚举总线上的设备。使用 getDeviceList方法获取连接的所有 USB 设备的哈希映射。如果要通过映射获取设备,哈希映射会由 USB 设备的名称进行键控。
/**
* 枚举所有的设备
*/
private void enumDevices() {
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
//获取所有设备的信息,然后通过设备名称获取设备
HashMap<String,UsbDevice> deviceHashMap = manager.getDeviceList();
UsbDevice device = deviceHashMap.get("deviceName");
//也可以获取迭代器 获取每个设备
Iterator<UsbDevice> deviceIterator = deviceHashMap.values().iterator();
while (deviceIterator.hasNext()){
UsbDevice dev = deviceIterator.next();
}
}
- 其实有个疑问,android机器同时不是只能连接一台外界设备么?
获取与设备通信的权限
- 您的应用必须获得用户的许可,才能与 USB 设备通信。
- 如果您的应用使用 Intent 过滤器来发现已连接的 USB 设备,则它会在用户允许应用处理 Intent 时自动获得权限。否则,您必须在应用中明确请求权限,然后才能连接到设备。
- 某些情况下可能需要明确请求权限,例如应用枚举已连接的 USB 设备,然后要与其中一个设备通信时。在尝试与设备通信之前,您必须先检查是否具有访问设备的权限。否则,如果用户拒绝授予访问设备的权限,您会收到运行时错误消息。
- 新建广播接收器,因为基本usb的插拔和权限获取都是通过广播返送
private class PhotoPermissionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(ACTION_USB_PERMISSION, action)) {
synchronized (this) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
} else {
Log.d("PhotoPermissionReceiver", "permission denied for device [" + device + "]");
}
}
}
}
}
- 初始化获取权限需要的对象
public void onCreate() {
super.onCreate();
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
permissionIntent = PendingIntent.getBroadcast(contextWeakReference.get(),REQUEST_CODE
,new Intent(ACTION_USB_PERMISSION),PendingIntent.FLAG_MUTABLE);
IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
PhotoPermissionReceiver receiver = new PhotoPermissionReceiver();
registerReceiver(receiver,intentFilter);
enumDevices();
}
- 枚举所有设备,针对你需要操作的设备去获取权限
/**
* 枚举所有的设备
*/
private void enumDevices() {
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
//获取所有设备的信息,然后通过设备名称获取设备
HashMap<String, UsbDevice> deviceHashMap = manager.getDeviceList();
UsbDevice device = deviceHashMap.get("deviceName");
//也可以获取迭代器 获取每个设备
Iterator<UsbDevice> deviceIterator = deviceHashMap.values().iterator();
while (deviceIterator.hasNext()) {
UsbDevice dev = deviceIterator.next();
//获取权限
usbManager.requestPermission(dev,permissionIntent);
}
}
- 其实开发中,itent过滤和枚举设备的方式都需要添加。因为你不确定外界设备何时连接,可能你枚举设备的时候还没有连接,你不能要求用户的操作顺序是吧,也不大可能写一个无限循环的东西去枚举设备,或者说连接完了你给个按钮让用户点击后去枚举设备,那样有点傻啊。
与设备通信
- 与 USB 设备的通信可以是同步的,也可以是异步的。在这两种情况下,您都应该创建一个新线程来执行所有数据传输,这样就不会锁定界面线程。要正确设置与设备的通信,您需要获取要与之通信的设备的相应 UsbInterface 和 UsbEndpoint,并使用 UsbDeviceConnection 在此端点发送请求
找到接口对象UsbInterface
获取endpoint
简历连接
- 上面三个步骤是一气呵成的
UsbInterface usbInterface = device.getInterface(0);
UsbEndpoint endpoint = usbInterface.getEndpoint(0);
UsbDeviceConnection connection = usbManager.openDevice(device);
while (true){
connection.claimInterface(usbInterface,true);
connection.bulkTransfer(endpoint,bytes,bytes.length,timeout);
}











网友评论