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固件空中升級了~我爭取快點更
原創作品,如需轉載,請與作者聯系,否則將追究法律責任。