Android读写USB串口数据
zhoupuxian 人气:0最近在研究USB方面的内容;先后做了关于Android读写HID、串口设备的DEMO。本文比较简单,主要介绍的是Android实现读取串口数据的功能
废话不多说,先看一下业务层是如何调用的;如图:
首先,监听USB连接状况,当USB 进行请求USB权限,当USB权限申请成功,进行调用打开Usb设备的方法;当监听到USB断开,进行关闭连接;
这是向串口写入数据的方法;
本DEMO主要使用Handle进行数据各个线程之间的数据传到,以及USB连接读写情况的反馈;
下面直接上代码:
连接USB设备的代码
public void openCDC(UsbDevice usbDevice, UsbDeviceConnection usbDeviceConnection) { this.usbDeviceConnection = usbDeviceConnection; usbInterface = usbDevice.getInterface(findCDC(usbDevice)); //获取USB设备接口 if (usbDeviceConnection == null) //判断USB设备链路是否为空 { myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return; } if (!usbDeviceConnection.claimInterface(usbInterface,true)) //USB设备链路绑定获取到的接口 { myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return; } int numberEndpoints = usbInterface.getEndpointCount(); //获取USB设备接口的数据传输通道数量 for (int num = 0; num <= numberEndpoints-1; num++) { UsbEndpoint usbEndpoint = usbInterface.getEndpoint(num); switch (usbEndpoint.getType()) { //USB控制传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_CONTROL: controlUsbEndpoint = usbEndpoint; break; //USB块传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_BULK: switch (usbEndpoint.getDirection()) { case UsbConstants.USB_DIR_OUT: bulkOutUsbEndpoint = usbEndpoint; //USB块传输模式输出通道 break; case UsbConstants.USB_DIR_IN: bulkInUsbEndpoint = usbEndpoint; //USB块传输模式输入通道 break; } break; //USB中断传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_INT: switch (usbEndpoint.getDirection()) { case UsbConstants.USB_DIR_OUT: intOutUsbEndpoint = usbEndpoint; break; case UsbConstants.USB_DIR_IN: intInUsbEndpoint = usbEndpoint; break; } break; } } if (bulkOutUsbEndpoint != null && bulkInUsbEndpoint != null) //如果USB块传输模式输入输通道都不为空出 { //USB连接成功 connect = true; //获取到USB设备的ID、VID、PID String usbData = "Name:"+usbDevice.getDeviceName()+"\nID:"+usbDevice.getDeviceId()+" VID:"+usbDevice.getVendorId()+" PID:"+usbDevice.getProductId(); mes = new Message(); mes.obj = usbData; mes.what = MyHandler.USB_CONNECT_SUCCESS; myHandler.sendMessage(mes); threadReadData.start(); //开启接收数据线程 } else { //USB连接失败 connect = false; myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); } }
这个代码有点多,可能看的不太清楚,我删减一下,是这样的
public void openCDC(UsbDevice usbDevice, UsbDeviceConnection usbDeviceConnection) { this.usbDeviceConnection = usbDeviceConnection; usbInterface = usbDevice.getInterface(findCDC(usbDevice)); //获取USB设备接口 int numberEndpoints = usbInterface.getEndpointCount(); //获取USB设备接口的数据传输通道数量 for (int num = 0; num <= numberEndpoints-1; num++) { UsbEndpoint usbEndpoint = usbInterface.getEndpoint(num); switch (usbEndpoint.getType()) { //USB控制传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_CONTROL: controlUsbEndpoint = usbEndpoint; break; //USB块传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_BULK: switch (usbEndpoint.getDirection()) { case UsbConstants.USB_DIR_OUT: bulkOutUsbEndpoint = usbEndpoint; //USB块传输模式输出通道 break; case UsbConstants.USB_DIR_IN: bulkInUsbEndpoint = usbEndpoint; //USB块传输模式输入通道 break; } break; //USB中断传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_INT: switch (usbEndpoint.getDirection()) { case UsbConstants.USB_DIR_OUT: intOutUsbEndpoint = usbEndpoint; break; case UsbConstants.USB_DIR_IN: intInUsbEndpoint = usbEndpoint; break; } break; } } }
设备打开之后,就可以进行读写了;
Android 读取串口数据
public String readData() { byte[] tempByte = new byte[4096]; int i = usbDeviceConnection.bulkTransfer(bulkInUsbEndpoint,tempByte,tempByte.length,100);//读取数据,100为超时时间,接收的数据为数组类型 //将接收的数组转为字符串并返回 byte[] messageByte = new byte[i]; System.arraycopy(tempByte,0, messageByte,0, i); return new String(messageByte); }
这里主要通过调用谷歌提供的bulkTransfer方法进行的,传递的参数分别有endpoint,要读取的数据长度,和放要读取的数据的数组,超时时间
有了读,当然也需要写,向串口写入数据;代码如下:
public boolean send(String message) { byte[] messageBytes = message.getBytes(); //字符串转为数组 int result = usbDeviceConnection.bulkTransfer(bulkOutUsbEndpoint,messageBytes,messageBytes.length,100);//发送数据,发送转换为数组后的数据,超时时间为100毫秒 if ((result >= 0)) //发送数据返回值大于等于0代表发送成功 { //向信息处理中心发送“发送成功”的信息,并将信息内容传递过去 return true; } else { //发送失败 connect = false; return false; } }
传输数据的方式是用Handler;以下是Handler类的写法
public void handleMessage(@NonNull Message msg) { switch (msg.what) { case USB_CONNECT_SUCCESS: //USB设备连接成功 MyHandler.USB_CONNECT_STATE = true; //连接状态改变为true bt_send.setEnabled(true); //发送控件可以使用 bt_sendTiming.setEnabled(true); bt_send.setTextColor(Color.BLACK); //定时发送控件可以使用 bt_sendTiming.setTextColor(Color.BLACK); tv_usbDataShow.setText(msg.obj.toString()); //填充意图发送过来的信息 Toast.makeText(context,"连接成功",Toast.LENGTH_LONG).show(); break; case USB_CONNECT_FAILED: //USB设备连接失败 MyHandler.USB_CONNECT_STATE = false; bt_send.setEnabled(false); bt_sendTiming.setEnabled(false); bt_send.setTextColor(Color.GRAY); bt_sendTiming.setTextColor(Color.GRAY); bt_sendTiming.setText("定时发送"); tv_usbDataShow.setText("未连接设备"); mainActivity.closeAll(); //连接断开或连接失败,执行关闭所有连接和对象的方法 Toast.makeText(context,"断开连接",Toast.LENGTH_LONG).show(); break; case OUTPUT: //发送消息 if (messageShowNeedRoll(tv_sendMessageShow) != 0) tv_sendMessageShow.scrollTo(0, messageShowNeedRoll(tv_sendMessageShow));//如果TextView填充满可使用高度就滚动到最新更新处 tv_sendMessageShow.append("[TX]"+gteNowDate()+": "+msg.obj.toString()+"\n"); //给控件填充意图发送来的信息 break; case INPUT: //接收消息 if (messageShowNeedRoll(tv_receiveMessageShow) != 0) tv_receiveMessageShow.scrollTo(0, messageShowNeedRoll(tv_receiveMessageShow)); tv_receiveMessageShow.append("[RX]"+gteNowDate()+": "+msg.obj.toString()+"\n"); break; } }
主要代码已展示完毕,接下来展示具体代码
先看USB类,如下:
public class UsbCDC { private boolean connect; //USB连接状态 private UsbInterface usbInterface; //USB设备的物理接口 //控制传输模式通道 private UsbEndpoint controlUsbEndpoint; //块传输模式通道 private UsbEndpoint bulkInUsbEndpoint; private UsbEndpoint bulkOutUsbEndpoint; //中断传输模式通道 private UsbEndpoint intInUsbEndpoint; private UsbEndpoint intOutUsbEndpoint; private UsbDeviceConnection usbDeviceConnection; //USB设备连接链路,用来进行设备通讯 private Message mes; //信息包 private MyHandler myHandler;//信息处理中心对象 UsbCDC(MyHandler myHandler) { this.myHandler = myHandler; } /** * 向USB设备发送数据 * @param message 要发送的数据,字符串类型 * @return 数据发送结果,true代表发送成功 */ public boolean send(String message) { if (this.usbDeviceConnection == null) //判断USB链路是否获取到,不为空才能进行数据发送 { //如果USB链路为空,执行该作用域代码 connect = false; myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return false; } byte[] messageBytes = message.getBytes(); //字符串转为数组 int result = usbDeviceConnection.bulkTransfer(bulkOutUsbEndpoint,messageBytes,messageBytes.length,100);//发送数据,发送转换为数组后的数据,超时时间为100毫秒 if ((result >= 0)) //发送数据返回值大于等于0代表发送成功 { //向信息处理中心发送“发送成功”的信息,并将信息内容传递过去 mes = new Message(); mes.obj = new String(messageBytes); mes.what = MyHandler.OUTPUT; myHandler.sendMessage(mes); return true; } else { //发送失败 connect = false; myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return false; } } /** * 接收数据 * @return 接收的数据内容 */ public String readData() { byte[] tempByte = new byte[4096]; if (usbDeviceConnection == null) //判断USB连接链路是否为空,不为空才能进行数据接收 { connect = false; myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return null; } int i = usbDeviceConnection.bulkTransfer(bulkInUsbEndpoint,tempByte,tempByte.length,100);//读取数据,100为超时时间,接收的数据为数组类型 if (i < 0) //小于0代表接收失败或未接收到数据,接收结果也受USB设备的影响 { return null; } //将接收的数组转为字符串并返回 byte[] messageByte = new byte[i]; System.arraycopy(tempByte,0, messageByte,0, i); return new String(messageByte); } /** * 设置USB设备的波特率,方法内涉及算法等; * @param paramInt 要设置波特率的数值 * @return 设置结果,true代表设置成功 */ public boolean configUsb(int paramInt) { if (usbDeviceConnection != null) { byte[] arrayOfByte = new byte[8]; usbDeviceConnection.controlTransfer(192, 95, 0, 0, arrayOfByte, 8, 1000); usbDeviceConnection.controlTransfer(64, 161, 0, 0, null, 0, 1000); long l1 = 1532620800 / paramInt; for (int i = 3; ; i--) { if ((l1 <= 65520L) || (i <= 0)) { long l2 = 65536L - l1; int j = (short) (int) (0xFF00 & l2 | i); int k = (short) (int) (0xFF & l2); usbDeviceConnection.controlTransfer(64, 154, 4882, j, null, 0, 1000); usbDeviceConnection.controlTransfer(64, 154, 3884, k, null, 0, 1000); usbDeviceConnection.controlTransfer(192, 149, 9496, 0, arrayOfByte, 8, 1000); usbDeviceConnection.controlTransfer(64, 154, 1304, 80, null, 0, 1000); usbDeviceConnection.controlTransfer(64, 161, 20511, 55562, null, 0, 1000); usbDeviceConnection.controlTransfer(64, 154, 4882, j, null, 0, 1000); usbDeviceConnection.controlTransfer(64, 154, 3884, k, null, 0, 1000); usbDeviceConnection.controlTransfer(64, 164, 0, 0, null, 0, 1000); return true; } l1 >>= 3; } } else return false; } /** * 获取收发数据的通道 * @param usbDevice USB设备 * @param usbDeviceConnection USB连接链路 */ public void openCDC(UsbDevice usbDevice, UsbDeviceConnection usbDeviceConnection) { this.usbDeviceConnection = usbDeviceConnection; usbInterface = usbDevice.getInterface(findCDC(usbDevice)); //获取USB设备接口 if (usbDeviceConnection == null) //判断USB设备链路是否为空 { myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return; } if (!usbDeviceConnection.claimInterface(usbInterface,true)) //USB设备链路绑定获取到的接口 { myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); return; } int numberEndpoints = usbInterface.getEndpointCount(); //获取USB设备接口的数据传输通道数量 for (int num = 0; num <= numberEndpoints-1; num++) { UsbEndpoint usbEndpoint = usbInterface.getEndpoint(num); switch (usbEndpoint.getType()) { //USB控制传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_CONTROL: controlUsbEndpoint = usbEndpoint; break; //USB块传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_BULK: switch (usbEndpoint.getDirection()) { case UsbConstants.USB_DIR_OUT: bulkOutUsbEndpoint = usbEndpoint; //USB块传输模式输出通道 break; case UsbConstants.USB_DIR_IN: bulkInUsbEndpoint = usbEndpoint; //USB块传输模式输入通道 break; } break; //USB中断传输模式通道 case UsbConstants.USB_ENDPOINT_XFER_INT: switch (usbEndpoint.getDirection()) { case UsbConstants.USB_DIR_OUT: intOutUsbEndpoint = usbEndpoint; break; case UsbConstants.USB_DIR_IN: intInUsbEndpoint = usbEndpoint; break; } break; } } if (bulkOutUsbEndpoint != null && bulkInUsbEndpoint != null) //如果USB块传输模式输入输通道都不为空出 { //USB连接成功 connect = true; //获取到USB设备的ID、VID、PID String usbData = "Name:"+usbDevice.getDeviceName()+"\nID:"+usbDevice.getDeviceId()+" VID:"+usbDevice.getVendorId()+" PID:"+usbDevice.getProductId(); mes = new Message(); mes.obj = usbData; mes.what = MyHandler.USB_CONNECT_SUCCESS; myHandler.sendMessage(mes); threadReadData.start(); //开启接收数据线程 } else { //USB连接失败 connect = false; myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); } } /** * USB接收数据线程 */ private Thread threadReadData = new Thread(new Runnable() { String message = ""; @Override public void run() { while (connect) //USB处于连接状态就循环执行 { String temMes = readData(); //获取到接收到的字符串 if (temMes != null) { //如果接收到的数据不为空,就一直拼接,因为这些可能属于同一组数据(除非USB设备发送频率小于我们设置的超时时间100毫秒) message = message+temMes; continue; } else { //接收到的数据为空了,表示该组数据接收完整了,就可以发送给消息处理中心进行处理了 if (!message.equals("")) //接收到的数据要不为空,不然没意义 { mes = new Message(); mes.obj = message; mes.what = MyHandler.INPUT; myHandler.sendMessage(mes); message = ""; } } } } }); /** * 获取USB可以收发数据的接口号 * @param usbDevice USB设备 * @return USB可以收发数据的接口号 */ private int findCDC(UsbDevice usbDevice) { int interfaceCount = usbDevice.getInterfaceCount(); //获取USB设备接口数量 for (int count = 0; count < interfaceCount; ++count) { //遍历获取到的接口进行判断是否为收发数据的接口,是就返回该接口号 if (usbDevice.getInterface(count).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { return count; } } // 如果获取到的所有接口没有我们需要的就返回-1 return -1; } /** * 关闭USB连接、链路、数据通道等 */ public void close() { connect = false; //连接状态为false usbDeviceConnection.releaseInterface(usbInterface); //USB设备链路解绑接口 usbDeviceConnection.close(); //关闭USB设备链路 usbDeviceConnection = null; //USB设备链路赋值为空 bulkOutUsbEndpoint = null; //输出通道赋值为空 bulkInUsbEndpoint = null; //输入通道赋值为空 } }
接下来是连接USB类与业务层的中枢,HANDLER类:
package com.jlkj.lsk.usb_host; import android.content.Context; import android.graphics.Color; import android.os.Handler; import android.os.Message; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import java.text.SimpleDateFormat; import java.util.Date; public class MyHandler extends Handler { public static final int OUTPUT = 0; //发送消息 public static final int INPUT = 1; //接收消息 public static final int USB_CONNECT_SUCCESS = 2; //USB设备连接成功 public static final int USB_CONNECT_FAILED = 3; //USB设备连接失败或断开连接 public static boolean USB_CONNECT_STATE = false; //当前USB设备连接状态 private Button bt_send,bt_sendTiming; private TextView tv_sendMessageShow,tv_receiveMessageShow,tv_usbDataShow; private Context context; //上下文 private MainActivity mainActivity; MyHandler(TextView tv_sendMessageShow, TextView tv_receiveMessageShow, TextView tv_usbDataShow, Button bt_send, Button bt_sendTiming, Context context,MainActivity mainActivity) { this.bt_send = bt_send; this.tv_sendMessageShow = tv_sendMessageShow; this.tv_receiveMessageShow = tv_receiveMessageShow; this.tv_usbDataShow = tv_usbDataShow; this.bt_sendTiming = bt_sendTiming; this.context = context; this.mainActivity = mainActivity; } @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case USB_CONNECT_SUCCESS: //USB设备连接成功 MyHandler.USB_CONNECT_STATE = true; //连接状态改变为true bt_send.setEnabled(true); //发送控件可以使用 bt_sendTiming.setEnabled(true); bt_send.setTextColor(Color.BLACK); //定时发送控件可以使用 bt_sendTiming.setTextColor(Color.BLACK); tv_usbDataShow.setText(msg.obj.toString()); //填充意图发送过来的信息 Toast.makeText(context,"连接成功",Toast.LENGTH_LONG).show(); break; case USB_CONNECT_FAILED: //USB设备连接失败 MyHandler.USB_CONNECT_STATE = false; bt_send.setEnabled(false); bt_sendTiming.setEnabled(false); bt_send.setTextColor(Color.GRAY); bt_sendTiming.setTextColor(Color.GRAY); bt_sendTiming.setText("定时发送"); tv_usbDataShow.setText("未连接设备"); mainActivity.closeAll(); //连接断开或连接失败,执行关闭所有连接和对象的方法 Toast.makeText(context,"断开连接",Toast.LENGTH_LONG).show(); break; case OUTPUT: //发送消息 if (messageShowNeedRoll(tv_sendMessageShow) != 0) tv_sendMessageShow.scrollTo(0, messageShowNeedRoll(tv_sendMessageShow));//如果TextView填充满可使用高度就滚动到最新更新处 tv_sendMessageShow.append("[TX]"+gteNowDate()+": "+msg.obj.toString()+"\n"); //给控件填充意图发送来的信息 break; case INPUT: //接收消息 if (messageShowNeedRoll(tv_receiveMessageShow) != 0) tv_receiveMessageShow.scrollTo(0, messageShowNeedRoll(tv_receiveMessageShow)); tv_receiveMessageShow.append("[RX]"+gteNowDate()+": "+msg.obj.toString()+"\n"); break; } } /** * 返回格式化后的当前时间 * @return 当前时间字符串形式 */ private String gteNowDate() { SimpleDateFormat sdf = new SimpleDateFormat();// 格式化时间 sdf.applyPattern("HH:mm:ss");// 时:分:秒 Date date = new Date();// 获取当前时间戳 return sdf.format(date); //返回格式化后的时间戳 } /** * 判断当前TextView是否已经填充满控件可使用高度,如果高度已满就滚动需要的距离高度 * @param textView 需要判断的TextView控件 * @return 已满就返回对应高度,否则就返回0 */ private int messageShowNeedRoll(TextView textView) { int offset = textView.getLineCount() * textView.getLineHeight(); //添加的textview数量 x 字体高度 if (offset > textView.getHeight()) return offset - tv_receiveMessageShow.getHeight(); //如果乘积大于控件高度就返回需要滚动的距离 else return 0; //小于就返回0 } }
监听USB连接状况的广播类,如下:
package com.jlkj.lsk.usb_host; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.widget.TextView; import android.widget.Toast; import java.util.HashMap; public class UsbMonitor extends BroadcastReceiver //继承USB广播对象 { private static final String ACTION_USB_PERMISSION = "com.spark.teaching.answertool.USB_PERMISSION"; //USB设备的操作权限,可自定义 //private static final String ACTION_USB_PERMISSION = "android.USB"; //USB设备的操作权限,可自定义 private int VID = 1155; //USB设备生产厂商ID,用来区分选择目标USB设备,如果不是该ID的USB设备,不对其进行操作 private int PID = 1155; //USB设备生产厂商ID,用来区分选择目标USB设备,如果不是该ID的USB设备,不对其进行操作 private UsbController usbController; //USB动作管理接口 private UsbManager usbManager; //USB状态、管理对象 private UsbDevice usbDevice; //USB设备 private Context context; //上下文 private TextView tv_usbDeviceDataShow; //USB信息数据展示控件 /** * 数据初始化 * @param usbController usb控制器接口 * @param context 上下文 * @param tv_usbDeviceDataShow USB信息数据展示控件 */ UsbMonitor(UsbController usbController,Context context,TextView tv_usbDeviceDataShow) { this.usbController = usbController; this.context = context; this.tv_usbDeviceDataShow = tv_usbDeviceDataShow; } /** * 注册USB广播监听、USB权限 */ public void register() { if (this.context != null) { IntentFilter intentFilter = new IntentFilter(); //意图过滤器 intentFilter.addAction(ACTION_USB_PERMISSION); //添加USB设备的操作权限意图 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); //添加设备接入意图 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); //添加设备拔出意图 this.context.registerReceiver(this, intentFilter); //注册添加的意图 usbManager = (UsbManager)this.context.getSystemService(Context.USB_SERVICE); //获取USB设备管理 if (usbManager != null) { HashMap<String,UsbDevice> list = usbManager.getDeviceList(); //获取USB设备,返回的是 UsbDevice 的Hash列表,里面是所有当前连接主机的USB设备 for (UsbDevice usbDevice : list.values()) //遍历获取到的UsbDevice { if ((usbDevice.getVendorId() == VID)&&(usbDevice.getProductId() == PID)) //找到目标USB设备 { this.usbDevice = usbDevice; usbController.onDeviceInsert(this, usbManager,usbDevice); //执行USB接入时接口 break; } } tv_usbDeviceDataShow.setText("不支持该设备"); //如果列表里面没有目标USB设备,执行该操作 } tv_usbDeviceDataShow.setText("未连接设备"); //如果没有USB设备接入,执行该操作 } } /** * 请求打开此USB设备的权限 * @param usbDevice usb设备 */ public void requestOpenDevice(UsbDevice usbDevice) { if (usbManager != null) { if (usbManager.hasPermission(usbDevice))//如果有该USB设备的操作权限 { usbController.onDeviceOpen(this,usbManager,usbDevice);//连接USB设备(打开USB设备) } else { usbManager.requestPermission(usbDevice,PendingIntent.getBroadcast(context, 666, new Intent(ACTION_USB_PERMISSION), 0));//如果没有USB操作权限则请求权限 } } } /** * 注销USB广播监听 */ public void unregister() { if (context != null) { context.unregisterReceiver(this); //注销USB设备广播监听 context = null; usbManager = null; usbController = null; } } /** * 广播事务处理中心 * @param context 上下文 * @param intent 意图 */ @Override public void onReceive(Context context, Intent intent) { if (intent.getExtras() != null && !intent.getExtras().isEmpty()) { usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); //获取意图中的USB设备 switch(intent.getAction()) { case UsbManager.ACTION_USB_DEVICE_ATTACHED: //USB设备接入 Toast.makeText(context, "设备接入", Toast.LENGTH_LONG).show(); if ((usbDevice.getVendorId() == VID)&&(usbDevice.getProductId() == PID)) usbController.onDeviceInsert(this, usbManager,usbDevice); //找到目标USB设备,执行USB设备接入时接口 else tv_usbDeviceDataShow.setText("不支持该设备"); //未找到目标USB设备 break; case UsbManager.ACTION_USB_DEVICE_DETACHED: //USB设备拔出 Toast.makeText(context, "设备断开", Toast.LENGTH_LONG).show(); usbController.onDevicePullOut(this,usbManager,usbDevice); //执行USB设备拔出时接口 break; case UsbMonitor.ACTION_USB_PERMISSION: //请求USB设备操作权限 if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { //同意USB权限 usbController.onDeviceOpen(this,usbManager,usbDevice); //执行连接USB设备接口 } else { //拒绝USB权限 Toast.makeText(context, "拒绝USB权限!", Toast.LENGTH_LONG).show(); } break; } } else { Toast.makeText(this.context,"请检查USB设备!",Toast.LENGTH_LONG).show(); } } }
接口类 UsbController
public interface UsbController { /** * USB设备接入时的接口 * @param usbMonitor USB监听广播对象 * @param usbManager USB状态、管理对象 * @param usbDevice USB设备对象 */ void onDeviceInsert(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice); //USB设备拔出时的接口 void onDevicePullOut(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice); //连接USB设备(打开USB设备)的接口 void onDeviceOpen(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice); }
activity类
package com.jlkj.lsk.usb_host; import android.app.AlertDialog; import android.content.DialogInterface; import android.graphics.Color; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends AppCompatActivity implements UsbController { private Timer timer; //计时器对象 private TimerTask timerTask; //计时器任务对象 private UsbCDC usbCDC; //当前连接的USB设备对象 private MyHandler myHandler; //消息处理中心对象 private UsbMonitor usbMonitor; //USB监听广播对象 private TextView m_tv_sendMessageShow,m_tv_receiveMessageShow,m_tv_usbDataShow,m_tv_porterShow; private EditText m_et_messageText,m_et_time; private Button m_bt_send,m_bt_sendTiming,m_bt_clean,m_tv_porterSet; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); //实例化当前页面控件 initData(); //加载初始数据 m_bt_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //开启新线程进行数据发送 new Thread(new Runnable() { @Override public void run() { usbCDC.send(m_et_messageText.getText().toString()); //向当前连接的USB设备发送消息 } }).start(); } }); m_bt_clean.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { m_tv_sendMessageShow.setText(""); //清除发送的消息文本 m_tv_receiveMessageShow.setText(""); //清除接收的消息文本 m_tv_sendMessageShow.scrollTo(0, 0); //发送的消息文本回滚到最顶部 m_tv_receiveMessageShow.scrollTo(0, 0); //接收的消息文本回滚到最顶部 } }); m_bt_sendTiming.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //判断计时器是否为空,不为就代表正在执行计时任务,就停止当前任务 if (timer != null) { timer.cancel(); //停止计时器 timer = null; //计时器设为空 m_bt_sendTiming.setTextColor(Color.BLACK); //改变定时发送控件的颜色 m_bt_sendTiming.setText("定时发送"); //控件 恢复为“定时发送” } else { //如果为空,就开始定时发送任务 if (!m_et_time.getText().toString().equals("")) //获取定时任务的时间间隔 { timer = new Timer(); //创建定时器 timerTask = new TimerTask() //创建定时任务 { @Override public void run() { //定时任务要执行的内容 usbCDC.send(m_et_messageText.getText().toString()); } }; new Thread(new Runnable() //开启新线程执行 开启计时器 { @Override public void run() { //开启计时器 timer.schedule(timerTask,0,Integer.parseInt(m_et_time.getText().toString())); } }).start(); m_bt_sendTiming.setTextColor(Color.RED); m_bt_sendTiming.setText("停止"); //计时器开始后“定时发送”控件就改变颜色和字体 } else { //判断计时器是否为空,如果为空,就执行该作用域内容 Toast.makeText(MainActivity.this,"定时不能为空",Toast.LENGTH_LONG).show(); } } } }); m_tv_porterSet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //展示设置波特率的diaog对象 setPorter(); } }); } @Override public void onDeviceInsert(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice) { usbMonitor.requestOpenDevice(usbDevice); //请求USB连接权限 } @Override public void onDevicePullOut(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice) { closeAll(); //执行关闭所有连接的方法 myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); //向消息中心发送 断开连接 信息 } @Override public void onDeviceOpen(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice) { usbCDC = new UsbCDC(myHandler); //创建USB连接的对象 UsbDeviceConnection connection = usbManager.openDevice(usbDevice); //获取此USB链路 usbCDC.openCDC(usbDevice, connection); //连接USB设备(打开USB设备) } @Override protected void onDestroy() { super.onDestroy(); closeAll();//执行关闭所有连接的方法 myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);//向消息中心发送 断开连接 信息 } //关闭所有连接 public void closeAll() { if (usbCDC != null) { usbCDC.close(); usbCDC = null; } if (timer != null) { timer.cancel(); timer = null; } } //展示设置波特率dialog的对象,用一个AlertDialog让用户进行选择比特率 private void setPorter() { final String[] items = {"2400","4800","9600","19200","38400","57600","115200","230400","460800","1700000","2300000","3400000"}; AlertDialog.Builder listDialog = new AlertDialog.Builder(MainActivity.this); listDialog.setTitle("设置波特率"); listDialog.setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //判断当前USB设备是否连接,连接之后才可以设置波特率 if (usbCDC != null) { boolean porter = usbCDC.configUsb(Integer.parseInt(items[which])); //执行设置波特率的对象,返回true代表设置成功 m_tv_porterShow.setText(porter ? "波特率:"+items[which]:"波特率:9600"); //设置波特率对象返回true才改变控件字体,否则设置失败,不改变控件字体 } else { //判断当前USB设备是否连接,未连接则提示 设备未连接 Toast.makeText(MainActivity.this,"设备未连接",Toast.LENGTH_LONG).show(); } } }); listDialog.show(); //展示dialog } //加载数据 private void initData() { myHandler = new MyHandler(m_tv_sendMessageShow,m_tv_receiveMessageShow,m_tv_usbDataShow,m_bt_send,m_bt_sendTiming,this,MainActivity.this); //实例化消息处理中心 usbMonitor = new UsbMonitor(this,this,m_tv_usbDataShow); //实例化USB广播监听 usbMonitor.register(); //注册USB广播监听,注册之后,才可以正常监听USB设备 } //实例化控件 private void initView() { m_tv_receiveMessageShow = (TextView)findViewById(R.id.m_tv_receiveMessageShow); m_tv_receiveMessageShow.setMovementMethod(ScrollingMovementMethod.getInstance()); m_tv_sendMessageShow = (TextView)findViewById(R.id.m_tv_sendMessageShow); m_tv_sendMessageShow.setMovementMethod(ScrollingMovementMethod.getInstance()); m_tv_usbDataShow = (TextView)findViewById(R.id.m_tv_usbDataShow); m_et_messageText = (EditText)findViewById(R.id.m_et_messageText); m_et_time = (EditText)findViewById(R.id.m_et_time); m_bt_sendTiming = (Button)findViewById(R.id.m_bt_sendTiming); m_bt_clean = (Button)findViewById(R.id.m_bt_clean); m_bt_send = (Button)findViewById(R.id.m_bt_send); m_tv_porterShow = (TextView)findViewById(R.id.m_tv_porterShow); m_tv_porterSet = (Button)findViewById(R.id.m_bt_porterSet); } }
这个比较初级,接下来,我会再出一个精简版本;详细探讨Android读取USB串口、HID设备的实现;我把这两个集成在了一起,并打包成了arr文件,这个库可以自动识别USB 串口或USB hid ,当连接成功,就可以自动读写;代码比这个更为精简;接下来我会慢慢的记录下来。
加载全部内容