Android硬件协议对接初识

往常做的都是普通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硬件协议对接初识)