主页(http://www.175shouji.com):android Ble开发的那些事(三)
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); //处理数据 if (pkgSize <= 267){ if (bufferData[13] == 0x0f){ //数据分类的标识位,这是采集的数据信息 byte[] data = new byte[pkgSize-12]; System.arraycopy(bufferData, 12, data, 0, pkgSize-12); dealBleData(time,data); //处理采集的数据信息,上传服务器等等。。。 }else { //这是配置的数据信息 dealCfglData(bufferData); //处理配置的数据信息,显示在app等等。。。 } }else { if (bufferData[14] == 0x0f){ byte[] data = new byte[pkgSize-13]; System.arraycopy(bufferData, 13, data, 0, pkgSize-13); Log.e("cyy ble data",DeviceBytes.byte2hex(data)); dealBleData(time,data); } } return true; } } return false; }可以看到,在得到数据包长、成功剥离数据之后,就可以根据数据分类的标志位来采取不同数据处理方法。比如,对于采集的数据,我会上传这条数据以及时间戳给服务器;对于相关的配置信息,我会选择性的显示在app中。
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
这个工具类主要有这么几个方法:
原创作品,如需转载,请与作者联系,否则将追究法律责任。
app所需要做的就是把这些数据都接收下来然后分包解析就可以了。那如何分包呢?
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结束这个循环,这样效率也快很多哟。
解决办法 1、BluetoothBuffer工具类一开始呢,我想用ByteBuffer来实现的,但是用在项目中,感觉并不是特别的方便,后来就自己写了个类似的工具类(这个工具类的一些方法在系统api中肯定有替代的方法的,感觉自己写比较方便,所以没有使用系统api,大家也可以用系统相关的api代替的)。
项目实际问题首先,讲讲我项目中遇到的实际问题吧。我们ble设备是开启notify之后,会自动发数据出来给手机的,这些数据的长度有长有短,代表着不同的含义(比如说电池电量、采集的数据。。。)。硬件的设计借鉴了微信那边相关的设计,由于ble传输的数据长度是有限制的,故将ble的数据发送设计成了类似于网络的发包过程,在发一条完整数据的时候,ble设备首先会把数据长度、类型等信息先放在数据头部,然后连同剩下的详细数据内容按照最大长度分割成一个个包依次广播发送出。
(1)appendBuffer(byte[] buffer)追加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
数据分包,也就是把数据一条条剥离出来,想要分包,就得先知道数据的长度到底是多少,然后把长度为多少的数据剥离出来就可以了。所以第一步是先得到数据包头,然后得到包长pkgSize,然后根据pkgSize把数据剥离出来,不断循环。。。(2)数据分包
好啦,有关ble的数据分包处理就讲完了,是不是也挺简单的,这也只是我自己的处理方式,如果您有更好的想法或者有不对的地方欢迎指出,相互交流学习。下篇就开始讲Ble固件空中升级了~我争取快点更