【转】Android Service创建USB HOST通信

时间:2021-11-15 08:01:25

之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信。要使用Android的USB Host功能,首先你需要确定你的平板(手机)设备是否支持USB Host的功能,你可以从手机开发商的简介里面看到,这个功能是由CPU直接关联的,和软件没有关系,所以,你可以把你的外设模块插进去你的Android设备看看有没有反应(比如:指示灯亮),假如没有反应,那肯定是不支持的。

废话说了那么多了,进入正题。

我的案子是把USB的通信写在Service里面的,有不了解Service的,先看Service的相关内容。下面列出了Android对USB的支持。

【转】Android Service创建USB HOST通信

点开USB,你可以看到Android USB支持的两种模式:

【转】Android Service创建USB HOST通信

第一种就是HOST模式:Android设备为USB总线和外设供电,数据传输是双向的。

第二种是Accessory模式:即附件模式,Android作为附件,手机和电脑连接,通常是这种模式,由USB Device端向总线供电,数据传输方向是双向的。这就是为什么手机插到电脑上可以充电的原因。

我们讨论的是第一种模式——HOST。

在讨论具体代码之前,我需要先讲一下再host模式下面的调试办法,因为数据线的端口被外设使用了,那么,传统的连接数据线调试的方法已经不行了。官网给出了解决办法:

1、请把你的Android设备用数据线连接到电脑,当然,你也要把Android设备的wifi打开。

2、在windows命令行下,进入SDK platform-tools/ 目录(具体看你把SDK安装在哪个目录了),执行 adb tcpip 5555 回车。这里其实是打开了adb调试的无线端口(Android设备在电脑上的端口映射),其实后面的数字你可以随便来,只要端口没有被占用。

3、adb connect <device-ip-address>:5555键入回车,这里的device-ip-address是你Android端的IP地址。

4、最后adb usb回车,假如没有问题,现在你已经可以在eclipse上看到logcat的输出了。

其实还有个简单的办法,笔者是使用这个办法,你可以在应用商店上下一个无线ADB工具,随便哪个都可以,这类工具就是在Android端做了上面的那些工作,而且还不用连数据线,但是第三步的那个操作还是要你在windows的命令行窗口手动输入的。

通过上面的操作,你已经可以用无线下载你写的程序、调试了。

在写代码之前,我们必须在我们的manifest文件里面声明我们要使用USB Host的功能。

方法:添加权限标签

  1. <uses-feature
  2. android:name="android.hardware.usb.host"
  3. android:required="true" />
  4. <uses-permission
  5. android:name="android.hardware.usb.host"
  6. android:required="false" />

上面的代码,会表明本应用程序是要使用host的功能的。

除开声明外,你还要添加一个关于设备信息的xml文件,这个文件放在res目录下的xml目录下:

【转】Android Service创建USB HOST通信

里面写好了我们要发现的具体设备的PID、VID,我只写了这两个,这是我在测试阶段用的一个设备的:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <usb-device
  4. product-id="5800"
  5. vendor-id="1105" />
  6. </resources>

里面的两个id你可以通过后面的枚举设备中打印出来。这样是方便设备一插入 ,系统就会提醒用户打开对设备进行声明的程序。

当然,你还要manifest中的某个activity下声明,你使用了这个文件,那么,一旦你打开应用,就会自动跳转到你声明的那个activity:

  1. <activity
  2. android:name="cyc.gzpl.gzplv3.WelcomeActivity"
  3. android:launchMode="standard"
  4. android:screenOrientation="landscape"
  5. android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
  6. <intent-filter>
  7. <action android:name="android.intent.action.MAIN" />
  8. <category android:name="android.intent.category.LAUNCHER" />
  9. </intent-filter>
  10. <intent-filter>
  11. <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
  12. </intent-filter>
  13. <meta-data
  14. android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
  15. android:resource="@xml/device_filter" />

我放在了MainActivity。

建立了一个Service类:

  1. public class ZigbeeService extends Service {
  2. //这里定义一些必要的变量
  3. <span style="white-space:pre">  </span>@Override
  4. public void onStart(Intent intent, int startId) {
  5. // TODO Auto-generated method stub
  6. super.onStart(intent, startId); // 每次startService(intent)时都回调该方法
  7. System.out.println("进入service的onStart函数");
  8. myUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // 获取UsbManager
  9. // 枚举设备
  10. enumerateDevice(myUsbManager);
  11. // 查找设备接口
  12. getDeviceInterface();
  13. // 获取设备endpoint
  14. assignEndpoint(Interface2);
  15. // 打开conn连接通道
  16. openDevice(Interface2);
  17. }

这一段代码,基本上已经完成了和USB建立连接了。我们一个个来分析:

  1. myUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // 获取UsbManager

这条代码的作用是获取一个UsbManager的实例,通过它我们可以获取USB的状态,并且和USB设备进行通信。总的来说,它管理了USB设备。

你把你的外设插入USB接口后,紧接着就是调用美剧USB总线上的usb设备了,具体函数实现如下:

  1. // 枚举设备函数
  2. private void enumerateDevice(UsbManager mUsbManager) {
  3. System.out.println("开始进行枚举设备!");
  4. if (mUsbManager == null) {
  5. System.out.println("创建UsbManager失败,请重新启动应用!");
  6. info.setText("创建UsbManager失败,请重新启动应用!");
  7. return;
  8. } else {
  9. HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
  10. if (!(deviceList.isEmpty())) {
  11. // deviceList不为空
  12. System.out.println("deviceList is not null!");
  13. Iterator<UsbDevice> deviceIterator = deviceList.values()
  14. .iterator();
  15. while (deviceIterator.hasNext()) {
  16. UsbDevice device = deviceIterator.next();
  17. // 输出设备信息
  18. Log.i(TAG, "DeviceInfo: " + device.getVendorId() + " , "
  19. + device.getProductId());
  20. System.out.println("DeviceInfo:" + device.getVendorId()
  21. + " , " + device.getProductId());
  22. // 保存设备VID和PID
  23. VendorID = device.getVendorId();
  24. ProductID = device.getProductId();
  25. // 保存匹配到的设备
  26. if (VendorID == 1105 && ProductID == 5800) {
  27. myUsbDevice = device; // 获取USBDevice
  28. System.out.println("发现待匹配设备:" + device.getVendorId()
  29. + "," + device.getProductId());
  30. Context context = getApplicationContext();
  31. Toast.makeText(context, "发现待匹配设备", Toast.LENGTH_SHORT)
  32. .show();
  33. }
  34. }
  35. } else {
  36. info.setText("请连接USB设备至PAD!");
  37. Context context = getApplicationContext();
  38. Toast.makeText(context, "请连接USB设备至PAD!", Toast.LENGTH_SHORT)
  39. .show();
  40. }
  41. }
  42. }

通过上面的枚举函数,总线上面的设备都会被列出来,你可以选择符合你要求的设备,把它放到一个UsbDevice的实例里面。接下来还不能对USB进行直接通信。。。

接下来的工作:查找外设的usb接口,我的zigbee上面有两个接口,一个0接口,还有一个2接口,我在这里吃了很大的亏,我一直忽视了2接口,一直死在0接口那里,0接口是用来进行配置的,作为用户层,是用不到的,2接口作为数据传输口。具体情况可能是要根据你的外设的情况来定的,推荐你接口的信息都要打印出来,并且都试一下。

下面是查询接口的具体实现:

  1. // 寻找设备接口
  2. private void getDeviceInterface() {
  3. if (myUsbDevice != null) {
  4. Log.d(TAG, "interfaceCounts : " + myUsbDevice.getInterfaceCount());
  5. for (int i = 0; i < myUsbDevice.getInterfaceCount(); i++) {
  6. UsbInterface intf = myUsbDevice.getInterface(i);
  7. if (i == 0) {
  8. Interface1 = intf; // 保存设备接口
  9. System.out.println("成功获得设备接口:" + Interface1.getId());
  10. }
  11. if (i == 1) {
  12. Interface2 = intf;
  13. System.out.println("成功获得设备接口:" + Interface2.getId());
  14. }
  15. }
  16. } else {
  17. System.out.println("设备为空!");
  18. }
  19. }

把获取到的接口,存放在一个UsbInterface实例里面。接下来还是不能直接通信的。。。。。

接下来,我们要分配接口的端点:

  1. // 分配端点,IN | OUT,即输入输出;可以通过判断
  2. private UsbEndpoint assignEndpoint(UsbInterface mInterface) {
  3. for (int i = 0; i < mInterface.getEndpointCount(); i++) {
  4. UsbEndpoint ep = mInterface.getEndpoint(i);
  5. // look for bulk endpoint
  6. if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
  7. if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
  8. epBulkOut = ep;
  9. System.out.println("Find the BulkEndpointOut," + "index:"
  10. + i + "," + "使用端点号:"
  11. + epBulkOut.getEndpointNumber());
  12. } else {
  13. epBulkIn = ep;
  14. System.out
  15. .println("Find the BulkEndpointIn:" + "index:" + i
  16. + "," + "使用端点号:"
  17. + epBulkIn.getEndpointNumber());
  18. }
  19. }
  20. // look for contorl endpoint
  21. if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL) {
  22. epControl = ep;
  23. System.out.println("find the ControlEndPoint:" + "index:" + i
  24. + "," + epControl.getEndpointNumber());
  25. }
  26. // look for interrupte endpoint
  27. if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
  28. if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
  29. epIntEndpointOut = ep;
  30. System.out.println("find the InterruptEndpointOut:"
  31. + "index:" + i + ","
  32. + epIntEndpointOut.getEndpointNumber());
  33. }
  34. if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
  35. epIntEndpointIn = ep;
  36. System.out.println("find the InterruptEndpointIn:"
  37. + "index:" + i + ","
  38. + epIntEndpointIn.getEndpointNumber());
  39. }
  40. }
  41. }
  42. if (epBulkOut == null && epBulkIn == null && epControl == null
  43. && epIntEndpointOut == null && epIntEndpointIn == null) {
  44. throw new IllegalArgumentException("not endpoint is founded!");
  45. }
  46. return epIntEndpointIn;
  47. }

usb的端点不是随便分配的,有IN/OUT之分,前者是输入,后者是输出。

【转】Android Service创建USB HOST通信

分配到的端点,用UsbEndpoint的实例存起来。Endpoint是用来传输数据的,但是,接下来,还是不能进行通信的。。。。。

我们要建立外设和Android设备的连接才行,也就是打开设备的连接,不然怎么通信呢?代码如下:

  1. // 打开设备
  2. public void openDevice(UsbInterface mInterface) {
  3. if (mInterface != null) {
  4. UsbDeviceConnection conn = null;
  5. // 在open前判断是否有连接权限;对于连接权限可以静态分配,也可以动态分配权限
  6. if (myUsbManager.hasPermission(myUsbDevice)) {
  7. conn = myUsbManager.openDevice(myUsbDevice);
  8. }
  9. if (conn == null) {
  10. return;
  11. }
  12. if (conn.claimInterface(mInterface, true)) {
  13. myDeviceConnection = conn;
  14. if (myDeviceConnection != null)// 到此你的android设备已经连上zigbee设备
  15. System.out.println("open设备成功!");
  16. final String mySerial = myDeviceConnection.getSerial();
  17. System.out.println("设备serial number:" + mySerial);
  18. } else {
  19. System.out.println("无法打开连接通道。");
  20. conn.close();
  21. }
  22. }
  23. }

打开连接后,我们会得到一个UsbDeviceConnection的实例,我们的通信都是建立在一个可用的USB的连接上。

终于可以通信了。。。。。。

下面讲一下USB传输在Android里面的几个函数。。。。。

通常有两种传输方式,一种叫控制传输,具体函数解释如下:

【转】Android Service创建USB HOST通信

这个传输函数有个特点,它是用于端点0的传输,具体,我也没用过,参考文档上说,0端点是用来配置用的,所以我也没有深究。

另外一个函数bulk传输,它用于usb大流量数据的一个传输,我使用的是这个。

【转】Android Service创建USB HOST通信

下面是我用这个函数实现读写USB的代码:

  1. // 发送数据
  2. private void sendMessageToPoint(byte[] buffer) {
  3. // bulkOut传输
  4. if (myDeviceConnection
  5. .bulkTransfer(epBulkOut, buffer, buffer.length, 0) < 0)
  6. System.out.println("bulkOut返回输出为  负数");
  7. else {
  8. System.out.println("Send Message Succese!");
  9. }
  10. }

当发送数据的时候,我们使用的是out端点。

  1. // 从设备接收数据bulkIn
  2. private byte[] receiveMessageFromPoint() {
  3. byte[] buffer = new byte[15];
  4. if (myDeviceConnection.bulkTransfer(epBulkIn, buffer, buffer.length,
  5. 2000) < 0)
  6. System.out.println("bulkIn返回输出为  负数");
  7. else {
  8. System.out.println("Receive Message Succese!"
  9. // + "数据返回"
  10. // + myDeviceConnection.bulkTransfer(epBulkIn, buffer,
  11. // buffer.length, 3000)
  12. );
  13. }
  14. return buffer;
  15. }

接收数据的时候,使用的IN端点。

上面打开设备的时候得到的UsbDeviceConnection的实例和端点分配分配的端点,将在这里被使用到。

OK!~~~

到这里,大部分的任务都完成了,剩下的工作就是写一些逻辑代码去调用bulk传输函数就可以了,这里我就不多说了。

另外,在Service是需要在manifest里面注册的,程序跑起来以后,Service是完全和程序的其他部分并行的,不影响程序的正常运行,也不会阻塞界面,实现了,后台与Zigbee的通信,这里主要讲的是usb host在Android里面的几个主要的点,关于Zigbee就没有多说了,无非就是一些看用户手册的活。

笔者了解有限,有不对的地方,请指出来,大家一起交流、探讨。。。THKS

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

【转】Android Service创建USB HOST通信的更多相关文章

  1. Android Service创建USB HOST通信

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

  2. Android USB Host 通信程序

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

  3. Android Service与Activity之间通信的几种方式

    在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务,所以在我们实际开发中,就会常常遇到Activity与Service之间的通信,我们一般在Activ ...

  4. Android Service与Activity之间通信

    主要分为: 通过Binder对象 通过broadcast(广播)的形式 Activity调用bindService (Intent service, ServiceConnection conn, i ...

  5. Android USB Host与HID通讯

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

  6. 翻译Android USB HOST API

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

  7. Android USB Host 与 Hid 设备通信bulkTransfer&lpar;&rpar;返回-1问题的原因

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

  8. android usb Host模式下与usb Hid 设备的通信

    做android 与USB HID设备的通信有段时间了,总结一下遇到的问题和解决方法: 1,第一次遇到的问题:android 版本低不支持usb hid, 被要求做相关项目的时候,就从mUsbMana ...

  9. 【转】Android实战技巧之四十九:Usb通信之USB Host

    零 USB背景知识 USB是一种数据通信方式,也是一种数据总线,而且是最复杂的总线之一. 硬件上,它是用插头连接.一边是公头(plug),一边是母头(receptacle).例如,PC上的插座就是母头 ...

随机推荐

  1. Treasure Exploration&lpar;二分最大匹配&plus;floyd&rpar;

    Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 7455   Accepted: 3 ...

  2. 浏览器被劫持到http&colon;&sol;&sol;hao&period;169x&period;cn&sol;&quest;v&equals;108的解决办法

    不管什么浏览器打开都是 http://hao.169x.cn/?v=108 ​1.下载wmi tool,(微软官网下载,我的下载地址是: http://120.52.73.52/download.mi ...

  3. CodeForces621E 快速矩阵幂优化dp

    有时些候在用快速矩阵幂优化dp的时候,它的矩阵乘法是不那么容易被具体为题目背景的意思的,大多数时候难以理解矩阵之间相乘的实际意义,正如有时候我们不知道现在在做手头这些事情的意义,但倘若是因一个目标而去 ...

  4. 广商博客冲刺第二天new

    队名:雷锋队 队员:叶子鹏 王佳宁 张奇聪 张振演 曾柏树 项目:广商博客(嵌入APP) 执笔人:王佳宁 第一天沖刺傳送門 第三天沖刺傳送門 今天主要是写需求分析,在经过组员的热烈地讨论,需求分析如下 ...

  5. RabbitMQ随笔

    不管是官方还是能搜到的文章,使用MQ的基本思路都是这样: static void Main(string[] args) { //通过工厂建立连接 using (IConnection connect ...

  6. &lbrack;knownledge&rsqb;&lbrack;latex&rsqb; LaTex入门

    序言 最近需要写一份文档, 时间也不是特别紧. 之前一直用markdown写文档. 始终想学一下LaTex, 毕竟是学术论文界的工具. 在提及LaTex的内容之前. 事必是一定要首先提及高德纳的. 他 ...

  7. 总结Linux 下Redis 操作常用命令(转)

    Redis的配置 Linux下安装 ]# wget http://download.redis.io/releases/redis-2.8.17.tar.gz ]# tar xzf redis-2.8 ...

  8. python的学习之路day2

    1.什么是常量: 常量在程序中是不变的量 但是在python中所有的变量都可以改 注意:为了防止区分错误,所以python中常量使用大写命名 例如: MYSQL_CONNECTION = '192.1 ...

  9. Python远程连接主机之paramiko模块

    Python的paramiko模块能够连接远程主机,并在该主机上执行命令,和该主机之间进行文件传输.paramiko支持用明文密码登录远程主机和秘钥登录.使用之前要安装一下这个模块哈,pip inst ...

  10. C&num;创建word,操作、读写

    要使用C#操作word,首先要添加引用: 1.添加引用->COM->Microsoft Word 11.0 Object Library 2.在.cs文件中添加 using Word;下面 ...