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();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335