美文网首页
Android硬件协议对接初识

Android硬件协议对接初识

作者: 香烟和白粥 | 来源:发表于2019-05-17 18:08 被阅读0次

    往常做的都是普通APP,没有物联网这个概念,所以对二进制 ,十六进制的理解少之又少,看到这些数值也很懵逼。
    进制参考:https://www.cnblogs.com/wslook/p/9385415.html
    异或,与等算法参考:https://blog.csdn.net/xiaopihaierletian/article/details/78162863

    首先要向硬件开发者索要 波特率 串口地址 协议规则 是否有心跳 等 相关内容,每种协议的校验,包括每个位置的数据都代表不同的意思,一并都是16进制的数值进行通信。(我们的通信是已经封装好了,具体内容我也不清楚)
    这里我只说一些注意事项,以及校验等相关认知 (我也是模模糊糊的)

    1.遇到问题之一:

    将所有的串口地址都试了一遍,没有一个有回应的(其实心跳的话,很好试,只要打开基本上就会有心跳过来)
    解决方案: 将硬件丢给硬件开发者调试,应该是线路没接好或者其他的原因,反正我不知道,后来再给我的时候就可以了。

    2.遇到问题之二:

    发起命令有应答了,但是硬件调试发现硬件有应答,而接入到安卓设备,安卓设备收到应答的概率是30%。
    起初怀疑安卓设备有问题,返修。良久后还是不对,查看自己的代码 ,重点来了 : 因为我第一次对接协议,不知道他的命令是不可以多条同时发送的,一并发了七八条。
    然后我改了自己的代码,逐条发送,应答后再继续下一步。
    解决方案:将安卓设备的插口换了一个,就可以了,地址为“/dev/ttyS3” 之前用的是“/dev/ttyS2” ,其实两个接口效果应该是一样的,都是232 。当然不知道什么原因,反正这个就是可以了。

    3.协议说明

    其中一只协议的格式

    image.png
    1,帧头是固定的不变的
    2,地址是可变的,可能不同的地址代表不一样的功能
    3,数据长度代表的是 后面数据内容的长度(有些可能不一样,数据长度可能会代表命令码+数据内容的总长度) 。 例如:当数据长度 = (命令码+数据内容) 的长度 , 数据内容是 [0000], 命令码是 [A1] 那这个时候 , 命令长度就是03 。
    4,命令码,就是不同的命令代表不同的含义 ,一般协议里面会写清楚 ,什么操作用什么命令码,带什么命令数据
    5,数据内容,配合命令码带入数据,协议上一般都会写的。
    7,校验位 ,很多种方式,异或校验啊,cr16校验等。反正这里传的都是16进制的数据

    4,解析硬件应答过来的数据

    ReceiveCallbacksh.java 是已经封装过的类了,只知道这个方法就可以了
    onReceive(String devicePath, String baudrateString, byte[] received, int size)
    devicePath 代表串口地址,baudrateString 代表波特率 received 收到的字节数据,size收到数据的长度

    主要代码:

        @Override
        public void onReceive(String devicePath, String baudrateString, byte[] received, int size) {
    
            LogPlus.i("DataReceiver", "接收数据=" + ByteUtil.bytes2HexStr(received, 0, size));
    
            mByteBuffer.put(received, 0, size);
            mByteBuffer.flip();
            byte b;
            int readable;
            while ((readable = mByteBuffer.remaining()) >= Protocol.MIN_PACK_LEN) {
                mByteBuffer.mark(); // 标记一下开始的位置
                int frameStart = mByteBuffer.position();
                //校验帧头 开始==========
                b = mByteBuffer.get();
                if (b != Protocol.FRAME_HEAD_0) { // 第1个byte要3B
                    continue;
                }
    
                b = mByteBuffer.get();
                if (b != Protocol.FRAME_HEAD_1) { // 第2个byte要B3
                    continue;
                }
                //校验帧头 结束==========
    
                b = mByteBuffer.get();
                if (!(b == Protocol.ADDRESS_1||b == Protocol.ADDRESS_2||b == Protocol.ADDRESS_3
                       || b == Protocol.ADDRESS_4 || b == Protocol.ADDRESS_5)) { //校验地址
    
                    continue;
                }
                byte[] ba  = new byte[]{mByteBuffer.get()};
                // 数据长度
                final int cmdDataLen =(int) ByteUtil.hexStr2decimal(ByteUtil.bytes2HexStr(ba));
                // 总数据长度  = 不包含数据位的长度+刚动态获取的数据位长度,就是总长度 , 
              // 看第三步的通信数据格式 , Protocol.PACK_LEN = 5  , cmdDataLen = received[3] 的值转成10进制后的值)
                int total = Protocol.PACK_LEN + cmdDataLen;
                // 如果可读数据小于总数据长度,表示不够,还有数据没接收
                if (readable < total) {
                    // 重置一下要处理的位置,并跳出循环
                    mByteBuffer.reset();
                    break;
                }
    
                // 回到头
                mByteBuffer.reset();
                // 拿到整个包
                byte[] allPack = new byte[total];
                mByteBuffer.get(allPack);
    
                //生成异或字符串用于校验该应答数据是否有效
                String myHex = HexTool.getInstance().getXOR(ByteUtil.bytes2HexStr(allPack, 0, total-1));
                //获取串口应答过来的校验位内容
                String reciveHex = ByteUtil.bytes2HexStr(allPack, total-1, 1);
                // 校验通过
                if (myHex.equalsIgnoreCase(reciveHex)) {
                    final byte[] data = new byte[cmdDataLen];//命令数据内容
                    System.arraycopy(allPack, 5, data, 0, data.length);//应答所有的数据
                    byte command = allPack[4];//当前命令码
                    // 收到有效数据
                    onReceiveValidData(allPack, data, command);
                } else {
                    // 不一致则回到“第二位”,继续找到下一个3BB3
                    mByteBuffer.position(frameStart + 2);
                }
            }
    
            // 最后清掉之前处理过的不合适的数据
            mByteBuffer.compact();
        }
    

    5, 发送数据

    就是根据协议 按照他的顺序和规则去发送命令
    比如: "3B B3 00 01 A1 00 1F"
    前面两个字节代表帧头, 第三个代表地址 ,第四个代表 命令数据长度 ,因为命令数据为00 所以是一位 ,即 地址为"01" A1代表的是命令码 ,1F代表校验位。
    上面数据是虚拟的,具体要什么值可参考协议。

    全部代码

    public abstract class DataReceiver3BB3 implements ReceiveCallback {
    
        private final ByteBuffer mByteBuffer;
    
        public DataReceiver3BB3() {
            mByteBuffer = ByteBuffer.allocate(1024);
            mByteBuffer.clear();
        }
    
        /**
         * 解析数据成功
         * @param allPack 所有数据
         * @param data 命令数据内容
         * @param command 命令码
         */
        public abstract void onReceiveValidData(byte[] allPack, byte[] data, byte command);
    
        public void resetCache() {
            mByteBuffer.clear();
        }
    
    /**
       重点在这里
    */
           @Override
        public void onReceive(String devicePath, String baudrateString, byte[] received, int size) {
    
            LogPlus.i("DataReceiver", "接收数据=" + ByteUtil.bytes2HexStr(received, 0, size));
    
            mByteBuffer.put(received, 0, size);
            mByteBuffer.flip();
            byte b;
            int readable;
            while ((readable = mByteBuffer.remaining()) >= Protocol.MIN_PACK_LEN) {
                mByteBuffer.mark(); // 标记一下开始的位置
                int frameStart = mByteBuffer.position();
                //校验帧头 开始==========
                b = mByteBuffer.get();
                if (b != Protocol.FRAME_HEAD_0) { // 第1个byte要3B
                    continue;
                }
    
                b = mByteBuffer.get();
                if (b != Protocol.FRAME_HEAD_1) { // 第2个byte要B3
                    continue;
                }
                //校验帧头 结束==========
    
                b = mByteBuffer.get();
                if (!(b == Protocol.ADDRESS_1||b == Protocol.ADDRESS_2||b == Protocol.ADDRESS_3
                       || b == Protocol.ADDRESS_4 || b == Protocol.ADDRESS_5)) { //校验地址
    
                    continue;
                }
                byte[] ba  = new byte[]{mByteBuffer.get()};
                // 数据长度
                final int cmdDataLen =(int) ByteUtil.hexStr2decimal(ByteUtil.bytes2HexStr(ba));
                // 总数据长度  = 不包含数据位的长度+刚动态获取的数据位长度,就是总长度 , 
              // 看第三步的通信数据格式 , Protocol.PACK_LEN = 5  , cmdDataLen = received[3] 的值转成10进制后的值)
                int total = Protocol.PACK_LEN + cmdDataLen;
                // 如果可读数据小于总数据长度,表示不够,还有数据没接收
                if (readable < total) {
                    // 重置一下要处理的位置,并跳出循环
                    mByteBuffer.reset();
                    break;
                }
    
                // 回到头
                mByteBuffer.reset();
                // 拿到整个包
                byte[] allPack = new byte[total];
                mByteBuffer.get(allPack);
    
                //生成异或字符串用于校验该应答数据是否有效
                String myHex = HexTool.getInstance().getXOR(ByteUtil.bytes2HexStr(allPack, 0, total-1));
                //获取串口应答过来的校验位内容
                String reciveHex = ByteUtil.bytes2HexStr(allPack, total-1, 1);
                // 校验通过
                if (myHex.equalsIgnoreCase(reciveHex)) {
                    final byte[] data = new byte[cmdDataLen];//命令数据内容
                    System.arraycopy(allPack, 5, data, 0, data.length);//应答所有的数据
                    byte command = allPack[4];//当前命令码
                    // 收到有效数据
                    onReceiveValidData(allPack, data, command);
                } else {
                    // 不一致则回到“第二位”,继续找到下一个3BB3
                    mByteBuffer.position(frameStart + 2);
                }
            }
    
            // 最后清掉之前处理过的不合适的数据
            mByteBuffer.compact();
        }
    }
    

    相关文章

      网友评论

          本文标题:Android硬件协议对接初识

          本文链接:https://www.haomeiwen.com/subject/vuwoaqtx.html