android串口通信——电子扫描枪

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));
    }
}

你可能感兴趣的:(android串口通)