0
点赞
收藏
分享

微信扫一扫

ANDROID OTG USB通信 读写 信息


 

github:​​https://github.com/mik3y/usb-serial-for-android​​

第一步:获取所有的已插入的串口驱动

1 UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
2 List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
3 if (availableDrivers.isEmpty()) {
4 return;
5 }

 

然后,我们选择第一个dirver ,连接设备

1 UsbSerialDriver driver = availableDrivers.get(0);
2 UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
3 if (connection == null) {
4 // You probably need to call UsbManager.requestPermission(driver.getDevice(), ..)
5 return;
6 }

 

接下来就可以读数据了

 

1 // Read some data! Most have just one port (port 0).
2 UsbSerialPort port = driver.getPorts().get(0);
3 try {
4 port.open(connection);
5 //设置串口的波特率、数据位,停止位,校验位
6 port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
7
8 byte buffer[] = new byte[16];
9 int numBytesRead = port.read(buffer, 1000);
10 Log.d(TAG, "Read " + numBytesRead + " bytes.");
11 } catch (IOException e) {
12 // Deal with error.
13 } finally {
14 port.close();
15 }

 

 

当然,我们可以给串口添加个监听

 

1  1 private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
2 2 private SerialInputOutputManager mSerialIoManager;
3 3
4 4 private final SerialInputOutputManager.Listener mListener =
5 5 new SerialInputOutputManager.Listener() {
6 6 @Override
7 7 public void onRunError(Exception e) {
8 8 Log.d(TAG, "Runner stopped.");
9 9 }
10 10
11 11 @Override
12 12 public void onNewData(final byte[] data) {
13 13 //TODO 新的数据
14 14 }
15 15 };
16 16
17 17 mSerialIoManager = new SerialInputOutputManager(sPort, mListener);//添加监听
18 //在新的线程中监听串口的数据变化
19 18 mExecutor.submit(mSerialIoManager);

 

如果需要接受比较大的数据,有可能会遇到一个问题:数据缓存和接收时间不够,导致数据被覆盖或者丢失,我们就需要修改串口读取缓存了

把 SerialInputOutputManager 中的 READ_WAIT_MILLIS 和 BUFSIZ 改成合适的大小就可以了

写数据的操作就是调用port的方法

port.write(bytes, 1000);

其实这个开源项目已经为我们封装了很多驱动类,都在driver包下,我们直接拿来用就可以了

 

零 USB背景知识

USB是一种数据通信方式,也是一种数据总线,而且是最复杂的总线之一。
硬件上,它是用插头连接。一边是公头(plug),一边是母头(receptacle)。例如,PC上的插座就是母头,USB设备使用公头与PC连接。
目前USB硬件接口分三种,普通PC上使用的叫Type;原来诺基亚功能机时代的接口为Mini USB;目前​​​Android​​手机使用的Micro USB。

Host
USB是由Host端控制整个总线的数据传输的。单个USB总线上,只能有一个Host。
OTG
On The Go,这是在USB2.0引入的一种mode,提出了一个新的概念叫主机协商协议(Host Negotiation Protocol),允许两个设备间商量谁去当Host。

 

一、Android中的USB

Android对Usb的支持是从3.1开始的,显然是加强Android平板的对外扩展能力。而对Usb使用更多的,是Android在工业中的使用。Android工业板子一般都会提供多个U口和多个串口,它们是连接外设的手段与桥梁。下面就来介绍一下Android Usb使用模式之一的USB Host。

android.hardware.usb包下提供了USB开发的相关类。
我们需要了解UsbManager、UsbDevice、UsbInterface、UsbEndpoint、UsbDeviceConnection、UsbRequest、UsbConstants。
1、UsbManager:获得Usb的状态,与连接的Usb设备通信。
2、UsbDevice:Usb设备的抽象,它包含一个或多个UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(endpoint)发送和接收数据。
3、UsbInterface:定义了设备的功能集,一个UsbDevice包含多个UsbInterface,每个Interface都是独立的。
4、UsbEndpoint:endpoint是interface的通信通道。
5、UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
6、UsbRequest:usb 请求包。可以在UsbDeviceConnection上同步异步传输数据。
7、UsbConstants:usb常量的定义,对应linux/usb/ch9.h

二、USB插入事件

Usb的插入和拔出是以​​系统​​广播的形式发送的,只要我们注册这个广播即可。

@Override​​
​​protected​​​ ​​void​​​ ​​onResume() {​​
​​super​​​​.onResume();​​
​​IntentFilter usbFilter = ​​​​new​​​ ​​IntentFilter();​​
​​usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);​​
​​usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);​​
​​registerReceiver(mUsbReceiver, usbFilter);​​
​​}​​

​​@Override​​
​​protected​​​ ​​void​​​ ​​onPause() {​​
​​super​​​​.onPause();​​
​​unregisterReceiver(mUsbReceiver);​​
​​}​​

​​private​​​ ​​final​​​ ​​BroadcastReceiver mUsbReceiver = ​​​​new​​​ ​​BroadcastReceiver() {​​
​​public​​​ ​​void​​​ ​​onReceive(Context context, Intent intent) {​​
​​String action = intent.getAction();​​
​​tvInfo.append(​​​​"BroadcastReceiver in\n"​​​​);​​

​​if​​​​(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {​​
​​tvInfo.append(​​​​"ACTION_USB_DEVICE_ATTACHED\n"​​​​);​​
​​} ​​​​else​​​ ​​if​​​​(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {​​
​​tvInfo.append(​​​​"ACTION_USB_DEVICE_DETACHED\n"​​​​);​​
​​}​​
​​}​​
​​};​​

三、Usb插入时启动程序

有些应用场景是,Usb插入后启动特定程序处理特定问题。
我们的做法就是在Manifest中某个Activity加入Usb插入的action。

<intent-filter>​​
​​<action android:name=​​​​"android.hardware.usb.action.USB_DEVICE_ATTACHED"​​​​>​​
​​</action></intent-filter>​​
​​<meta-data android:name=​​​​"android.hardware.usb.action.USB_DEVICE_ATTACHED"​​​ ​​android:resource=​​​​"@xml/usbfilter"​​​​></meta-data>​​

在usbfilter中加入厂商id和产品id的过滤,如下:

<resources>​​
​​<usb-device vendor-id=​​​​"1234"​​​ ​​product-id=​​​​"5678"​​​​>​​
​​</usb-device></resources>​​

结果就是,当此型号设备通过Usb连接到系统时,对应的Activity就会启动。

四、UsbManager的初始化

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

五、列出Usb设备

 

​​Iterator<usbdevice> iterator = deviceHashMap.values().iterator();​​
​​while​​​ ​​(iterator.hasNext()) {​​
​​UsbDevice device = iterator.next();​​
​​tvInfo.append(​​​​"\ndevice name: "​​​​+device.getDeviceName()+​​​​"\ndevice product name:"​​
​​+device.getProductName()+​​​​"\nvendor id:"​​​​+device.getVendorId()+​​
​​"\ndevice serial: "​​​​+device.getSerialNumber());​​
​​}</usbdevice></string,usbdevice>​​

六、USB使用权限

安卓系统对USB口的使用需要得到相应的权限,而这个权限要用户亲自给才行。
首先我们会确认一下上一节中的device是否已经获得权限,如果没有就要主动申请权限:

//先判断是否为自己的设备​​
​​//注意:支持十进制和十六进制​​
​​//比如:device.getProductId() == 0x04D2​​
​​if​​​​(device.getProductId() == ​​​​1234​​​ ​​&& device.getVendorId() == ​​​​5678​​​​) {​​
​​if​​​​(mUsbManager.hasPermission(device)) {​​
​​//do your work​​
​​} ​​​​else​​​ ​​{​​
​​mUsbManager.requestPermission(device,mPermissionIntent);​​
​​}​​
​​}​​

我们仍然使用广播来获得权限赋予情况。

1​​public​​​ ​​static​​​ ​​final​​​ ​​String ACTION_DEVICE_PERMISSION = ​​​​"com.linc.USB_PERMISSION"​​​​;​​

注册广播

mPermissionIntent = PendingIntent.getBroadcast(​​​​this​​​​,​​​​0​​​​,​​​​new​​​ ​​Intent(ACTION_DEVICE_PERMISSION),​​​​0​​​​);​​
​​IntentFilter permissionFilter = ​​​​new​​​ ​​IntentFilter(ACTION_DEVICE_PERMISSION);​​
​​registerReceiver(mUsbReceiver,permissionFilter);​​

接收器的代码:

private​​​ ​​final​​​ ​​BroadcastReceiver mUsbReceiver = ​​​​new​​​ ​​BroadcastReceiver() {​​
​​public​​​ ​​void​​​ ​​onReceive(Context context, Intent intent) {​​
​​String action = intent.getAction();​​
​​tvInfo.append(​​​​"BroadcastReceiver in\n"​​​​);​​
​​if​​​ ​​(ACTION_DEVICE_PERMISSION.equals(action)) {​​
​​synchronized​​​ ​​(​​​​this​​​​) {​​
​​UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);​​
​​if​​​ ​​(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, ​​​​false​​​​)) {​​
​​if​​​ ​​(device != ​​​​null​​​​) {​​
​​tvInfo.append(​​​​"usb EXTRA_PERMISSION_GRANTED"​​​​);​​
​​}​​
​​} ​​​​else​​​ ​​{​​
​​tvInfo.append(​​​​"usb EXTRA_PERMISSION_GRANTED null!!!"​​​​);​​
​​}​​
​​}​​
​​} ​​
​​}​​
​​};​​

七、通信

UsbDevice有了权限,下面就可以进行通信了。
这里要用到:UsbInterface、UsbEndpoint(一进一出两个endpoint,双向通信)、UsbDeviceConnection。
注意:通信的过程不能在UI线程中进行。
得到授权后,将做一些通信前的准备工作,如下:

​​?​​

private​​​ ​​void​​​ ​​initCommunication(UsbDevice device) {​​
​​tvInfo.append(​​​​"initCommunication in\n"​​​​);​​
​​if​​​​(​​​​1234​​​ ​​== device.getVendorId() && ​​​​5678​​​ ​​== device.getProductId()) {​​
​​tvInfo.append(​​​​"initCommunication in right device\n"​​​​);​​
​​int​​​ ​​interfaceCount = device.getInterfaceCount();​​
​​for​​​ ​​(​​​​int​​​ ​​interfaceIndex = ​​​​0​​​​; interfaceIndex < interfaceCount; interfaceIndex++) {​​
​​UsbInterface usbInterface = device.getInterface(interfaceIndex);​​
​​if​​​ ​​((UsbConstants.USB_CLASS_CDC_DATA != usbInterface.getInterfaceClass())​​
​​&& (UsbConstants.USB_CLASS_COMM != usbInterface.getInterfaceClass())) {​​
​​continue​​​​;​​
​​}​​

​​for​​​ ​​(​​​​int​​​ ​​i = ​​​​0​​​​; i < usbInterface.getEndpointCount(); i++) {​​
​​UsbEndpoint ep = usbInterface.getEndpoint(i);​​
​​if​​​ ​​(ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {​​
​​if​​​ ​​(ep.getDirection() == UsbConstants.USB_DIR_OUT) {​​
​​mUsbEndpointIn = ep;​​
​​} ​​​​else​​​ ​​{​​
​​mUsbEndpointOut = ep;​​
​​}​​
​​}​​
​​}​​

​​if​​​ ​​((​​​​null​​​ ​​== mUsbEndpointIn) || (​​​​null​​​ ​​== mUsbEndpointOut)) {​​
​​tvInfo.append(​​​​"endpoint is null\n"​​​​);​​
​​mUsbEndpointIn = ​​​​null​​​​;​​
​​mUsbEndpointOut = ​​​​null​​​​;​​
​​mUsbInterface = ​​​​null​​​​;​​
​​} ​​​​else​​​ ​​{​​
​​tvInfo.append(​​​​"\nendpoint out: "​​​ ​​+ mUsbEndpointOut + ​​​​",endpoint in: "​​​ ​​+​​
​​mUsbEndpointIn.getAddress()+​​​​"\n"​​​​);​​
​​mUsbInterface = usbInterface;​​
​​mUsbDeviceConnection = mUsbManager.openDevice(device);​​
​​break​​​​;​​
​​}​​
​​}​​
​​}​​
​​}​​

发送数据如下:

​​?​​

​​result = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, mData, (​​​​int​​​​)buffSize, ​​​​1500​​​​);​​​​//需要在另一个线程中进行​​

 

举报

相关推荐

0 条评论