Android小白usb通信入门篇(一)


前些日志去了一趟广州,老总对自动贩卖机有点想法,于是乎回来就开始查阅相关文档做好准备工作,这不记下自己的理解,如果大家有更好的理解,或者本人的一些介绍理解有错误或者偏差的地方,欢迎留言,大家一起共同进步!

一、Android USB开发模式

android 中usb有两种开发模式,一种是host模式,另一种是accessory模式,下面介绍一下这两种模式。

  1. Host模式:如图,此模式中,android设备充当主机,给usb外部设备供电,常见的Host模式有:鼠标、键盘、等。
    在这里插入图片描述
  2. Accessory模式:如图,和Host模式相反,此模式中,usb设备充当主机,给android手机提供电源,常见的设备:无人机远程控制器等。
    在这里插入图片描述
二、进入Hello World
1、 配置AndroidManifest.xml文件中usb模式

在android系统中,默认是关闭usb模式的,当我们将usb外部设备插入android设备时,android系统不回出任何响应。如果我们要打开系统usb模式,需要在android清单文件里使用<uses-feature/>标签声明响应的usb模式

  1. Host模式
    <uses-feature android:name="android.hardware.usb.host" />
  1. accessory模式
    <uses-permission android:name="android.hardware.usb.accessory" />
2、配置usb设备插入的通知和相关usb设备的过滤

若我们希望在插入usb设备时,android系统能接收到提示性通知,则需要在android组件<Activity/>中配置<intent-filter/>和<meta-data/>标签配置相关信息,<intent-filter/>中配置我们要接收的相关类型的信息通知,<meta-data/>配置我们需要检测的指定的设备,标签内容对应一个xml资源文件,里面配置我们指定的usb设备。如下:

<activity android:name=".ui.ChoiceModelActivity">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <!--host模式下通知的过滤-->
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>
    <!--host模式下指定过滤设备的配置文件-->
    <meta-data
        android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
        android:resource="@xml/device_filter" />

    
    <!--accessory模式下通知的过滤-->
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    </intent-filter>
    <!--accessory模式下指定过滤设备的配置文件-->
    <meta-data
        android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
        android:resource="@xml/device_filter" />

</activity>

其中xml资源文件的配置如下:

<?xml version="1.0" encoding="utf-8"?>
<rescources xmlns:android="http://schemas.android.com/apk/res/android">
    <!--host模式-->
    <usb-device
        class=""
        vendor-id=""
        product-id=""
        protoclo=""
        subclass="" />

    <!--accessory模式-->
    <usb-accessory
        model="xxx"
        manufacturer="xxx" />
3、android设备与USB设备连接和通信

无论是host模式还是accessory模式,在进行检测获取usb设备时,都需要用到UsbManager类,只是调用不同的方法而已。如下:

  1. host模式
    1)获取UsbManager
    2)通过usbManager获取连接到的usb外部设备
    3)获取usb设备引用,通过usbManager检测是否有对应权限,若无则请求权限,通过广播接收权限信息获取情况。
    4)与usb设备进行通信
    public static final String action_usb_permission = "org.zhuhailong.myviewproject.permission";

    public void hostModel(Context context) {

        //获取UsbManager
        UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

        //获取usb设备列表
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();

        Set<Map.Entry<String, UsbDevice>> entries = deviceList.entrySet();

        UsbDevice mUsbDevice = null;

        for (Map.Entry<String, UsbDevice> entry : entries) {
            UsbDevice value = entry.getValue();
            String key = entry.getKey();

            if (filterDevice(key, value)) {//判断是否使我们要连接的usb设备
                mUsbDevice = value;
                break;
            }
        }

        if (usbManager.hasPermission(mUsbDevice)) {//检测是否有usb权限
            requestPermission(mUsbDevice);
        } else {
            connect(mUsbDevice);
        }

    }

    /**
     * 请求usb权限
     * @param usbManager
     * @param parcelable
     */
    public void requestPermission(Parcelable parcelable,UsbManager usbManager) {           
    		UsbDevice usbDevice = (UsbDevice) parcelable;
            if (!usbManager.hasPermission(usbDevice)) {
                IntentFilter intentFilter = new IntentFilter(action_usb_permission);
                registerReceiver(mMyBroadcastReceiver, intentFilter);
                PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent(action_usb_permission), 0);
                usbManager.requestPermission(usbDevice, broadcast);
            } else {
                Toast.makeText(context, "already have permission", Toast.LENGTH_SHORT).show();
            }
        }
    }

    public boolean connect(UsbDevice mUsbDevice) {
        if (mUsbDevice != null) {
            UsbInterface anInterface = mUsbDevice.getInterface(0);
            mUsbDeviceConnection = mUsbManager.openDevice(mUsbDevice);//连接usb设备
            if (mUsbDeviceConnection == null) {
                Toast.makeText(mContext, "mUsbDeviceConnection can't be null", Toast.LENGTH_SHORT).show();
                return false;
            }
            if (mUsbDeviceConnection.claimInterface(anInterface, true)) {
                Toast.makeText(mContext, "找到USB接口", Toast.LENGTH_SHORT).show();
                int endpointCount = anInterface.getEndpointCount();
                for (int i = 0; i < endpointCount; i++) {
                    UsbEndpoint endpoint = anInterface.getEndpoint(i);
                    if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                        if (UsbConstants.USB_DIR_IN == endpoint.getDirection()) {
                            mUsbEndpoint_in = endpoint;//获取读数据通道
                        } else {
                            mUsbEndpoint_out = endpoint;//获取写数据通道
                        }
                    }
                }
                return true;
            } else {
                mUsbDeviceConnection.close();//关闭连接
                Toast.makeText(mContext, "找不到USB接口", Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(mContext, "mUsbDevice can't be null", Toast.LENGTH_SHORT).show();
        }
        return false;
    }

    /**
     * 从usb通信设备中读取数据
     * @return
     */
    public byte[] readData() {
        int inMax = mUsbEndpoint_in.getMaxPacketSize();
        byte[] bytes = new byte[inMax];
        ByteBuffer byteBuffer = ByteBuffer.allocate(inMax);
        UsbRequest usbRequest = new UsbRequest();
        usbRequest.initialize(mUsbDeviceConnection, mUsbEndpoint_in);
        usbRequest.queue(byteBuffer, inMax);
        if (mUsbDeviceConnection.requestWait() == usbRequest) {
            bytes = byteBuffer.array();
        }
        return bytes;
    }

    /**
     * 将数据写入到usb设备中
     * @param bytes
     */
    public void sendData(byte[] bytes) {
        if (mUsbDeviceConnection == null) {
            Toast.makeText(mContext, "mUsbDeviceConnection can't be null", Toast.LENGTH_SHORT).show();
            return;
        }
        if (mUsbEndpoint_out == null) {
            Toast.makeText(mContext, "mUsbEndpoint_out can't be null", Toast.LENGTH_SHORT).show();
            return;
        }

        int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpoint_out, bytes, bytes.length, 1000);
        if (i < 0) {
            Toast.makeText(mContext, "failure to write", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(mContext, "success to write", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 权限广播接收器
     */
    private BroadcastReceiver mMyBroadcastReceiver=new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action_usb_permission.equals(action)) {
                synchronized (this) {
                    UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (usbDevice != null) {
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            connect(usbDevice);
                            Toast.makeText(context, "success get permission", Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(context, "failure get permission", Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(context, "the usbDevice be null", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    };

    /**
     * 筛选出我们想要的usb设备
     * @param name
     * @param usbDevice
     * @return
     */
    public boolean filterDevice(String name, UsbDevice usbDevice) {
        // TODO: 2019/3/13 对应判断设备是否是我们要连接的设备
        return false;
    }
  1. accessory模式(和host模式差不多,大致步骤一样,只是相关类不同而已如下)
    1)获取UsbManager
    2)通过usbManager获取连接到的usb外部设备UsbAccessory
    3)获取usb设备引用,通过usbManager检测是否有对应权限,若无则请求权限,通过广播接收权限信息获取情况。
    4)与UsbAccessory设备进行通信
    public static final String action_usb_permission = "org.zhuhailong.myviewproject.permission";

    private UsbManager usbManager;

    public void hostAccessory(Context context) {

        //获取UsbManager
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

        //获取usb设备列表
        UsbAccessory[] accessoryList = usbManager.getAccessoryList();

        if (accessoryList == null || accessoryList.length <= = 0) {
            Toast.makeText(context, "未查询到对应设备", Toast.LENGTH_SHORT).show();
            return;
        }

        UsbAccessory mUsbAccessory = null;
        for (UsbAccessory usbAccessory : accessoryList) {
            if (filterDevice(usbAccessory)) {//判断是否使我们要连接的usb设备
                break;
            }
        }

        if (usbManager.hasPermission(mUsbAccessory)) {//检测是否有usb权限
            requestPermission(mUsbAccessory);//请求usb权限
        } else {
            connect(mUsbAccessory);//连接usb设备
        }

    }

    /**
     * 请求usb权限
     *
     * @param usbManager
     * @param parcelable
     */
    public void requestPermission(Parcelable parcelable, UsbManager usbManager) {
        UsbAccessory usbAccessory = (UsbAccessory) parcelable;
        if (!usbManager.hasPermission(usbAccessory)) {
            IntentFilter intentFilter = new IntentFilter(action_usb_permission);
            registerReceiver(mMyBroadcastReceiver, intentFilter);
            PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent(action_usb_permission), 0);
            usbManager.requestPermission(usbAccessory, broadcast);
        } else {
            Toast.makeText(context, "already have permission", Toast.LENGTH_SHORT).show();
        }
    }

    private FileInputStream mFileInputStream;

    private FileOutputStream mFileOutputStream;

    /**
     * 连接设备
     * @param usbAccessory
     * @return
     */
    public boolean connect(UsbAccessory usbAccessory) {
        ParcelFileDescriptor parcelFileDescriptor = usbManager.openAccessory(usbAccessory);
        if (parcelFileDescriptor != null) {
            FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();

            mFileInputStream = new FileInputStream(fileDescriptor);

            mFileOutputStream = new FileOutputStream(fileDescriptor);

        }
        return false;
    }

    /**
     * 写入数据
     * @param data
     */
    public void write(byte[] data) {
        try {
            mFileOutputStream.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 读取数据
     */
    public void read() {
        int max;//字节数据根据协议来确定
        byte[] data = new byte[max];
        mFileInputStream.read(data);
    }


    /**
     * 权限广播接收器
     */
    private BroadcastReceiver mMyBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action_usb_permission.equals(action)) {
                synchronized (this) {
                    UsbAccessory usbAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                    if (usbAccessory != null) {
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            connect(usbAccessory);
                            Toast.makeText(context, "success get permission", Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(context, "failure get permission", Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(context, "the usbDevice be null", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    };

    /**
     * 筛选出我们想要的usb设备
     *
     * @param usbAccessory
     * @return
     */
    public boolean filterDevice(UsbAccessory usbAccessory) {
        // TODO: 2019/3/13 对应判断设备是否是我们要连接的设备
        return false;
    }

注意!!!重要的事情说三遍,由于本人未使用过Accessory模式,在参考其他文章进行整理书写的,若有错误地方欢迎通知,必打赏。
第二遍:同上
第三遍:同上

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值