usb 端点host怎样知道访问哪个端点

android(100)
eclipse(22)
【废话一段】
&&&&&&这段时间,我的小组正在开发一个Android主机的系统,这个系统需要外接USB的指纹机、读卡器、U盘,硬件已经有了,主机是一个开发板接口丰富,并且支持Android&USB&Host模式,外设自然不用说。
&&&&&但是碰到了一个问题,驱动!本来这个项目是源于Windows的,外设全部是针对Windows而开发的,如果要用专门的驱动,那么开发Android本身就需要复杂的过程。后来经过硬件工程师的改造,我们将USB换成了HID模式,减轻开发难度。
&&&&&经过一段时间搜索网上资料,关于Android&USB&Host的资料可以说非常少,不是少数,而是几乎雷同。我是百度+google,更换无数中英文关键字,最后我如愿完成自己的项目,和HID设备正常通讯了,并且识别了U盘。对于网络上中文资料的少而单一的现状,我决定自己写一篇文章,让同行们少走弯路。
&&&&我的代码参考了来自“开源中国”部分资料,如果有解决不了的,可以在那里查询。
【基础功能】
&&&&注意:本文的步骤,可能需要你具备Root的权限,否则有些操作可能会无法完成。强烈建议你先root设备。
&&&&步骤一:你必须确定你的Android设备支持USB&Host,具体如何确定啊,还是看设备的说明书吧。如果支持,进入下一步骤。
&&&&步骤二:确定Android有没有开启USB&Host的权限,必须是开启的才能通讯。首先用RE文件管理器(或者连接Eclipse时使用DDMS查看),反正要能进入以下目录:/system/etc/permissions。
你应该要能看到目录有一个“android.hardware.usb.host.xml”,一个“handheld_core_hardware.xml(手机)”或者“tablet_core_hardware.xml(平板)”,
&&&&&&&如果看不到“android.hardware.usb.host.xml”,那么就用记事本写入以下代码,保存,然后PUSH或粘贴到/system/etc/permissions目录下。
&span style=&font-family: 'Comic Sans MS';&&&permissions&
      &feature name=&android.hardware.usb.host&/& 
&/permissions&&/span&
&&步骤三:拷出“handheld_core_hardware.xml(手机)”或者“tablet_core_hardware.xml(平板)”文件,怎么操作?我是用Eclipse的DDMS中的File&Explorer把文件pull出来的,还可以用其他方法。
&&&&&&&&&打开文件,你应该可以看到&permissions&结点下面有不少东西,检查有没有一段:
&span style=&font-family: 'Comic Sans MS';&&&feature name=&android.hardware.usb.host& /&&/span&
&&&&&&&&&确定没有就补上去,比如我的是:
&span style=&font-family: 'Comic Sans MS';&&&permissions&
    &feature name=&android.hardware.camera& /&
    &feature name=&android.hardware.location& /&
    &feature name=&android.hardware.location.network& /&
    &feature name=&android.pass& /&
    &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&&/span&
&&&&&步骤四:以上步骤做完后,请重启你的设备。
【代码内容】
&&&&&&&&&&步骤一:&这里有个细节,就是【AndroidManifest.xml】文件中的权限,网上的多数文章,包括google的官方文档都只讲到其一,其实还有一个,留意代码。
&&&&&先贴上【AndroidManifest.xml】
&span style=&font-family: 'Comic Sans MS';&&&manifest xmlns:android=&/apk/res/android&
    package=&com.example.&a target=_blank target=&_blank& name=&baidusnap0& style=&color: rgb(202, 0, 0);&&&/a&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&/&
                                            
        &/activity&
    &/application&
                                          
&/manifest&&/span&
&&&&步骤二:有没有发现,我们还需要一个device_filte.xml文件,这个文件包含有你的USB设备的ProductID和VendorID,即我们常说的PID和VID,不知道这2个值的,请查Windows的设备管理器属性。记住:Windows用的是16进制表示的,你必须将它转为10进制,以下有说明。
&&&&&&&添加步骤:在Eclipse项目中找到res结点,看有没有xml文件夹,如果没有就点右键--new---folder,新增文件夹名xml,然后在该xml文件夹下用同样的方法新增一个device_filte.xml文件,文件名一定不能错,内容如下:
&span style=&font-family: 'Comic Sans MS';&&&?xml version=&1.0& encoding=&utf-8&?&
&resources&
    &!-- 亿捷U盘,vid的16进制是090C,pid是1000,转10进制是分别是 --&
    &usb-device vendor-id=&2316& product-id=&4096&/&
    &!-- M1读卡器 ,vid的16进制是0483,pid是5750,转10进制是分别是--&
    &usb-device vendor-id=&1155& product-id=&22352&/&
&/resources&&/span&
&&&&&&&&怎么转16进制为10进制???用windows计算器啊,1.查看类型是科学型,2.选中16进制,3.输入值,4.再选择回10进制就可以了。
步骤三:布局文件其实应该是因人而异的,由于我刚做的时候是随意列出的,不建议大家仿照。我的文件名是activity_main.xml,你们的可能是main.xml,不一定要一模一样,只要啊Activity代码描述清楚就行。我的代码基本没用到多少控件,请适当过滤。
&span style=&font-family: 'Comic Sans MS';&&&RelativeLayout xmlns:android=&/apk/res/android&
    xmlns:tools=&/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=&usb简易调试工具& /&
                          
    &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=&发送内容&
        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=&接收内容&
        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=&接收& /&
                          
    &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=&发送& /&
                          
    &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&&/span&
步骤四:好吧,我承认我比较啰嗦,到现在才进入步骤四的MainActivity.java,由于我的目标更多是让大家知道如何连接上设备,因此代码显得随意,并且这些代码在网上也能搜索到,因此写的不是很好,但是做了非常多注释,值得参考。
&span style=&font-family: 'Comic Sans MS';&&package com.example.
         
import java.util.ArrayL
import java.util.HashM
import java.util.I
import java.util.L
         
import android.os.B
import android.R.
import android.app.A
import android.app.PendingI
import android.content.BroadcastR
import android.content.C
import android.content.DialogI
import android.content.I
import android.content.IntentF
import android.database.DataSetO
import android.hardware.usb.UsbC
import android.hardware.usb.UsbD
import android.hardware.usb.UsbDeviceC
import android.hardware.usb.UsbE
import android.hardware.usb.UsbI
import android.hardware.usb.UsbM
import android.util.L
import android.view.View.OnClickL
import android.view.G
import android.view.M
import android.view.V
import android.view.ViewG
import android.widget.ArrayA
import android.widget.B
import android.widget.EditT
import android.widget.ListA
import android.widget.ListV
import android.widget.T
         
public class MainActivity extends Activity {
    private static final String TAG = &MainActivity&;   //记录标识
    private Button       //发送按钮
    private UsbManager    //USB管理器
    private UsbDevice mUsbD  //找到的USB设备
    private ListView lsv1;         //显示USB信息的
    private UsbInterface mI   
    private UsbDeviceConnection mDeviceC
    @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) {
            
        } 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() == ;&& device.getProductId() == 22352) {
                mUsbDevice = 
                Log.i(TAG, &找到设备&);
            }
        }
        // 创建一个ArrayAdapter
        lsv1.setAdapter(new ArrayAdapter&String&(this,
                android.R.layout.simple_list_item_1, USBDeviceList));
        findIntfAndEpt();
                 
    }
         
    private byte[] S    //发送信息字节
    private byte[] R  //接收信息字节
    private OnClickListener btsendListener = new OnClickListener() {
        int ret = -100;
        @Override
        public void onClick(View v) {
            /*
             * 请注意,本模块通信的内容使用的协议是HID读卡器协议,不会和大家手上的设备一样
             * 请大家在测试时参考自己手上的设备资料,严格按照HID标准执行发送和接收数据
             * 我的范例使用的设备是广州微云电子的WY-M1RW-01非接触式读卡器,outputreport是64,因此我发送的字节长度是64
             * 我发送的字节内容是要求读卡器蜂鸣器响两短一长
             */
            String testString = &9F401F401F401F407D447FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF&;
            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));
                
            }
            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,&没有找到设备&);
            
        }
        for (int i = 0; i & mUsbDevice.getInterfaceCount();) {
            // 获取设备接口,一般都是一个接口,你可以打印getInterfaceCount()方法查看接
            // 口的个数,在这个接口上有两个端点,OUT 和 IN 
            UsbInterface intf = mUsbDevice.getInterface(i);
            Log.d(TAG, i + & & + intf);
            mInterface = 
            
        }
         
        if (mInterface != null) {
            UsbDeviceConnection connection = 
            // 判断是否有权限
            if(manager.hasPermission(mUsbDevice)) {
                // 打开设备,获取 UsbDeviceConnection 对象,连接设备,用于后面的通讯
                connection = manager.openDevice(mUsbDevice); 
                if (connection == null) {
                    
                }
                if (connection.claimInterface(mInterface, true)) {
                    Log.i(TAG,&找到接口&);
                    mDeviceConnection = 
                    //用UsbDeviceConnection 与 UsbInterface 进行端点设置和通讯
                    getEndpoint(mDeviceConnection,mInterface);
                } else {
                    connection.close();
                }
            } else {
                Log.i(TAG,&没有权限&);
            }
        }
        else {
            Log.i(TAG,&没有找到接口&);
        }
    }
             
             
    private UsbEndpoint epO
    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);
        }
    }
             
             
步骤五:我在步骤四的代码中包含有个类clsPublic,这个类是用来转换十六进制和字符串的,一般来说大家也不需要,但是考虑代码完整性,我也贴上来。这个类和MainActivity是在同一个包名下的文件clsPublic.java。
&span style=&font-family: 'Comic Sans MS';&&package com.example.
       
public class clsPublic {
    // 整数到字节数组转换
     public static byte[] int2bytes(int n) {
     byte[] ab = new byte[4];
     ab[0] = (byte) (0xff & n);
     ab[1] = (byte) ((0xff00 & n) && 8);
     ab[2] = (byte) ((0xff;& n) && 16);
     ab[3] = (byte) ((0xff0;& n) && 24);
     return 
     }
       
     // 字节数组到整数的转换
     public static int bytes2int(byte b[]) {
     int s = 0;
     s = ((((b[0] & 0xff) && 8 | (b[1] & 0xff)) && 8) | (b[2] & 0xff)) && 8
     | (b[3] & 0xff);
     return s;
     }
       
     // 字节转换到字符
     public static char byte2char(byte b) {
     return (char) b;
     }
       
     private final static byte[] hex = &ABCDEF&.getBytes();
       
     private static int parse(char c) {
     if (c &= 'a')
     return (c - 'a' + 10) & 0x0f;
     if (c &= 'A')
     return (c - 'A' + 10) & 0x0f;
     return (c - '0') & 0x0f;
     }
       
     // 从字节数组到十六进制字符串转换
     public static String Bytes2HexString(byte[] b) {
     byte[] buff = new byte[2 * b.length];
     for (int i = 0; i & b. i++) {
     buff[2 * i] = hex[(b[i] && 4) & 0x0f];
     buff[2 * i + 1] = hex[b[i] & 0x0f];
     }
     return new String(buff);
     }
       
     // 从十六进制字符串到字节数组转换
     public static byte[] HexString2Bytes(String hexstr) {
     byte[] b = new byte[hexstr.length() / 2];
     int j = 0;
     for (int i = 0; i & b. i++) {
     char c0 = hexstr.charAt(j++);
     char c1 = hexstr.charAt(j++);
     b[i] = (byte) ((parse(c0) && 4) | parse(c1));
     }
     return b;
     }
&&&&&&&&&&制作完成软件后,安装到设备上,或者直接用Eclipse调试运行。然后插入USB-HID设备,幸运的话,你会看到系统弹出一个打开方式的提示(我的设备是这样的,其他设备不知道是什么结果)。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:29600次
排名:千里之外
原创:24篇
转载:88篇
(1)(3)(10)(10)(1)(1)(2)(6)(13)(30)(9)(2)(6)(6)(7)(3)(1)

我要回帖

更多关于 usb 端点0 的文章

 

随机推荐