美文网首页AndroidIM、视频直播、蓝牙专题androidBLE开发
android Ble开发的那些事(三)--Ble数据分包处理

android Ble开发的那些事(三)--Ble数据分包处理

作者: Young_cyy | 来源:发表于2016-08-23 17:24 被阅读10433次

    android Ble开发的那些事(一)
    android Ble开发的那些事(二)
    android Ble开发的那些事(三)--Ble数据分包处理
    android Ble开发的那些事(四)—— OTA升级
    由于最近有点事,更的比较慢了。那就先把数据的相关处理先讲完吧。刚开始处理数据的时候,也想了很久,毕竟之前底子不太好,一时没反应过来,后来想通了问题都迎刃而解了。

    项目实际问题

    首先,讲讲我项目中遇到的实际问题吧。我们ble设备是开启notify之后,会自动发数据出来给手机的,这些数据的长度有长有短,代表着不同的含义(比如说电池电量、采集的数据。。。)。硬件的设计借鉴了微信那边相关的设计,由于ble传输的数据长度是有限制的,故将ble的数据发送设计成了类似于网络的发包过程,在发一条完整数据的时候,ble设备首先会把数据长度、类型等信息先放在数据头部,然后连同剩下的详细数据内容按照最大长度分割成一个个包依次广播发送出。

    app所需要做的就是把这些数据都接收下来然后分包解析就可以了。那如何分包呢?

    解决办法

    1、BluetoothBuffer工具类

    一开始呢,我想用ByteBuffer来实现的,但是用在项目中,感觉并不是特别的方便,后来就自己写了个类似的工具类(这个工具类的一些方法在系统api中肯定有替代的方法的,感觉自己写比较方便,所以没有使用系统api,大家也可以用系统相关的api代替的)。

    这个工具类主要有这么几个方法:
    (1)appendBuffer(byte[] buffer)追加buffer

    public  void appendBuffer(byte[] buffer) {
        if (null == buffer || 0 == buffer.length) return;
        int size = buffer.length + this._rawBufferSize;
        if (size <= this._rawBuffer.length) {
            System.arraycopy(buffer, 0, this._rawBuffer, this._rawBufferSize, buffer.length);
            this._rawBufferSize += buffer.length;
        } else {
            int newSize = this._rawBuffer.length;
            while (newSize <= size) {
                newSize *= 1.5;
            }
            byte[] newRawBuffer = new byte[newSize];
            System.arraycopy(this._rawBuffer, 0, newRawBuffer, 0, this._rawBufferSize);
            this._rawBuffer = newRawBuffer;
            System.arraycopy(buffer, 0, this._rawBuffer, this._rawBufferSize, buffer.length);
            this._rawBufferSize += buffer.length; 
       }
    }
    

    (2)getFrontBuffer(int size)取前size长度的buffer

    public  byte[] getFrontBuffer(int size) {
        if (0 >= size || size > this._rawBufferSize) return null;
        byte[] buffer = new byte[size];
        System.arraycopy(this._rawBuffer, 0, buffer, 0, size);
        return buffer;
    }
    

    (3)releaseFrontBuffer(int size)释放前size长度的buffer

    public  void releaseFrontBuffer(int size) {
        if (0 >= size || size > this._rawBufferSize) return;
        System.arraycopy(this._rawBuffer, size, this._rawBuffer, 0, this._rawBufferSize - size);
        this._rawBufferSize -= size;
    }
    

    2、接收数据并分包

    (1)接收数据
    数据的接收是在LiteBleGattCallback中的onCharacteristicChanged回调函数中接收的,所以分包处理也应该在这个回调函数中进行。

    private void  connect(final BluetoothDevice device){
        liteBluetooth.connect(device, false, new LiteBleGattCallback() {
            ......
            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                //开启notify之后,我们就可以在这里接收数据了。
                //分包处理数据
                btBuffer.appendBuffer(characteristic.getValue());
                while (true){
                    boolean ret = subPackageOnce(btBuffer);
                    if (false == ret) break;
                }
                super.onCharacteristicChanged(gatt, characteristic);
            }
        });
    }
    

    可以看到,首先接收到消息,我就先append上去,然后循环的调用subPackageOnce()分包这个函数,直到不能再分包返回false结束这个循环,这样效率也快很多哟。

    (2)数据分包
    数据分包,也就是把数据一条条剥离出来,想要分包,就得先知道数据的长度到底是多少,然后把长度为多少的数据剥离出来就可以了。所以第一步是先得到数据包头,然后得到包长pkgSize,然后根据pkgSize把数据剥离出来,不断循环。。。

    private boolean subPackageOnce(BluetoothBuffer buffer) {
            if (null == buffer) return false;
            if (buffer.getBufferSize() >= 14) {
                byte[] rawBuffer =  buffer.getBuffer();
                //求包长
                if (isHead(rawBuffer)){
                    pkgSize = byteToInt(rawBuffer[2], rawBuffer[3]);
                }else {
                    pkgSize = -1;
                    for (int i = 0; i < rawBuffer.length-1; ++i){
                        if (rawBuffer[i] == -2 && rawBuffer[i+1] == 1){
                            buffer.releaseFrontBuffer(i);
                            return true;
                        } 
                   }
                    return false;
                }
              //剥离数据
                if (pkgSize > 0 && pkgSize <= buffer.getBufferSize()) {
                    byte[] bufferData = buffer.getFrontBuffer(pkgSize);
                    long time = System.currentTimeMillis();
                    buffer.releaseFrontBuffer(pkgSize);
                    //在这处理数据
                    deal something。。。。。
                    return true;
                }
            }
            return false;
        }
    

    可以看到,在得到数据包长、成功剥离数据之后,就可以根据数据分类的标志位来采取不同数据处理方法。比如,对于采集的数据,我会上传这条数据以及时间戳给服务器;对于相关的配置信息,我会选择性的显示在app中。

    好啦,有关ble的数据分包处理就讲完了,是不是也挺简单的,这也只是我自己的处理方式,如果您有更好的想法或者有不对的地方欢迎指出,相互交流学习。下篇就开始讲Ble固件空中升级了~我争取快点更

    原创作品,如需转载,请与作者联系,否则将追究法律责任。

    相关文章

      网友评论

      • 五月海风:一个包没有数据校验?毕竟蓝牙不是TCP/UDP协议,数据有可能出现坏数据,我觉得先进行一个包一个包的数据校验,再按照网络通信分包处理方法处理。
      • ghjjjhghh:@Young_cyy 有点好奇 这个判断条件 if(rawBuffer[i] == -2 && rawBuffer[i+1] == 1) 是啥意思啊
      • Ayres:你好,能分享一下BluetoothBuffer工具类吗
      • Sherlock_582d:你好,看了很赞,请问能分享一下BluetoothBuffer工具类的源码吗?谢谢!!!906726463@qq.com
      • dff40a2e454b:btBuffer.appendBuffer(characteristic.getValue());
        请问这个btBuffer哪里来的?
      • e6d0429ebca4:哇厉害厉害,大神能分享下demo吗?1747783796@qq.com
      • 三金_25bb:大神你好,刚开始接触蓝牙项目,看了你的文章,感觉很棒!但是有点小疑惑,如果发送时出现丢包的情况,有一包没收到,那会不会出现我在解析这帧数据时,将下一帧数据的帧头包含了进来,然后一并释放掉了。
      • bae1dd9546b8:你好,感谢你的文章,对我帮助很大,请问你遇到过ble通知接收不到的情况吗?
      • 76a95c9c2d50:能分享下工具源码吗?多谢!438759715@qq.com
      • eaee24ca29cb:小妹妹你写的真好
      • dcef74161308:发送 分包怎么用啊,大神
        dcef74161308:完整的命令是超过20个字符的, 如果一开始先发20个字符,那么接受回掉直接就报错误命令了,怎么在接着发
        Young_cyy:@bin丶彬 发送的话 也可以用这个思路封装下啊,当时项目对发送没这个要求,所以就没考虑了。不过你发送的话,需要注意收到回调后再发送下一条,要保证同步发送,不然会阻塞
      • 鸩羽千夜92:LZ,你在做蓝牙开发的时候 ,有没有遇到过频繁的连接和断开与低功耗蓝牙设备的连接,会出现再次扫描设备的时候,扫描不到设备
      • 毒药_fbc7:你好,能把源码发一份给我吗?谢谢了,我的邮箱是346184758@qq.com
      • 风影_638f:楼主好厉害
      • 0ea6f257cf54:楼主很赞,能给个工具类源码么,android_dvp@sina.com 谢谢
      • b5a6b4a5ddc8:分包这边卡住了,能否帮我一下,我是将数据内容通过 Protobuff 序列化后得到字节,在分包传输。我想问下byteToInt这个方法是做什么处理,我将pkgSize 写死成5,讲过自己测试,可以将序列化后的字节还原成原来的数据。第一次接触ble和手机端的开发,望美女指教一下,拜托了
      • 过眼云烟梦:能给个Demo吗?1923077429@qq.com 最近也在弄蓝牙项目,接收的数据特别快,1秒200条,每条20字节,不懂怎么分包,直接用AudioTrack写入播放PCM音频,噪音特别大,声音很奇怪。
        杰哥哥爱撸码:是不是不分包的话会造成数据丢丢失?
      • 嘿你的益达886:接收发消息的分包代码能不能看一下啊 ,最近在写 一直没写好
      • bwzhny:很实际,很赞
        Young_cyy:@bwzhny 谢谢
      • d8a8f2653b1c:大神,什么时候有空,可以给链接个源码吗?
      • Maxoxo:贴近实际开发,写得很赞👍
        Young_cyy:@xlipeng 谢谢 :blush:
      • 天是一般蓝:你好 请教一下 :pray: 蓝牙数据传输时 APP退到后台 怎么办
        Young_cyy:@天是一般蓝 你可以用服务啊
      • 石器时代小古董:高质量的文章,感谢分享。 :smile: 另外,请问您BLE传输的最大传输单元是多少字节啊 :pray:
        Young_cyy:@疯狂橘子侠 :smile:没事没事
        石器时代小古董:@Young_cyy 感谢 :pray:
        Young_cyy:@疯狂橘子侠 你说的是一次吧?一次最大20字节。一波数据最多1024
      • 56a5e6abbe78:写的真好,什么时候有时间我也写写自己这边的蓝牙项目…还有打赏了哟~快点更新吧~
        Young_cyy:@xumingx 不用打赏的,真的 :joy: 喜欢给个爱心就好了~因为打赏我也拿不到 :stuck_out_tongue:
      • woitaylor:什么时候有空啊!
      • b2c2ec90f1ef:可不可以分享下demo 大神,谢谢
        6ac6b90b172f:@祉飒 你好,你有demo吗
        b2c2ec90f1ef:@Young_cyy 什么时候有空呢?可不可发我邮箱?765031457@qq.com 谢谢大神
        Young_cyy:@祉飒 好的 有空把demo放出来
      • 41cb4596c576:应该多分享这类的知识 当时做蓝牙的时候 满是费劲 资料太少 👍
        Young_cyy:@JamieFan 当时起初接手项目,好痛苦,资料博客太少

      本文标题:android Ble开发的那些事(三)--Ble数据分包处理

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