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的插入和拔出是以系统广播的形式发送的,只要我们注册这个广播即可。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

@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。

1

2

3

4

<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的过滤,如下:

1

2

3

4

 

<resources>

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

</usb-device></resources>

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

四、UsbManager的初始化

1

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

五、列出Usb设备

 

1

2

3

4

5

6

7

8

   HashMap<string,usbdevice> deviceHashMap = mUsbManager.getDeviceList();

        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是否已经获得权限,如果没有就要主动申请权限:

1

2

3

4

5

6

7

8

9

10

11

            //先判断是否为自己的设备

            //注意:支持十进制和十六进制

            //比如:device.getProductId() == 0x04D2

            if(device.getProductId() == 1234 && device.getVendorId() == 5678) {

                if(mUsbManager.hasPermission(device)) {

                    //do your work

                } else {

                    mUsbManager.requestPermission(device,mPermissionIntent);

                }

            }

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

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

注册广播

1

2

3

   mPermissionIntent = PendingIntent.getBroadcast(this,0,new Intent(ACTION_DEVICE_PERMISSION),0);

        IntentFilter permissionFilter = new IntentFilter(ACTION_DEVICE_PERMISSION);

        registerReceiver(mUsbReceiver,permissionFilter);

接收器的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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线程中进行。
得到授权后,将做一些通信前的准备工作,如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

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;

                }

            }

        }

    }

发送数据如下:

?

1

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhangJiQun&MXP

等到80岁回首依旧年轻

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值