`

(转)android usb host

阅读更多
【废话一段】

      这段时间,我的小组正在开发一个Android主机的系统,这个系统需要外接USB的指纹机、读卡器、U盘,硬件已经有了,主机是一个开发板接口丰富,并且支持Android USB Host模式,外设自然不用说。

     但是碰到了一个问题,驱动!本来这个项目是源于Windows的,外设全部是针对Windows而开发的,如果要用专门的驱动,那么开发Android本身就需要复杂的过程。后来经过硬件工程师的改造,我们将USB换成了HID模式,减轻开发难度。

     经过一段时间搜索网上资料,关于Android USB Host的资料可以说非常少,不是少数,而是几乎雷同。我是百度+google,更换无数中英文关键字,最后我如愿完成自己的项目,和HID设备正常通讯了,并且识别了U盘。对于网络上中文资料的少而单一的现状,我决定自己写一篇文章,让同行们少走弯路。

    我的代码参考了来自“开源中国”部分资料,如果有解决不了的,可以在那里查询。

【基础功能】

    注意:本文的步骤,可能需要你具备Root的权限,否则有些操作可能会无法完成。强烈建议你先root设备。

    步骤一:你必须确定你的Android设备支持USB Host,具体支持与否请参考自己的说明书。确定了才有必要看本文章。

   步骤二:确认Android是否已经开放了USB访问权限,这一步非常重要。操作是:进入系统,找到目录“/system/etc/permissions”,可以用ES或者RE文件管理器进行操作。查看该目录下,是否有一个文件"android.hardware.usb.host.xml",如果没有,则自己创建一个同名文件,内容如下:
<permissions> 

    <feature name="android.hardware.usb.host"/> 

</permissions>

然后,拷贝到“/system/etc/permissions”目录下。(可以用Eclipse的DDMS帮忙,push进去)

   步骤三:其实呢,有了步骤三基本也就可以了,但是我自己也不是很确定,于是有了步骤四。继续检查目录“/system/etc/permissions”下,将其中的“handheld_core_hardware.xml (手机)或者 tablet_core_hardware.xml(平板)”拖出来,打开文件,看看<permissions>结点下面有没有下面这个结点:

 
<feature name="android.hardware.usb.host" />


如果没有,就自己补上一行,保存,并push进去替换原来的文件。比如我的文件内容是:
<?xml version="1.0" encoding="utf-8"?>

<permissions>

    <feature name="android.hardware.camera" />

    <feature name="android.hardware.location" />

    <feature name="android.hardware.location.network" />

    <feature name="android.hardware.sensor.compass" />

    <feature name="android.hardware.sensor.accelerometer" />

    <feature name="android.hardware.bluetooth" />

    <feature name="android.hardware.touchscreen" />

    <feature name="android.hardware.microphone" />

    <feature name="android.hardware.screen.portrait" />

    <feature name="android.hardware.screen.landscape" />

    <feature name="android.hardware.usb.host" />

</permissions>


步骤四:非常重要,就是重启你的Android设备。
【详细代码】

    事实上,做完上面的步骤,剩下的代码就非常地简单了,我之前搜索到的基本就是这些内容了。

   先看看AndroidManifest.xml文件,为了写这篇文章,我特意做了大量注释:

 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.usbmanager"

    android:versionCode="1"

    android:versionName="1.0" >

      <!-- 这个权限是必须有的,否则操作不了硬件,google的文档没有说出来,据说是因为有过滤器后自动获得,但是我的项目没这句话不成功。 -->

    <uses-permission android:name="android.permission.HARDWARE_TEST" />

    <!-- 这句话也是必须的 -->

    <uses-feature android:name="android.hardware.usb.host" android:required="true"/>

    <!-- SDK必须是12以上的,因为从 Android3.1开始,才正式支持USB Host -->

    <uses-sdk

        android:minSdkVersion="12"

        android:targetSdkVersion="17" />

            

    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:label="@string/app_name"

            >

            <intent-filter>

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

                            

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

            </intent-filter>

            <!-- 以下这个过滤器是要手工增加上,如果不增加也可以在代码中动态注册,不过我的代码是在这里注册 -->

            <intent-filter>

                <action

                    android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

            </intent-filter>

             <!-- 以下这个meta-data是要手工增加上,他是用来过滤你的具体USB设备的,其中的device_filter是个xml文件 -->

            <meta-data

                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"   

                android:resource="@xml/device_filter"/>

            <!--  

            <intent-filter> 

                <action android:name="android.intent.action.VIEW"></action>

                <category android:name="android.intent.category.DEFAULT"></category>

                <data android:mimeType=""></data> 

            </intent-filter>

            -->

                        

        </activity>

    </application>

            

</manifest>

注意看:上面的文件提到了一个文件“device_filter”,他也是你能否成功的一个重要文件”device_filter.xml“,这个文件必须自己创建:

         在项目工程中的res结点创建一个新的文件夹叫”xml“(不会操作????右键啊!),然后再在xml文件夹下创建一个xml,文件名就叫做“device_filter",内容如下:

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <!-- 以下内容的 vendor-id、product-id就是USB的vid和pid了,请大家自己在Windows中找到这个设备的属性,检查设备的VID_PID值-->

    <!-- 还要说明一点的是:Windows设备属性中看到的ID值是16进制表示的,必须转换成10进制,并配置 。-->

    <!-- 测试用的亿捷U盘,Windows中显示的VID是090C,转换为十进制是2316,其他的道理是一样的 -->

    <usb-device vendor-id="2316" product-id="4096"/>

    <!-- 测试用的M1读卡器 -->

    <usb-device vendor-id="1155" product-id="22352"/>

    <!-- USB-HUB -->

    <usb-device vendor-id="1507" product-id="1544" />

</resources>

我必须讲清楚,上面的设备是我测试用的,和大家手上的设备根本不一样,请自行查看USB设备VID\PID然后转换。




         我们再来看看布局文件activity_main.xml,这个布局是测试用的,非常随意,请大家根据自己的项目布局测试,不一定要用我这个,也不要问我为什么要这么设计布局,哥我只是玩玩而已,不要那么认真嘛~~~~~

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".MainActivity" >

   

    <TextView

        android:id="@+id/tvtitle"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/title" />

   

    <EditText

        android:id="@+id/etxsend"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/tvtitle"

        android:layout_below="@+id/tvtitle"

        android:ems="10"

        android:hint="@string/sendhint"

        android:visibility="invisible" />

   

    <EditText

        android:id="@+id/etxreceive"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/btsend"

        android:layout_below="@+id/btsend"

        android:layout_marginTop="37dp"

        android:ems="10"

        android:hint="@string/receivehint"

        android:visibility="invisible" />

   

    <Button

        android:id="@+id/btreceive"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/etxreceive"

        android:layout_below="@+id/etxreceive"

        android:text="@string/btreceive" />

   

    <Button

        android:id="@+id/btsend"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/etxsend"

        android:layout_below="@+id/etxsend"

        android:layout_marginTop="16dp"

        android:text="@string/btsend" />

   

    <ListView

        android:id="@+id/lsv1"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/btreceive"

        android:layout_below="@+id/btreceive" >

    </ListView>

   

</RelativeLayout>

特别是上面提到的一些按钮上的text,大家发挥自己想象力,我不想再贴上values下面的那些文件了。

     

       这回,我们进入了直接的代码模块:MainActivity.java

package com.example.usbmanager;

   

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

   

import android.os.Bundle;

import android.R.string;

import android.app.Activity;

import android.app.PendingIntent;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.DialogInterface;

import android.content.Intent;

import android.content.IntentFilter;

import android.database.DataSetObserver;

import android.hardware.usb.UsbConstants;

import android.hardware.usb.UsbDevice;

import android.hardware.usb.UsbDeviceConnection;

import android.hardware.usb.UsbEndpoint;

import android.hardware.usb.UsbInterface;

import android.hardware.usb.UsbManager;

import android.util.Log;

import android.view.View.OnClickListener;

import android.view.Gravity;

import android.view.Menu;

import android.view.View;

import android.view.ViewGroup;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ListAdapter;

import android.widget.ListView;

import android.widget.Toast;

   

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";   //记录标识

    private Button btsend;      //发送按钮

    private UsbManager manager;   //USB管理器

    private UsbDevice mUsbDevice;  //找到的USB设备

    private ListView lsv1;         //显示USB信息的

    private UsbInterface mInterface;   

    private UsbDeviceConnection mDeviceConnection;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        btsend = (Button) findViewById(R.id.btsend);

   

        btsend.setOnClickListener(btsendListener);

   

        lsv1 = (ListView) findViewById(R.id.lsv1);

        // 获取USB设备

        manager = (UsbManager) getSystemService(Context.USB_SERVICE);

        if (manager == null) {

            return;

        } else {

            Log.i(TAG, "usb设备:" + String.valueOf(manager.toString()));

        }

        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();

        Log.i(TAG, "usb设备:" + String.valueOf(deviceList.size()));

        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

        ArrayList<String> USBDeviceList = new ArrayList<String>(); // 存放USB设备的数量

        while (deviceIterator.hasNext()) {

            UsbDevice device = deviceIterator.next();

   

            USBDeviceList.add(String.valueOf(device.getVendorId()));

            USBDeviceList.add(String.valueOf(device.getProductId()));

   

            // 在这里添加处理设备的代码

            if (device.getVendorId() == 1155 && device.getProductId() == 22352) {

                mUsbDevice = device;

                Log.i(TAG, "找到设备");

            }

        }

        // 创建一个ArrayAdapter

        lsv1.setAdapter(new ArrayAdapter<String>(this,

                android.R.layout.simple_list_item_1, USBDeviceList));

        findIntfAndEpt();

           

    }

   

    private byte[] Sendbytes;    //发送信息字节

    private byte[] Receiveytes;  //接收信息字节

    private OnClickListener btsendListener = new OnClickListener() {

        int ret = -100;

        @Override

        public void onClick(View v) {

            /*

             * 请注意,本模块通信的内容使用的协议是HID读卡器协议,不会和大家手上的设备一样

             * 请大家在测试时参考自己手上的设备资料,严格按照HID标准执行发送和接收数据

             * 我的范例使用的设备是广州微云电子的WY-M1RW-01非接触式读卡器,outputreport是64,因此我发送的字节长度是64

             * 我发送的字节内容是要求读卡器蜂鸣器响两短一长

             */

            String testString = "90000CB20301F401F401F401F407D447FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";

            Sendbytes = clsPublic.HexString2Bytes(testString);

               

            // 1,发送准备命令

            ret = mDeviceConnection.bulkTransfer(epOut, Sendbytes, Sendbytes.length, 5000); 

            Log.i(TAG,"已经发送!");

               

            // 2,接收发送成功信息

            Receiveytes=new byte[64];     //这里的64是设备定义的,不是我随便乱写,大家要根据设备而定

            ret = mDeviceConnection.bulkTransfer(epIn, Receiveytes, Receiveytes.length, 10000);

            Log.i(TAG,"接收返回值:" + String.valueOf(ret));

            if(ret != 64) {

                DisplayToast("接收返回值"+String.valueOf(ret));

                return;

            }

            else {

                //查看返回值

                DisplayToast(clsPublic.Bytes2HexString(Receiveytes));

                Log.i(TAG,clsPublic.Bytes2HexString(Receiveytes));

            }

        }

    };

   

    // 显示提示的函数,这样可以省事,哈哈

    public void DisplayToast(CharSequence str) {

        Toast toast = Toast.makeText(this, str, Toast.LENGTH_LONG);

        // 设置Toast显示的位置

        toast.setGravity(Gravity.TOP, 0, 200);

        // 显示Toast

        toast.show();

    }

       

    // 寻找接口和分配结点

    private void findIntfAndEpt() {

        if (mUsbDevice == null) {

            Log.i(TAG,"没有找到设备");

            return;

        }

        for (int i = 0; i < mUsbDevice.getInterfaceCount();) {

            // 获取设备接口,一般都是一个接口,你可以打印getInterfaceCount()方法查看接

            // 口的个数,在这个接口上有两个端点,OUT 和 IN 

            UsbInterface intf = mUsbDevice.getInterface(i);

            Log.d(TAG, i + " " + intf);

            mInterface = intf;

            break;

        }

   

        if (mInterface != null) {

            UsbDeviceConnection connection = null;

            // 判断是否有权限

            if(manager.hasPermission(mUsbDevice)) {

                // 打开设备,获取 UsbDeviceConnection 对象,连接设备,用于后面的通讯

                connection = manager.openDevice(mUsbDevice); 

                if (connection == null) {

                    return;

                }

                if (connection.claimInterface(mInterface, true)) {

                    Log.i(TAG,"找到接口");

                    mDeviceConnection = connection;

                    //用UsbDeviceConnection 与 UsbInterface 进行端点设置和通讯

                    getEndpoint(mDeviceConnection,mInterface);

                } else {

                    connection.close();

                }

            } else {

                Log.i(TAG,"没有权限");

            }

        }

        else {

            Log.i(TAG,"没有找到接口");

        }

    }

       

       

    private UsbEndpoint epOut;

    private UsbEndpoint epIn;

    //用UsbDeviceConnection 与 UsbInterface 进行端点设置和通讯

    private void getEndpoint(UsbDeviceConnection connection, UsbInterface intf) {

        if (intf.getEndpoint(1) != null) {

            epOut = intf.getEndpoint(1);

        }

        if (intf.getEndpoint(0) != null) {

            epIn = intf.getEndpoint(0);

        }

    }

       

       

}


好吧!已经把该说的代码都说了,我必须吐槽一些百度空间,我写文章很容易吗?为什么我发文章后根本无法查看,老是404,我都已经发消息给百度了,并且我告知他们说,是因为我上传的图片没有正常解析造成的,只要他们将我的文章中图片链接修正即可,结果他们回复我说”尊敬的百度用户:您好!首先非常感谢您对百度产品的使用与支持!对于您所投诉的内容,希望如下答案可以帮助到您。请您确认您的网络状态良好,尝试清空浏览器缓存、cookie,然后刷新页面重试。再次感谢您对百度的关注、支持与理解!“。

         这已经是我第二次碰到百度简直是推脱责任的回复(我一共也就反映过2次),比163的客服差不知道多少,由此我总结一下:百度后台的技术员应该也就那样。

        反正,你现在看得到的这篇文章,是我第二次用键盘敲出来的。




【调试】

      调试的内容应该我不需要讲了,Eclipse会帮你搞定的。



转载网址:http://hi.baidu.com/intel88888/item/9a194171438dd9356dc37ca7


分享到:
评论

相关推荐

    全志 Android USB Host 补丁

    Usb Host ADK是指不采用USB驱动,直接用java与设备编程的 这样让Android 可以无需修改内核和驱动情况下方便与各种USB外设通讯

    android usb host通信

    可以接收单片机发送的usb hid信息,并显示在android手机上

    android下USB Host开发

    android下USB Host开发的一些注意事项和开发步骤

    android usb host实现串口传输数据

    3.1版本之后支持的usb host API。可以通过usb接口让安卓设备作为主设备来接收来自usb的数据,比如平板上插个单片机,就可以接收单片机的数据了。该程序封装了多个包,实现了该功能。

    Android usb host检测

    用于检测Android平板是否支持USB HOST API

    Android USB host简介,中文文档

    Android USB host简介,中文文档

    how to enable android usb host api

    how to enable android usb host api

    android usb host通信示例源码

    此demo实现两个android设备通过usb线进行相互通信,用于host和devices之间通信

    android usb转串口数据通信示例(源代码)亲测可用

    android usb转串口数据通信示例(源代码) android usb转串口数据通信示例。物联网开发中也会经常用到usb转串口,对android手机进行通信。一般都会用otc线进行转换。我在GitHub下来一份代码,亲测可用。并进行了修改...

    android usb转串口源码

    android usb转串口源码,android usb转串口源码,android usb转串口源码,

    关于android USB Host 串口编程

    NULL 博文链接:https://dengzhangtao.iteye.com/blog/1860520

    Android开发USB Host开发

    本人最近在Android的PAD上开发USB Host数据传输,USB驱动芯片是PL2303。(见附件)已经能够正常读写。欢迎试用。

    android usb host

    启用android usb host功能的xml文件。 需要将这个文件加到设备的/system/etc/permissions/目录下,才能开启android设备的usb host权限。

    Android开发USB Host应用

    本人最近在Android的PAD上开发USB Host数据传输。(见附件) 对CH340,已经能够正常读写;但对CH341只是可以正常写出,读入总是有问题:只有当USB缓存满32字节时,才可以读入数据(数据是对的)。 不知道有无同行在CH...

    android usbhost串口编程,优化ch340驱动

    android usbhost串口编程,优化ch340驱动,支持多串口,用于wifi模块产测

    android usbhost

    android USBHOST功能,能解决android与单片机通信,android与zigbee通信的鞥问题

    Usb-host-修复和检测

    修复里面的install_fix.cmd文件把android.hardware.usb.host.xml和tablet_core_hardware.xml写入安卓系统的权限文件夹里。修改系统文件的前提是设备已获得root权限。不让是修改不了文件的。 Check检测是否支持USB ...

    android-PL2303-usb-host

    此demo为android usb host开发 pL2303demo 其他型号修改id即可通用,开发usb host 穿戴设备

    android手机配host

    安装此apk,后运行,可对android手机进行host映射 前提是手机己经root,并且有写入权限

    Android Usb Port Forwarding

    The Android architecture does not allow to start communication from the Android to the host through the USB cable.The opposite is possible, using the Google "Android Debug Bridge" (ADB in short)....

Global site tag (gtag.js) - Google Analytics