推广

Android USB通信

iseeyu2年前 (2024-02-22)推广132

Android USB主机模式原理图

在USB主机模式下,我们的Android设备必须支持以下条件:

          1、Android系统版本3.1(API Level 12)及以上。在概述中我们也提到,自Android3.1(API Level 12)开始才提供Android USB Host Mode的支持。

          2、Android设备须支持OTG功能。我们的智能手机和相机等移动设备本身是无法像PC那样直接充当USB Host为总线供电的,而OTG正是为解决此类题而生,目前主流的Android手机和平板都已添加OTG模块。在主机模式下,我们将Android设备上的USB主机模块又称为USB嵌入式主机(Embedded Host 简称 EH)。EH无法像PC上的USB主机一样,为接入总线的未识别外围设备加载驱动程序,所以EH设备提前在系统中对其目标外围设备列表TPL(Target Peripheral List)进行了定义,在这些外围USB设备中大部分是HID设备(Human Interface Device,如游戏手柄)、BOMS设备(Bulk Only Mass Storage,如读卡器、U盘)和CDC设备(Communication Device Class,USB通信设备类,如打印机、相机),其驱动程序已存在于Android平台的系统中(Linux Kernel),Android设备可以直接与这些设备直接通信。

         3、支持AOA协议。AOA协议(Android Open Accessory Protocol,Android开发配件协议)是Google公司推出的用于实现Android设备与外围设备之间进行USB通信的协议,该协议拓展了Android设备USB接口的功能,为基于Android系统的智能设备应用于设备控制和数据采集领域提供了条件。关于AOA协议的固件源码烧写于硬件中,我们有时也把这项称作为Android设备的硬件支持。(该条件仅在接入Android设备外围设备是另一台Android设备时需要,当接入像U盘或打印机时,可不需要AOA协议的支持)

          4、系统features.xml文件中提供了关于<uses-featureandroid:name=”android.hardware.usb.host”/> 的定义。在使用Android USB Host Mode开发时,我们会在应用程序的AndroidMainifast.xml文件中指定<uses-featureandroid:name=”android.hardware.usb.host”/> 用来对不支持Android USB Host Mode的设备进行过滤,Android系统版本3.1及以上默认支持,但是不排除设备商会对原生的Android系统进行裁剪,可能会裁剪掉features.xml文件中关于<uses-featureandroid:name=”android.hardware.usb.host”/>的定义,也就是说当应用程序安装时来扫描系统的硬件支持feature时,发现没有关于<uses-featureandroid:name=”android.hardware.usb.host”/>的定义,认为该设备不支持Android USB Host Mode,也就会提示你无法安装了。

3、Android USB Accessory Mode(USB 从机模式)

          在Android USB Accessory Mode模式下,外部USB硬件充当USB主机,配件包括机器人控制器、扩展坞、音乐设备、自助服务终端、读卡器等。不具备主机功能的Android设备就能够与USB硬件互动。Android USB配件必须设计为与Android设备兼容,并且必须遵守Android配件通信协议。

Android USB从机模式原理图

  在USB 从机模式下,我们的Android设备必须支持以下条件:

         1、Android系统版本2.3.4(API Level 10)及以上。在概述中我们也提到,自Android3.1(API Level 12)开始才直接提供对Android USB Accessory Mode的支持,同时Google提供的配件开发工具包ADK(Accessory Development Kit)提供了Android设备与Android配件通过USB通信的API,该ADK包能够向后兼容至Android2.3.4系统版本。(Android 3.1及以上的系统之所以能够直接支持也是因为系统直接封装了ADK的API)

         2、必须支持AOA协议。在Android USB Accessory Mode中,Android设备必须支持AOA协议,因为当Android设备以从机的方式接入Android配件时,Android配件会通过AOA协议检测并初始化Android设备的USB通信的环境和启动Android设备的USB从机模式。

         3、系统features.xml文件中提供了关于<uses-featureandroid:name=”android.hardware.usb.accessory”/> 的定义。关于该条件与Android USB Host Mode中的原因一致,这里不再赘述。

4:Android USB Host Mode 通信开发指南:

4-1:USB设备管理器在不同版本系统中的获取方式不同:

Android 2.3.4版本:UsbManager manager=UsbManager.getInstance(this);
Android 3.1版本:UsbManager manager=(UsbManager)getSystemService(Context.USB_SERVICE);

4-2:配置AndroidManifest.xml:

1).添加<uses-feature>元素来声明您的应用使用android.hardware.usb.host功能;

2).将应用的最低SDK设置为API级别 12 或更高级别。USB主机API在更早的API级别中不存在。

3).如果您希望应用接收有关连接的 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 设备进行匹配,因此只在应用需要时才这样做:vendor-id、product-id、class、subclass、protocol(设备或接口)如下图:

AndroidManifest资源文件

在 res/xml/device_filter.xml 中,并指定应过滤具有指定属性的所有 USB 设备:

4-3:SUB通信实现代码封装到UsbHidHelper类中:

   

/**

* Created by 631934797 on 2021/3/3

*/

public class UsbHidHelper {

private static final StringTAG = UsbHidHelper.class.getCanonicalName();

    private UsbManagermUsbManager;

    private UsbDeviceConnectionmUsbDeviceConnection;

    private UsbEndpointmUsbEndpointOut;

    private UsbEndpointmUsbEndpointIn;

    private UsbInterfacemUsbInterface;

    private static UsbHidHelpermInstance =null;

    private static ContextmContext;

    private boolean mToggle =true;

    private boolean isConnect =false;

    private ExecutorServicemThreadPool;

    private byte[]recvBuffer  =new byte[1024];

    private int mVendorID ;

    private int mProductID ;

    private int mFindCont =3;

    private final StringUSB_PERMISSION =”roy-lee.usb.permission”;

    private PendingIntentmPrtPermissionIntent; //获取外设权限的意图

    /**

    * 获取UsbHidHelper对象

    * @param context

    * @return

    */

    public static UsbHidHelper  getInstance(Context context) {

             if(mInstance ==null) {

            mInstance =new UsbHidHelper();

           }

         mContext = context;

        return mInstance;

    }

/**

    * 初始化 USB设备

    *

    * @param vendorID

    * @param productID

    */

    public void initUsb_Hid(int vendorID, int productID){

        mVendorID = vendorID;

        mProductID = productID;

        // init UsbManager

        mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);

        // 初始化线程池

        mThreadPool = Executors.newFixedThreadPool(5);

        // 注册usb广播

        registerReceiver();

        // 查找USB设备

        findUsbDevice();

    }

/**

    * 动态注册usb广播,拔插动作,注册动作

    * */

    private void registerReceiver(){

        //注册在此service下的receiver的监听的action

        IntentFilter intentFilter =new IntentFilter();

        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);

        intentFilter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);

        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);

        intentFilter.addAction(USB_PERMISSION);

        mContext.registerReceiver(usbReceiver, intentFilter);//注册receiver

        //通知监听外设权限注册状态

        //PendingIntent:连接外设的intent

       //ask permission

        mPrtPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(USB_PERMISSION), 0);

    }

private BroadcastReceiverusbReceiver =new BroadcastReceiver() {

        @Override

        public void onReceive(Context context, Intent intent) {

                 if (intent ==null) {

                          return;

                  }

                String action = intent.getAction();

                switch (action){

                       // USB注册动作

                      case USB_PERMISSION:

                              synchronized (this) {

                                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {

UsbDevice parcelableExtra = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                            if (parcelableExtra !=null) {

// 连接设备

                                connectDevice(parcelableExtra);

                            }else {

Log.e(TAG,”usb device suddenly disappera.”);

                                Log.e(TAG,”…USB外设意外消失…”);

                            }

}else {

Log.e(TAG,”usb permission granted fail.”);

                            Log.e(TAG,”…USB权限注册失败…”);

                            mFindCont–;

                            if (mFindCont >0){

findUsbDevice();

                            }

}

}

break;

                // USB插入动作

                case UsbManager.ACTION_USB_ACCESSORY_ATTACHED:

case UsbManager.ACTION_USB_DEVICE_ATTACHED:

Log.i(TAG,”…USB 插入…”);

                    mFindCont =3;

                    findUsbDevice();

break;

                // USB拔出动作

                case UsbManager.ACTION_USB_DEVICE_DETACHED:

Log.e(TAG,”…USB 已被拔出…”);

                    mToggle =true;

                    isConnect =false;

break;

            }

}

};

    /**

    *  查找设备

    */

    private boolean findUsbDevice(){

mThreadPool.execute(new Runnable() {

@Override

            public void run() {

//                while (mToggle && mFindCont > 0) {

                    Log.d(TAG, “…查找USB设备…”);

                    HashMap deviceList =mUsbManager.getDeviceList();

                    Collection values = deviceList.values();

                    if (!values.isEmpty()) {

for (UsbDevice usbDevice : values) {

// 输出设备信息

                            Log.e(TAG,”mVendorID : “+mVendorID +”  mProductID : ” +mProductID);

                            Log.d(TAG, “设备ID: vid = ” + String.format(“%x”, usbDevice.getVendorId()) +” , pid = ” + String.format(“%x”, usbDevice.getProductId()));

                            int vendorId = usbDevice.getVendorId();

                            int productId = usbDevice.getProductId();

                            if (vendorId ==mVendorID && productId ==mProductID) {

Log.d(TAG, “…枚举SUB设备成功…”);

                                // 获取权限

                                if (mUsbManager.hasPermission(usbDevice)) {

// 建立连接

                                    connectDevice(usbDevice);

                                }else {

Log.e(TAG,”…申请USB权限失败…”);

                                    mUsbManager.requestPermission(usbDevice, mPrtPermissionIntent);

                                }

}

}

}else {

// TODO 没有USB设备

                        Log.e(TAG,”…没有USB设备…”);

                    }

//                    SystemClock.sleep(10000);

//                    mFindCont–;

//                }

            }

});

        return isConnect;

    }

/**

    * 连接设备

    * @param usbDevice

    */

    private void connectDevice(UsbDevice usbDevice){

Log.e(TAG,”…申请USB权限成功…”);

        Log.e(TAG,”UsbDevice :” + usbDevice);

        // 打开设备

        UsbDeviceConnection conn=mUsbManager.openDevice(usbDevice);

        if (conn !=null) {

mUsbInterface = usbDevice.getInterface(0);

            if (conn.claimInterface(mUsbInterface, true)){

mUsbDeviceConnection = conn;

                int endpointCount =mUsbInterface.getEndpointCount();

                for (int i =0; i < endpointCount; i++) {

UsbEndpoint usbEndpoint =mUsbInterface.getEndpoint(i);

                    Log.e(TAG,”Type: “+ usbEndpoint.getType());

                    Log.e(TAG,”Direction: “+ usbEndpoint.getDirection());

                    // TODO USB 4种传输模式,根据自己实际通信需求自行更改

                    if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {

if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) {

mUsbEndpointOut = usbEndpoint;

                        }else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) {

mUsbEndpointIn = usbEndpoint;

                        }

}

}

if (mUsbEndpointOut !=null &&mUsbEndpointIn !=null) {

// TODO 连接USB设置成功

                    Log.i(TAG,”connected success”);

                    mToggle =false;

                    isConnect =true;

                    onLoopSendData();

                }

}

}

}

/**

    * 发送HID数据

    *

    * @param messageContent

    * @return

    */

    public boolean sendHidData(String messageContent){

return sendHidData(messageContent.getBytes());

    }

public boolean sendHidData(final byte[] contentBytes){

final boolean[] states = {false};

        mThreadPool.execute(new Runnable() {

@Override

            public void run() {

if (mUsbDeviceConnection !=null &&mUsbEndpointOut !=null) {

/**

                    * 发送数据的地方 , 只接受byte数据类型的数据

                    */

                    int i =mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, contentBytes, contentBytes.length, 2000);

                    if (i >0) {

Log.i(TAG,”发 ==> ◇: ” + HexDump.byteTo16String(contentBytes) +”\r\n”);

                        states[0] =true;

                    }else {

Log.e(TAG,”…数据发送失败…”);

                    }

}else {

Log.e(TAG,”…请先连接USB…”);

                }

}

});

        return states[0];

    }

/**

    * 接收HID数据

    *

    * @param callback

    */

    public void receivedHidNewData(final HidDataCallback callback){

mThreadPool.execute(new Runnable() {

@Override

            public void run() {

while (true) {

/**

                    * 循环接受数据的地方 , 只接受byte数据类型的数据

                    */

                    if (mUsbDeviceConnection !=null &&mUsbEndpointIn !=null &&isConnect) {

int i =mUsbDeviceConnection.bulkTransfer(mUsbEndpointIn, recvBuffer, 64, 1000);

                        if (i >0) {

byte[] subArray = HexDump.getSubArray(recvBuffer, 0, i);

                            Log.i(TAG,”收 <== ◆: “+HexDump.byteTo16String(subArray) +”\r\n”);

                            if(callback !=null)

callback.onReceiveHidData(subArray);

                        }

}

SystemClock.sleep(10);

                }

}

});

    }

}

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://www.0291.com.cn/post/56358.html

相关文章

在北京有多少钱才能称之为财务自由?

在北京有多少钱才能称之为财务自由?

在北京有多少钱才能称之为财务自由?...

对于财富,你是否跟我一样?

对于财富,你是否跟我一样?

看了就要关注我,喵呜~这是我陪你的第355天读完这篇文章大约需要6分钟想了两天,该如何写这篇文章?脑袋中思绪翻飞,而在这个时间节点读《穷爸爸富爸爸》真的是引发诸多思考,有些想法有点“大逆不道”,但深刻知道其有一定的道理。对于财富,你是否跟我一样?好好工作获得晋升,努力,贷款...

细分网站标题、导航栏目及内容的关键词匹配规则。

细分网站标题、导航栏目及内容的关键词匹配规则。

seo与sem的不同之处在于,它需要准确和少量的关键字,而seo需要大量的关键字。在网站内部建设、网站内部优化、网站外部推广等方面需要设置关键词。 关于搜索引擎优化关键词,每个人都有不同的想法。许多人知道关键词的密度,但他们不知道合理的匹配关键词。我们不知道匹配会对网站产生什么样的影响,也不知道匹...

如何从穷人思维过渡到富人思维?

如何从穷人思维过渡到富人思维?

如何从穷人过渡到富人思维?------线上理财课程课堂笔记决定一个人贫穷还是富有的根本原因,是思维方式的不同。一、当一个人处于长期性的资源缺失,认知和判断力会全面下降,更加重视短期利益,而忽略长期利益。这就是穷人思维。看一个世界著名潜能激励大师安东尼罗宾的长大故事。安东尼最...

商业10个故事,10种商业智慧,给您不一样的商业思维(深度好文)

商业10个故事,10种商业智慧,给您不一样的商业思维(深度好文)

1、【送的小故事】 张三一直喜欢喝20块钱的茶叶。新开茶店里每次张三去买茶叶,老板都送他半两好茶。张三将好茶攒着待客。一天闲来无事泡壶好茶,竟喝上瘾。喝完免费的好茶,张三便不愿喝20块的了。不管他买多贵的茶叶,老板总送他半两更好的。半年下来,张三花在茶叶上的钱是原...

小编分享全网推广怎么做才有更有效果(全网推广广告怎么做)

小编分享全网推广怎么做才有更有效果(全网推广广告怎么做)

网站其实就相当于公司的形象,就相当于企业自身的宣传单,如果做好了宣传单整天不去推广不去散发,那么你觉得会有什么效果呢?我们需要的是网络推广,只有做了推广才会让更多人看到。那么全网推广怎么做效果? 1、找准自己的定位(是卖产品还是服务,优势有哪些,别人为什么需要找我,我能提供哪些等等)...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片