Android-USB通信

Android-USB通信

本文记录下,Android平台上如何与USB设备进行通信。我这里使用的USB设备是一个USB加密设备(简称Ukey),通过与Ukey通信,对数据进行加密,提供一些加密算法。

USB API介绍

  • UsbManager:获得USB的状态,与连接的USB设备通信。
  • UsbDevice:USB设备的抽象,它包含了一个或多个的UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(UsbEndpoint)发送和接受数据。
  • UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
  • UsbEndpoint:endpoint是interface的通信信道。
  • UsbInterface : 定理设备的功能集,一个UsbDevice包含多个UsbInterface,每个UsbInterface都是独立的。
  • UsbRequest:usb请求包。可以在UsbDeviceConnection上异步传输数据。注意是只在异步通信时才会使用到它。
UsbManager常用方法说明
getDeviceList()获得设备列表,返回的是一个HashMap
hasPermission(UsbDevice device)判断你的应用程序是否有接入此USB设备的权限,如果有则返回真,否则返回false
openDevice(UsbDevice device)打开USB设备,以便向此USB设备发送和接受数据,返回一个关于此USB设备的连接
requestPermission(UsbDevice device, PendingIntent pi)向USB设备请求临时的接入权限
UsbDevice常用方法说明
getDeviceClass()返回此USB设备的类别,用一个整型来表示
getDeviceId()返回唯一标识此设备的ID号,也用一个整型来表示
getDeviceName()返回此设备的名称,用一个字符串来表示
getDeviceProtocol()返回此设备的协议类别,用一个整型来表示
getDeviceSubclass()返回此设备的子类别,用一个整型来表示
getVendorId()返回生产商ID
getProductId()返回产品ID
getInterfaceCount()返回此设备的接口数量
getInterface(int index)得到此设备的一个接口,返回一个UsbInterface
UsbDeviceConnection常用方法说明
bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout)通过给定的endpoint来进行大量的数据传输,传输的方向取决于该节点的方向,buffer是要发送或接收的字节数组,length是该字节数组的长度。传输成功则返回所传输的字节数组的长度,失败则返回负数
controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout该方法通过0节点向此设备传输数据,传输的方向取决于请求的类别,如果requestType为USB_DIR_OUT则为写数据,USB_DIR_IN, 则为读数据
UsbEndpoint常用方法说明
getAddress()获得此节点的地址
getAttributes()获得此节点的属性
getDirection()获得此节点的数据传输方向
UsbInterface常用方法说明
getId()得到给接口的id号。
getInterfaceClass()得到该接口的类别
getInterfaceSubclass()得到该接口的子类
getInterfaceProtocol()得到该接口的协议类别。
getEndpointCount()获得关于此接口的节点数量
getEndpoint(int index)对于指定的index获得此接口的一个节点,返回一个UsbEndpoint

获取USB设备权限

  1. 首先在AndroidManifest.xml中添加权限
	<uses-feature
        android:name="android.hardware.usb.host"
        android:required="true"/>
    <uses-permission android:name="android.permission.MANAGE_USB"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.HARDWARE_TEST"
        tools:ignore="ProtectedPermissions" />

在标签中添加:

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

在res下创建xml名称的文件夹。
device_USB.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device vendor-id="9840" product-id="1030"/>
</resources>
  1. 申请USB权限
 private static final String ACTION_USB_PERMISSION = "com.android.usb.USB_PERMISSION";


 private void getUsbPermission(UsbDevice mUSBDevice) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        registerReceiver(mUsbReceiver, filter);// 广播监听,监听USB设备插拔、权限
        usbManager.requestPermission(mUSBDevice, pendingIntent); // 该代码执行后,系统弹出一个对话框/等待权限
    }

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    unregisterReceiver(mUsbReceiver);
                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false) && device.equals(device)) {
                        //授权成功后,进行USB设备操作
                        initUSB();
                    } else {
                        // 拒绝
                        Toast.makeText(MainActivity.this, "拒绝权限会造成与UKey通信失败!", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    };

初始化设备

  1. 获取USB设备
		UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        List<UsbDevice> usbDevices = new ArrayList<UsbDevice>();
        while (deviceIterator.hasNext()) {
            UsbDevice device = deviceIterator.next();
            usbDevices.add(device);
            Log.e("USB_Test", "getDeviceList: " + device.getDeviceId());
        }
        device = usbDevices.get(0);// U口使用的是第一个设备节点,只获取第一个设备信息
  1. 获取设备功能节点
UsbInterface usbInterface = device.getInterface(0);
UsbEndpoint epBulkIn = usbInterface.getEndpoint(0);// 读信息
UsbEndpoint epBulkOut = usbInterface.getEndpoint(1);// 写入指令

f (usbInterface != null) {
    // open前判断连接权限
    if (usbManager.hasPermission(device)) {
        // 打开USB设备,以便向此USB设备发送和接受数据,返回一个关于此USB设备的连接
        usbDeviceConnection = usbManager.openDevice(device);
    }
    if (usbDeviceConnection != null && usbDeviceConnection.claimInterface(usbInterface, true)) {
        usbDeviceConnection = conn;
        if (usbDeviceConnection != null) {
            // android设备已经连接硬件设备
            Log.e("USB_Test", "android设备已经连接硬件设备.");
        }
    } else {
    
    }
}

USB交互

发送测试指令

 	private void sendToUsb(UsbEndpoint usbEpOut, UsbEndpoint usbEpIn) {
        byte[] buffer = new byte[320];
		// 0200050084000010   随机数
        buffer[0] = 0x02;
        buffer[1] = 0x00;
        buffer[2] = 0x05;
        buffer[3] = 0x00;
        buffer[4] = (byte) 0x84;
        buffer[5] = 0x00;
        buffer[6] = 0x00;
        buffer[7] = 0x10;

		int ret = -1;
        // 发送准备命令
        ret = usbDeviceConnection.bulkTransfer(usbEpOut, buffer, buffer.length, 5000);

        // 接收发送成功信息(相当于读取设备数据)
        byte[] receiveytes = new byte[320];// 根据设备实际情况写数据大小
        ret = usbDeviceConnection.bulkTransfer(usbEpIn, receiveytes, receiveytes.length, 10000);

        try {
            String strHex = DataUtils.getByteHexString(receiveytes);
            tv.setText(ret + "\n " + strHex);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

运行效果:
运行效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值