android串口通信——电子扫描枪
我们这里开始介绍电子扫描枪(串口的),在开发中我们可能用到电子扫描枪这么一个玩意。比如,我们在做一个可以说扫描条码的app的时候,就会用到,这种情况一般都是运行在终端上,往往不是我们手机上,那么我们来看看扫描枪这个玩意吧。串口的调用我们是基于android-serialport-api的,如有疑问,请看 android串口通信——android-serialport-api

一、扫描枪基础

1.基础指令

下面介绍的只是其中一种,具体使用的是哪一种看具体的文档。

指令 说明
02820383 扫描指令
06 成功的标志(这个是一个坑,实际在用的时候,有可能只返回06,就不返回数据了,所以不能把它当做唯一成功的标志)
15 失败的标志
0d0a 结束标志,如果一个返回的数据中,是个字符串结尾,那么说明数据读取结束

2.基本操作说明

当我们需要扫描条码时候,发送 02820383 指令即可启动扫描枪扫描条码,然后我们根据上面的状态说明,来操作放回的数据。特此说明,串口的数据可能不是一次读完的,有时一个数据可能分好几次来读才读完,有时候一次就读完了,由此应该知道我们结束标志是多么的重要了。 所以我们在读完时,需要不数据先保存下来,等到读取完了了,再返回数据。

二、扫描工具类的实现

主要说明:
1.读取数据的线程我们必须只能使用一个线程,不然会造成数据读取不正确。
2.我们发送和读取到得数据都是十六进制。
3.读取到数据是ascii值,我们需要自己转换为对应的值。

package com.qiwenming.scandemo.utils;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.security.InvalidParameterException;import android.content.Context;import android.util.Log;import android.widget.Toast;import android_serialport_api.SerialPort;import android_serialport_api.SerialPortFinder;import com.qiwenming.scandemo.MainActivity;import com.qiwenming.scandemo.bean.SerialPortSendData;/** * @author qiwenming * @date 2015-11-2 下午2:00:12  * @ClassName ScanUtils  * @Package com.qiwenming.scandemo.utils  * @Description: 串口工作类 */public class ScanUtils {    protected static OutputStream mOutputStream=null;    private static InputStream mInputStream = null;    private ReadThread mReadThread;    public SerialPortFinder mSerialPortFinder = new SerialPortFinder();    private SerialPort mSerialPort;    private Context context;    public static ReadThread thread = null;    /**     * @author qiwenming     * @creation 2015-6-18 下午4:38:54     * @instruction 读取类     */    private class ReadThread extends Thread {        private ScanReciverListener listener;        private SerialPortSendData sendData;        public ReadThread() {        }        public void setDataListener(SerialPortSendData sendData, ScanReciverListener listener) {            this.listener = listener;            this.sendData = sendData;        }        @Override        public void run() {            thread = this;            StringBuffer sb = new StringBuffer();            super.run();            while (!isInterrupted()) {                int size;                try {                    byte[] buffer = new byte[64];                    if (mInputStream == null)                        return;                    size = mInputStream.read(buffer);                    if (size > 0) { // 读取数据 数据c                        //str 就是我们读取到数据                        String str = StringUtils.bytesToHexString(buffer, size).trim().toLowerCase();                        sb.append(str);                        String msg = sb.toString();                        //如果我们存储的数据,也就是读取到得数据包含了 结束的标志,那么进入这个if                        if (msg.contains(sendData.stopStr)) {                            //把成功的标志替换为 ""                            msg = msg.replaceFirst("("+sendData.okStr+")+", "");                            //查找到结束位标志的位置  然后窃取我们的数据(不包含结束位)                            int end1 = msg.indexOf(sendData.stopStr);                            if (end1 > 0) msg = msg.substring(0, end1 + 1);                            //查找到结束位标志的位置  然后窃取我们的数据(不包含结束位)有的时候我们可能出现两种结束位                            int end2 = msg.indexOf(sendData.stopStr1);                            if (end2 > 0) msg = msg.substring(0, end2 + 1);                            final String data = msg;                            Log.i("onDataReceived_stop", data);                            Log.i("onDataReceived_stop_ascii",StringUtils.convertHexToString(data)+"--------"+Thread.currentThread().getId());                            closeDevice();                            if (null == context)                                return;                            ((MainActivity) context)                                    .runOnUiThread(new Runnable() {                                        @Override                                        public void run() {                                            thread = null;                                            listener.onReceived(data);                                        }                                    });                        }                        //包含了 失败的字符标志                        if (sb.toString().matches("\\w+" + sendData.failStr + "\\w+")) {                            closeDevice();                            if (null == context)                                return;                            ((MainActivity) context)                                    .runOnUiThread(new Runnable() {                                        @Override                                        public void run() {                                            thread = null;                                            listener.onFail(sendData.failStr);                                        }                                    });                        }                    }                } catch (Exception e) {                    listener.onErr(e);                    return;                }            }        }    }    /**     * 发送数据     *      * @param context     * @param devStr     *            地址     * @param baudRate     *            波特率     * @param msg     *            发送的消息     */    public void toSend(Context context, SerialPortSendData sendData,            ScanReciverListener listener) {        this.context = context;        //检查设备地址        if ("".equals(sendData.path) || "/dev/tty".equals(sendData.path)) {            Toast.makeText(context, "设备地址不能为空", 0).show();            return;        }        //检查指令        if ("".equals(sendData.commandStr)) {            Toast.makeText(context, "指令不能为空", 0).show();            return;        }        //获取输入输出流        try {            mSerialPort = getSerialPort(sendData.path, sendData.baudRate);            mOutputStream = mSerialPort.getOutputStream();            mInputStream = mSerialPort.getInputStream();            //使用一个线程来读取数据            if(thread==null){                thread = new ReadThread();                thread.setDataListener(sendData, listener);                thread.start();            }            else{                thread.setDataListener(sendData, listener);            }        } catch (SecurityException e) {        } catch (IOException e) {        } catch (InvalidParameterException e) {        }        // 上面是获取设置而已 下面这个才是发送指令        byte[] text = StringUtils.hexStringToBytes(sendData.commandStr);        try {            mOutputStream.write(text);            mOutputStream.flush();        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 获取到串口通信的一个实例     *      * @param path     * @param baudrate     * @return     * @throws SecurityException     * @throws IOException     * @throws InvalidParameterException     */    public SerialPort getSerialPort(String path, int baudrate)            throws SecurityException, IOException, InvalidParameterException {        /* Check parameters */        if ((path.length() == 0) || (baudrate == -1)) {            throw new InvalidParameterException();        }        /* Open the serial port */        mSerialPort = new SerialPort(new File(path), baudrate, 0);// 打开这个串口        return mSerialPort;    }    /**     * 关闭设备     */    public void closeDevice() {        if (mReadThread != null)            mReadThread.interrupt();        closeSerialPort();        // mSerialPort = null;    }    /**     * 关闭串口     */    public void closeSerialPort() {// 关闭窗口        if (mSerialPort != null) {            mSerialPort.close();            mSerialPort = null;        }        try {            if(mInputStream!=null){                mInputStream.close();                mInputStream = null;            }            if(mOutputStream !=null){                mOutputStream.close();                mOutputStream.close();            }        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * @author qiwenming     * @creation 2015-7-20 上午10:16:54     * @instruction 接受回调类     */    public interface ScanReciverListener {        /**         * 接受以后的处理方法         *          * @param string         */        public abstract void onReceived(String receviceStr);        /**         * 出错         *          * @param string         */        public abstract void onFail(String fialStr);        /**         * 出现异常         *          * @param e         */        public abstract void onErr(Exception e);    }    /**     * @author qiwenming     * @creation 2015-7-20 下午2:34:28     * @instruction 这个是我们用于存储读取的数据     */    public class RecevedData {        public ReturnType returnType;        /**         * 数据         */        public String receviedData;    }    /**     * @author qiwenming     * @creation 2015-7-20 下午2:36:21     * @instruction 使用辨识返回的数据的     */    public enum ReturnType {        ERR, // 错误        OK, // OK        Exception    }}

三、发送数据和接受数据的处理

package com.qiwenming.scandemo;import java.util.Arrays;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.TextView;import android.widget.Toast;import android_serialport_api.SerialPortFinder;import com.qiwenming.scandemo.bean.SerialPortSendData;import com.qiwenming.scandemo.constant.CommandConstants;import com.qiwenming.scandemo.dialog.OneColumDialog;import com.qiwenming.scandemo.dialog.OneColumDialog.SelectListener;import com.qiwenming.scandemo.utils.ScanUtils;import com.qiwenming.scandemo.utils.ScanUtils.ScanReciverListener;import com.qiwenming.scandemo.utils.StringUtils;/** * @author qiwenming * @date 2015-11-2 下午1:38:37  * @ClassName MainActivity  * @Package com.qiwenming.scandemo  * @Description:   扫描 */public class MainActivity extends Activity {    /**     * 内容     */    private TextView contentTv;    /**     * 硬件地址     */    private String address = "";   /**    * 波特率    */    private int baudRate = 0;    private SerialPortFinder serailFinder;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        contentTv = (TextView)findViewById(R.id.tv_content);        serailFinder = new SerialPortFinder();    }    /**     * 扫描     * @param view     */    public void toScan(View view){        //1.判断有没有硬件地址        //2.判断有木有波特率        //3.组装指令        //4.发送指令        //5.数据处理        //1.判断有没有硬件地址        if("".equals(address)){            setDeviceAddress();            return;        }        //2.判断有木有波特率        if(baudRate==0){            setDeviceBautRate();            return;        }        //3.组装指令        //4.发送指令        SerialPortSendData sendData = new SerialPortSendData(address, baudRate, CommandConstants.SCAN_START,                CommandConstants.SCAN_RSP_OK, CommandConstants.SCAN_RSP_FAIL,                CommandConstants.SCAN_STOP, true);        ScanUtils scanDevice = new ScanUtils();        scanDevice.toSend(this, sendData, new ScanReciverListener() {            //5.数据处理            @Override            public void onReceived(String receviceStr) {                String scanNo = StringUtils.convertHexToString(receviceStr);                contentTv.setText(scanNo);                Log.i("toScan_recevied", scanNo);            }            @Override            public void onFail(String string) {                Toast.makeText(MainActivity.this, "扫描失败,请重新扫描", 0).show();            }            @Override            public void onErr(Exception e) {                Toast.makeText(MainActivity.this, "扫描失败,请重新扫描", 0).show();            }        });    }    /**     * 显示地址     * @param v     */    public void setDeviceAddress(){        OneColumDialog dialog = new OneColumDialog(this, getAllDevicesPath(),new SelectListener() {            @Override            public void selected(int position, String value) {                address = value;                toScan(null);            }        });        dialog.show();        dialog.setTile("设置硬件地址");    }    /**     * 获取全部窗口地址     *      * @return     */    public List getAllDevicesPath() {        return Arrays.asList(serailFinder.getAllDevicesPath());    }    /**     * 设置波特率     */    public void setDeviceBautRate(){        OneColumDialog dialog = new OneColumDialog(this, getAllBautRate(),new SelectListener() {            @Override            public void selected(int position, String value) {                baudRate = Integer.parseInt(value);                toScan(null);            }        });        dialog.show();        dialog.setTile("设置波特率");    }    /**     * 获取全部 波特率     *      * @return     */    public List getAllBautRate() {        return Arrays.asList(getResources().getStringArray(R.array.baudrates));    }}

更多相关文章

  1. Android 判断用户2G/3G/4G移动数据网络
  2. Android Studio中使用adb shell查看数据库
  3. 共享全局数据 android
  4. Android 数据Parcel序列化过程源码分析
  5. Android中Activity之间的数据传递和Intent使用
  6. 【Android 开发】: Android客户端与服务端之间使用GSON交互数据

随机推荐

  1. Android(安卓)读取元素的数据
  2. Android(安卓)debug时一直处于waiting fo
  3. 传说是藏地密码中的海蓝兽
  4. Android(安卓)Paint类方法说明
  5. 【Android】第5章(4) 单选和复选
  6. android源代码下载及编译开发
  7. 关于android获得图片的总结
  8. 关于Android加载图片时的OOM的一些解决方
  9. buildinfo.sh简要分析
  10. Java、Android中Math详解