USB扫码枪获取数据流的实现方式

您所在的位置:网站首页 扫二维码的扫码枪 USB扫码枪获取数据流的实现方式

USB扫码枪获取数据流的实现方式

2024-02-04 20:45| 来源: 网络整理| 查看: 265

硬件条件: OTG接口转换器(或者自带usb接口的设备(大头))USB扫码枪(支持USB虚拟串口)安卓设备 实现方式: 串口方式USB方式 使用场景:

在扫码枪连接机器的时候,当扫码枪扫描到内容时,获取扫描到的内容。

解决的问题:

之前扫码枪使用的是USB模式(即扫描到的内容会直接输入到EditText之中,并且末尾会增加一个回车键),但是后来发现,当二维码包含中文的时候,中文不会输出进来,于是乎,使用以上两种方式实现。

实现思路:

连接扫码枪,因为数据肯定是以字节流的方式发送的,那么我们只需获取到输入的字节流,自己处理成需要的内容就可以了。

实现方式------串口方式:

    需要经过以下几个步骤:

集成谷歌原生serial_port包,参考该文章集成就可以了: Android串口集成寻找设备串口地址(这个咱们仅仅是为了获取串口地址,因为串口地址是固定的,所以这里可以不加在程序中,咱们目的是为了知道USB扫码枪的串口地址)连接设备获取数据流

步骤一:集成谷歌原生serial_port包,这个自己看上面教程了。

步骤二:寻找设备串口地址,在完成步骤一之后,会有一个SerialPortFinder的类,这个类的作用是寻找咱们安卓设备上连接的串口设备(包括扫码枪),具体获取扫码枪串口地址的思路:获取未插入扫码枪时所有设备的串口地址------》获取插入扫码枪时所有设备的串口地址

-----》看看多出那个,多出的那个就是扫码枪的串口地址了,废话不多说,直接贴代码了:

case R.id.btn_print://获取所有串口设备地址,mFinder就是SerialPortFinder StringBuffer stringBuffer = new StringBuffer(); for (String str:mFinder.getAllDevicesPath()) { stringBuffer.append(str + "\n"); } mTvMessage.setText(stringBuffer.toString()); break;

怎么找USB扫码枪你懂我意思吧。

步骤三:连接设备:

废不多讲,首先咱们连接到串口设备,如果你连接不上,那么就是步骤一有问题,请到步骤一那篇博客问问作者:

private String mSerialPath = "/dev/ttyUSB0" ;//物理串口地址,这个就是咱们步骤二找到的地址了,这是我的设备的地址,你的自己找去 private int baudrate = 9600;//波特率,这个是可以扫码枪自己设置的,看说明书 private SerialPort mSerialPort; private InputStream mInputStream; @Override protected int getContentView() { return R.layout.activity_test; } @Override protected void initView() { super.initView(); initSerialPort(); } private void initSerialPort(){//连接串口设备,建议加try,硬件设备你永远不知道会为啥崩溃 try { mSerialPort = new SerialPort(new File(mSerialPath),baudrate); mInputStream = mSerialPort.getInputStream(); ReadThread thread = new ReadThread();//这是读取数据流的线程,代码在下方贴出 thread.start();//启动数据流读取线程 } catch (Exception e) { e.printStackTrace(); } }

步骤四:获取数据流,这时候步骤三,我们开启了一个线程读取扫码枪的数据流,这时候我写了一个死循环,轮询扫码枪发送的内容,线程代码如下

private InputStream mInputStream; /** * 读串口线程 */ private class ReadThread extends Thread {//这是我的内部类,我代码习惯不好,别瞎鸡儿抄 @Override public void run() { super.run(); while ((!Thread.currentThread().isInterrupted())) { final int size; try { if (mInputStream == null) return; final byte[] buffer = new byte[512]; size = mInputStream.read(buffer);//这就是扫描到的内容了 if (size > 0) { runOnUiThread(new Runnable() { @Override public void run() { try { ToastUtils.makeText(TestActivity.this,new String(buffer,"GB2312"));//此处我设置的编码是GB2312,这个可以看说明书,可以设置的 } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }); } Thread.sleep(300);//你自己可以设置睡眠时间,这个睡眠时间可以会影响识别速度,那么就可以叫用户加钱,你懂我意思吧。 } catch (Exception e) { //如果抛出异常则再次设置中断请求 Thread.currentThread().interrupt(); return; } } } }

嗯,到了这一步,大功告成了。

注意:串口方式实现的话兼容性不好,因为遇到部分安卓设备直接阉割了这部分功能,所以我才会研究USB方式的。

惊不惊喜,意不意外。

实现方式------USB方式:

该种方式好处在于不需要集成serial_port包,但是里面一些类理解比较灵性,USB方式需要经过以下几个步骤:

寻找需要连接的devices设备连接设备获取数据流

步骤一:寻找需要连接的devices设备,这里的话有两种场景

  1.USB扫码枪一直插在安卓设备上,我们需要在程序启动的时候自动找到并且连接

  2.USB扫码枪在热拔插的情况下,我们需要在插入的时候连接

第一种的话我是直接写了一个方法,在程序启动的时候检查时候插入需要支持的设备类型,如果有,那么直接连接,判断方法是通过设备的pid和vid对比进行判断,pid和vid获取方式自己百度,或者把扫码枪插在电脑上,在设备管理可以看到,我通过findDevices方法找到需要连接的扫码枪设备。

贴代码:

private UsbManager mManager; //查找已连接的设备 UsbDevice findDevices() { if (null == mManager) { return null; } HashMap mMap = mManager.getDeviceList(); for (UsbDevice device : mMap.values()) { if (BaseScanner.isS5920(device) || BaseScanner.isS5600(device)) {//判断设备是否支持的类型 return device; } } return null; }

这是baseScanner,这个类名我觉得不够准确,它是用来记录需要支持的设备的信息的,包含设备的判断方法:

public class BaseScanner{ private static final int scanner5600_pid = 4456; private static final int scanner5600_vid = 866; private static final int scanner5920_pid = 9527; private static final int scanner5920_vid = 549; public static boolean isS5600(UsbDevice usbDevice){//是不是s5600扫码枪 return usbDevice.getProductId() == scanner5600_pid && usbDevice.getVendorId() == scanner5600_vid; } public static boolean isS5920(UsbDevice usbDevice){//是不是s5920 return usbDevice.getProductId() == scanner5920_pid && usbDevice.getVendorId() == scanner5920_vid; } }

第二种USB扫码枪热拔插连接方式,这时候我们采用的是广播监听的方式,因为设备拨叉都会有广播发送,这条广播包含的信息包含一个USBDevices对象(也就是扫码枪),我们需要动态注册拔,插两条广播,静态注册不生效,代码如下:

//这是广播类,因为我的扫描是写在一个service中,所以把连接的设备交给service处理就可以 public class USBBroadcastReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { // call your method that cleans up and closes communication with the device Toast.makeText(context, "拔出", Toast.LENGTH_LONG).show(); } }else if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)){//设备插入 UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);//获取插入的设备 Intent intent1 = new Intent(context,ScannerService.class); Bundle bundle = new Bundle(); bundle.putParcelable("device",device); intent1.putExtra("data",bundle);//将设备包入intent中,交给service处理 context.startService(intent1); Toast.makeText(context, "插入", Toast.LENGTH_LONG).show(); } } }

我是在程序启动的时候就注册了这个广播如下:

public class MyApplication extends Application { private USBBroadcastReceiver mUsbReceiver; @Override public void onCreate() { super.onCreate(); registBroadCast(); } @Override public void onTerminate() { unregisterReceiver(mUsbReceiver); super.onTerminate(); } private void registBroadCast(){//注册USB插拔广播 mUsbReceiver = new USBBroadcastReceiver(); IntentFilter usbDeviceStateFilter = new IntentFilter(); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);//插入设备状态 usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);//拔出设备状态 registerReceiver(mUsbReceiver, usbDeviceStateFilter); } }

步骤二,连接设备,这边我把所有都写注释里面:

private UsbDevice mDevide; private UsbDeviceConnection mConnect; private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private static UsbConnectManager mInstance; private ScannerListener mListener; private UsbManager mManager; private UsbEndpoint mUsbEndpointIn; private UsbInterface mUsbInterface; private Thread mReadingthread; public void connetDevice(UsbDevice device, Context context) { disConnect();//断开之前的连接 mDevide = device;//当前需要连接的设备 try { if (!mManager.hasPermission(mDevide)) {//检查是否有扫码枪的访问权限,如果没有,那么请求一下临时权限 PendingIntent intent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); mManager.requestPermission(mDevide, intent); } mConnect = mManager.openDevice(mDevide);//打开设备 mUsbInterface = device.getInterface(0);//获取数据的接口.这个可以理解成设备有多少个线头子 mUsbEndpointIn = mUsbInterface.getEndpoint(0);//获取设备的输出流向,输入或者输出因为usb扫码枪只有一个输出项,所以直接选择0 if (mConnect.claimInterface(mUsbInterface, true)) {//获取设备数据写入流,如果获取成功,那么数据已经通常,我这边写的是一个获取数据,输入数据的话把getEndpoint(0)换成输入的接口即可 Log.i(TAG, "connetDevice: find device,start get data!!!"); startReading();//开启读取数据流的线程 } else { mConnect.close(); Log.i(TAG, "connetDevice: not find device !!!"); } } catch (Exception e) { e.printStackTrace(); } }

步骤三,获取输入的流,并解析成需要的内容,代码如下:

//开线程读取数据 private void startReading() { if (null != mReadingthread) { mReadingthread.interrupt(); } mReadingthread = new Thread(new Runnable() { @Override public void run() { while (!mReadingthread.isInterrupted()) { synchronized (this) { byte[] bytes = new byte[128]; int ret = mConnect.bulkTransfer(mUsbEndpointIn, bytes, bytes.length, 100);//获取数据流 if (ret > 0) { try { byte[] bs = new byte[ret]; System.arraycopy(bytes, 0, bs, 0, ret);//获取数据长度 String str = new String(bs,"GB2312");//转换成汉字 if (null != mListener){ mListener.onScanner(str);//你自己需要的处理方式 } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } } } }); mReadingthread.start(); }

OK啦,USB模式的也完成了。

有疑问或者有建议的膀友可以加群:497438697  我是群里的 杭州-大魔王,有艾特必应。

祝大家新年快乐,万事亨通!!!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3