换到了一家新公司,于是就有了新的项目。这次的项目 要用Android SDK与USB HID设备进行通信。第一次接触Android SDK,以及USB,记录下源程序、开发过程以及一些心得。

首先,要感谢网上“先行者”们的无私帮助,使得开始的工作进展比较顺利。这里提及两个非常好的网址,我的源码借鉴了这两个网址很多:

http://blog.csdn.net/tianruxishui/article/details/38338087

http://www.android-doc.com/guide/topics/connectivity/usb/host.html

以下是程序源码(目前只开发到探测部分,具体通信部分有待完善):

USB_Access.java:

package com.example.vrgate_usb;
import android.os.Bundle;
import android.app.Service;
import android.app.Activity;
import android.content.Intent;
import android.hardware.usb.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import android.widget.Toast;
import android.content.Context;
import android.widget.TextView;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.os.Handler;
public class USBAccess extends Activity {
 TextView View1 = null;
 TextView View2 = null;
 TextView View3 = null;
 TextView View4 = null;
 TextView View5 = null;
 TextView View6 = null;
 TextView View7 = null;
 TextView View8 = null;
 TextView View9 = null;
 TextView View10 = null;
 TextView View11 = null;
 UsbManager myUsbManager;
 UsbDevice myUsbDevice;
 UsbInterface Interface[];
 UsbDeviceConnection myDeviceConnection;
 UsbEndpoint epBulkOut, epBulkIn;
 UsbEndpoint epControl;
 UsbEndpoint epIntOut, epIntIn;
 int VendorID;
 int ProductID;
 //private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
 private static int TIMEOUT = 300;
 int ret = -1;
 byte[] recvBuffer = new byte[256];
 usb_hid usbHid;
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.usb_access);
  /*
  //usbHid = new usb_hid(this);
  usbHid = usb_hid.getInstance(this);
  if (usbHid.getUsbDevice() == 0)
  {
   this.setTitle("已连接0设备");
  }
  else if(usbHid.getUsbDevice() == -1)
  {
   this.setTitle("已连接-1设备");
  }
  else if(usbHid.getUsbDevice() == -2)
  {
   this.setTitle("已连接-2设备");
  }
  else if(usbHid.getUsbDevice() == -3)
  {
   this.setTitle("已连接-3设备");
  }
  else
  {
   this.setTitle("已连接-9设备");
  }*/

  View1 = (TextView) findViewById(R.id.Vendor_ID);
  View2 = (TextView) findViewById(R.id.Product_ID);
  View3 = (TextView) findViewById(R.id.Count);
  View4 = (TextView) findViewById(R.id.Interface_ID);
  View5 = (TextView) findViewById(R.id.Control_Endpoint);
  View6 = (TextView) findViewById(R.id.BulkIn_Endpoint);
  View7 = (TextView) findViewById(R.id.BulkOut_Endpoint);
  View8 = (TextView) findViewById(R.id.InterruptIn_Endpoint);
  View9 = (TextView) findViewById(R.id.InterruptOut_Endpoint);
  View10 = (TextView) findViewById(R.id.Serial_Number);
  View11 = (TextView) findViewById(R.id.Recv_Data);

  // 获取UsbManager
  myUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
  // 枚举设备
  enumerateDevice(myUsbManager);
  // 查找设备接口
  ret = getDeviceInterface();
  // 获取设备endpoint
  if(ret == 0)
   assignEndpoint(Interface[0]);
  // 打开conn连接通道
  if(ret == 0)
  {
   ret = openDevice(Interface[0]);
  }
  // 开始USB数据收发
  if(ret == 0)
  {
   UsbReadThread thread = new UsbReadThread();
            thread.start();

            final Handler handler= new Handler();
            final Runnable runnable = new Runnable() {
             public void run() {
              View11.setText("data 0:" + recvBuffer[0] + '\n'
                + "data 1:" + recvBuffer[1] + '\n'
                + "data 2:" + recvBuffer[2] + '\n'
                + "data 3:" + recvBuffer[3] + '\n');
             }
            };

            final Thread t = new Thread() {
             @Override
             public void run() {
              while(true)
              {
               handler.post(runnable); //加入到消息队列  这样没有启动新的线程,虽然没有报异常。但仍然阻塞ProgressDialog的显示
               try
               {
                sleep(10); //直接调用
               }
               catch (InterruptedException e)
               {
                return;
               }
              }
             }
            };
            t.start();
  }
 }

 public class UsbReadThread extends Thread {
        @Override
        public void run()
        {
         byte[] data = new byte[256];
         while(true)
         {
          receiveMessageFromEndpoint();
          //sendMessageToEndpoint(data);
         }
        }
    }

 @Override
 public void onResume() {
  super.onResume();
 }

 // 枚举设备函数
 private void enumerateDevice(UsbManager mUsbManager)
 {
  System.out.println("开始进行枚举设备!\n");
  if (mUsbManager == null)
  {
   System.out.println("创建UsbManager失败,请重新启动应用!");
   Context context = getApplicationContext();
   Toast.makeText(context, "创建UsbManager失败,请重新启动应用!", Toast.LENGTH_SHORT).show();
   return;
  }
  else
  {
   HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
   if (!(deviceList.isEmpty()))
   {
    // deviceList不为空
    System.out.println("已连接USB设备至PAD!\n");
    System.out.println("deviceList is not null!");
    Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
    while (deviceIterator.hasNext())
    {
     UsbDevice device = deviceIterator.next();
     // 输出设备信息
     //Log.i(TAG, "DeviceInfo: " + device.getVendorId() + " , " + device.getProductId());
     System.out.println("DeviceInfo:" + device.getVendorId() + " , " + device.getProductId());
     // 保存设备VID和PID
     VendorID = device.getVendorId();
     ProductID = device.getProductId();
     View1.setText("制造商 ID:" + VendorID);  //东芝U盘:2352; VrGate Hid: 1155
     View2.setText("产品ID:" + ProductID);  //东芝U盘:25924; VrGate Hid: 22352
     // 保存匹配到的设备
     if (VendorID == 1155 && ProductID == 22352) {
     //if (VendorID == 2352 && ProductID == 25924) {
      myUsbDevice = device; // 获取USBDevice
      System.out.println("发现待匹配设备:" + device.getVendorId() + "," + device.getProductId());
      Context context = getApplicationContext();
      Toast.makeText(context, "发现待匹配设备。", Toast.LENGTH_SHORT).show();
     }
    }
   }
   else
   {
    System.out.println("请连接USB设备至PAD!");
    Context context = getApplicationContext();
    Toast.makeText(context, "请连接USB设备至PAD!", Toast.LENGTH_SHORT).show();
   }
  }
 }

 // 寻找设备接口
 private int getDeviceInterface()
 {
  if (myUsbDevice != null)
  {
   int count = -1;

   //Log.d(TAG, "interfaceCounts : " + myUsbDevice.getInterfaceCount());
   count = myUsbDevice.getInterfaceCount();
   System.out.println("设备接口数:" + count);
   View3.setText("设备接口数:" + count);
   if (count <= 0)
    return -2;
   Interface = new UsbInterface[count];
   for (int i = 0; i < myUsbDevice.getInterfaceCount(); i++)
   {
    //UsbInterface intf = myUsbDevice.getInterface(i);
    Interface[i] = myUsbDevice.getInterface(i); // 保存设备接口
    System.out.println("成功获得设备接口:" + Interface[i].getId());
    View4.setText("接口号:" + Interface[i].getId());
    View1.setText("制造商 ID:" + VendorID + ";" + myUsbDevice.getInterfaceCount() + ";" + Interface[i].getInterfaceClass() + ";" + Interface[i].getInterfaceSubclass() + ";" + Interface[i].getInterfaceProtocol());
   }

   return 0;
  }
  else
  {
   System.out.println("设备为空!");
   return -1;
  }
 }
 // 分配端点,IN | OUT,即输入输出;可以通过判断
 private void assignEndpoint(UsbInterface mInterface)
 {
  if ((myUsbDevice != null) && (mInterface != null))
  {
   for (int i = 0; i < mInterface.getEndpointCount(); i++)
   {
    UsbEndpoint ep = mInterface.getEndpoint(i);
    int type = ep.getType();
    int direction = ep.getDirection();
    // look for bulk endpoint
    if (type == UsbConstants.USB_ENDPOINT_XFER_BULK)
    {
     if (direction == UsbConstants.USB_DIR_OUT)
     {
      epBulkOut = ep;
      System.out.println("Find the BulkEndpointOut," + "index:" + i + "," + "使用端点号:" + epBulkOut.getEndpointNumber());
      View7.setText("Find the BulkEndpointOut," + "index:" + i + "," + "使用端点号:" + epBulkOut.getEndpointNumber());
     }
     else
     {
      epBulkIn = ep;
      System.out.println("Find the BulkEndpointIn:" + "index:" + i + "," + "使用端点号:" + epBulkIn.getEndpointNumber());
      View6.setText("Find the BulkEndpointIn:" + "index:" + i + "," + "使用端点号:" + epBulkIn.getEndpointNumber());
     }
    }
    // look for control endpoint
    else if (type == UsbConstants.USB_ENDPOINT_XFER_CONTROL)
    {
     epControl = ep;
     System.out.println("find the ControlEndPoint:" + "index:" + i + "," + "使用端点号:" + epControl.getEndpointNumber());
     View5.setText("find the ControlEndPoint:" + "index:" + i + "," + "使用端点号:" + epControl.getEndpointNumber());
    }
    // look for interrupt endpoint
    else if (type == UsbConstants.USB_ENDPOINT_XFER_INT)
    {
     if (direction == UsbConstants.USB_DIR_OUT)
     {
      epIntOut = ep;
      System.out.println("find the InterruptEndpointOut:" + "index:" + i + "," +  "使用端点号:" + epIntOut.getEndpointNumber());
      View9.setText("find the InterruptEndpointOut:" + "index:" + i + "," + "使用端点号:" + epIntOut.getEndpointNumber());
     }
     else
     {
      epIntIn = ep;
      System.out.println("find the InterruptEndpointIn:" + "index:" + i + "," + "使用端点号:" + epIntIn.getEndpointNumber());
      View8.setText("find the InterruptEndpointIn:" + "index:" + i + "," + "使用端点号:" + epIntIn.getEndpointNumber());
     }
    }
   }
   if (epBulkOut == null && epBulkIn == null && epControl == null && epIntOut == null && epIntIn == null)
   {
    throw new IllegalArgumentException("not endpoint is founded!");
   }
  }
 }

 // 打开设备
 public int openDevice(UsbInterface mInterface)
 {
  if (mInterface != null)
  {
   UsbDeviceConnection conn = null;

   Context context = getApplicationContext();
   // 在open前判断是否有连接权限;对于连接权限可以静态分配,也可以动态分配权限
   if (myUsbManager.hasPermission(myUsbDevice))
   {

    conn = myUsbManager.openDevice(myUsbDevice);  //此处与device_filter.xml中的值密切相关!
    if (conn == null)
    {
     Toast.makeText(context, "打开设备失败,未找到该设备!", Toast.LENGTH_SHORT).show();
     return -2;
    }
   }
   else
   {
    Toast.makeText(context, "打开设备失败,无连接权限!", Toast.LENGTH_SHORT).show();
    return -3;
   }

   if (conn.claimInterface(mInterface, true))
   {
    myDeviceConnection = conn;
    //if (myDeviceConnection != null)// 到此你的android设备已经连上zigbee设备
    {
     System.out.println("open设备成功!");
     Toast.makeText(context, "打开设备成功!", Toast.LENGTH_SHORT).show();
    }
    final String mySerial = myDeviceConnection.getSerial();
    System.out.println("设备serial number:" + mySerial);
    View10.setText("设备序列号:" + mySerial);
    //View10.setText("端点数:" + mInterface.getEndpointCount());
    return 0;
   }
   else
   {
    System.out.println("无法打开连接通道。");
    Toast.makeText(context, "无法打开连接通道。", Toast.LENGTH_SHORT).show();
    conn.close();
    return -4;
   }
  }

  return -1;
 }
 // 发送数据
 private void sendMessageToEndpoint(byte[] buffer)
 {
  //if (buffer == null)
  // return;
  if(epIntOut != null)
  {
   // interruptOut传输
   if (myDeviceConnection.bulkTransfer(epIntOut, buffer, buffer.length, 0) < 0)
   {
    System.out.println("interruptOut返回输出为  负数!\n");
    recvBuffer[1] = -1;
    recvBuffer[2] = -5;
    return;
   }
   recvBuffer[1] = 4;
   recvBuffer[2] = 6;
   //System.out.println("Send Message Succeed.");
  }
  else if(epBulkOut != null)
  {
   // bulkOut传输
   if (myDeviceConnection.bulkTransfer(epBulkOut, buffer, buffer.length, 0) < 0)
   {
    recvBuffer[1] = -7;
    recvBuffer[2] = -5;
    System.out.println("bulkOut返回输出为  负数!\n");
    return;
   }
   recvBuffer[1] = 6;
   recvBuffer[2] = 4;
   //System.out.println("Send Message Succeed.");
  }

 }

 // 从设备接收数据bulkIn
 private byte[] receiveMessageFromEndpoint()
 {
  if(epIntIn != null)
  {
   if (myDeviceConnection.bulkTransfer(epIntIn, recvBuffer, 64, 0) < 0)
   {
    System.out.println("interruptIn返回输出为负数!\n");
    recvBuffer[0] = -3;
    recvBuffer[3] = -9;
    return null;
   }
   //System.out.println("Receive Message Succeed!" + "数据返回" + myDeviceConnection.bulkTransfer(epBulkIn, recvBuffer, recvBuffer.length, 3000));
  }
  else if(epBulkIn != null)
  {
   recvBuffer[0] = 3;
   recvBuffer[3] = 3;
   if (myDeviceConnection.bulkTransfer(epBulkIn, recvBuffer, recvBuffer.length, 0) < 0)
   {
    recvBuffer[0] = -2;
    recvBuffer[3] = -7;
    System.out.println("BulkIn返回输出为 负数!\n");
    return null;
   }
   //System.out.println("Receive Message Succeed!" + "数据返回" + myDeviceConnection.bulkTransfer(epBulkIn, recvBuffer, recvBuffer.length, 3000));
  }
  return recvBuffer;
 }
}
 

Android USB Host 通信程序的更多相关文章

  1. Android USB Host 与 Hid 设备通信bulkTransfer()返回-1问题的原因

    近期一直在做Android USB Host 与USB Hid设备(STM32FXXX)的通信,遇到了很多问题.项目源码以及所遇到的其他问题可以见本博客其他相关文章,这里重点讲一下bulkTransf ...

  2. Android USB Host与HID通讯

    前端时间捣鼓一个HID的硬件, 需要和android通信, 网上搜索了一圈,收获不小. 比较好的文章是:      Android USB Host与HID通讯 Android Service创建US ...

  3. 翻译Android USB HOST API

    翻译Android USB HOST API 源代码地址:http://developer.android.com/guide/topics/connectivity/usb/host.html 译者 ...

  4. Android USB Host与HID通讯 (二)

    不好意思,从上一篇到现在确实比较忙,中间又外出了一段时间,虽然也上LOFTER,或者看到一些朋友QQ上加我,给我发信息询问,有些看到了有些可能没看到,偶尔回复了一两个,也不咋的详细,在此我想说,一方面 ...

  5. Android USB Host与HID通讯 (一)

    去年9月份来到现在的公司,接到新公司的第一个项目就是Android USB Host与HID通讯,当时也什么都不懂,就拿着google的api 开发指南 (http://developer.andro ...

  6. Android USB Host 与 HID 之通讯方法(bulkTransfer()与controlTransfer()方法使用)

    转载地址:差满多乃几 Android USB Host与HID通讯,就目前Google Developer提供的方法有bulkTransfer()与controlTransfer(),看是简简单单的两 ...

  7. Android USB Host 与 HID 之通讯方法

    Android USB Host与HID通讯,就目前Google Developer提供的方法有bulkTransfer()与controlTransfer(),看是简简单单的两个方法,要实现真正的通 ...

  8. 【转】Android Service创建USB HOST通信

    之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信.要使用Android的USB Host ...

  9. Android Service创建USB HOST通信

    之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信.要使用Android的USB Host ...

随机推荐

  1. length prototype 函数function的属性,以及构造函数

    前言:学到一些JavaScript高级的知识,在这里记下,方便以后的查找 1.length代表函数定义的形参的个数,挺简单的     例如:function Pen(price,cname) {  . ...

  2. 第四篇、C_快速、冒泡、选择、插入排序、二分查找排序、归并、堆排序

    1.快速排序 实现: 1.取中间一个数作为支点 2.分别在支点的左右两边进行查找,如果左边查找到比支点大,右边查找到比支点小,就交换位置,如此循环,比支点小的数就排在了左边,比支点大的就排在右边 3. ...

  3. iOS启动图片适配问题

    Portrait 是竖屏 top home button Landscape是横屏 left home button retina 要求640x1136pixels, 在右边的Image属性 Expe ...

  4. 12天学好C语言——记录我的C语言学习之路(Day 3)

    12天学好C语言--记录我的C语言学习之路 Day 3: 不知不觉到了第三天的学习,我们前两天学习的东西很杂乱,各个方面都有学习.我觉得这不是不系统,也不是学的不扎实,这种学习对于初学者而言我认为是很 ...

  5. 公共语言运行库(CLR)和中间语言(IL)(一)

    公共语言运行库(.net运行库)即CLR 1.C#先编译为IL,IL为ms的中间语言,IL是平台无关性的. 2.CLR再将IL编译为平台专用语言. 3.CLR在编译IL时为即时编译(JIT) VB.V ...

  6. C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是TAP(Task-based Asynchronous Pattern, 基于任务的异步模式)

    学习书籍: <C#本质论> 1--C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是 ...

  7. Linq 中的TakeWhile 和 SkipWhile

    这两个概念容易搞混 理解了一番后 在这里写下便于记忆 SkipWhile 可以理解为如果条件满足  就一直跳过   知道不满足后 就取剩下的所有元素(后面的不会再判断) TakeWhile 可以理解为 ...

  8. starling 中 的特效

    一. 最好用同一张图片进行缩放变形等处理后组合,这样可以每帧一draw

  9. Jquery Offset, Document, Window 都是什么

    From http://www.cnblogs.com/luhe/archive/2012/11/14/2769263.html   JQuery Offset实验与应用 我们有时候需要实现这样一种功 ...

  10. 推荐:PHPCMS v9 安全防范教程!

    一.目录权限设置很重要:可以有效防范黑客上传木马文件. 如果通过 chmod 644 * -R 的话,php文件就没有权限访问了. 如果通过chmod 755 * -R 的话,php文件的权限就高了. ...