1.首先说明一下本文档的背景:
由于BLE蓝牙传输一个包最多只能18个字节,而实际通讯自己定的协议一般都会超过18个字节,而数据也一般会有非常多个包一起发送,这个时候很多包就会黏在一起,而其实最好最简单的处理方法就是,定义一个超大的buf,直接往buf里不断的往后黏,然后最后再将这个buf拿出来解析。但是呢,实际很多情况是需要实时处理蓝牙的数据,并将数据解析显示或者分析等,还有就是整个设备本身整个应用就是在传输中进行的,再者这个buf也是有限大小的,所以效率相当低下,且有一定局限性,遇到这种情况那就得边接收数据边解析处理数据,那么接下来就介绍对蓝牙黏包的处理。
2.蓝牙数据包的处理:
这个数据包处理主要是针对一款开锁器而设计的,所以里面设计了一个在线模式和离线模式的开锁,其他则与平时其他蓝牙应用的差不多。
流程图:
代码与解析:
uint8 incompleteFlag=0;//数据不完整标志
uint8 frontDataCount=0;//数据前半部分数量
uint8 backDataCount=18;//数据后半部分数量
uint8 totalDataCount=24;//实际协议数据包长度,这个根据自己定的协议而定
uint8_t tempString[24];//用的临时数组
uint8_t flashBuf[4800];//写入flash的数组
int flashBufLength=0;//flash数组的长度
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR6, newValue, &returnBytes);//接收到app端数据
if(returnBytes > 0)//确认有数据
{
if(incompleteFlag!=0)//数据不完整
{
memcpy(tempString+backDataCount,newValue,frontDataCount);//将之前不足的6个字节补上(第一次为例)
backDataCount=18-frontDataCount;//剩下12个字节
//数据处理
if(tempString[5]==0x01&&tempString[0]==0x02&&tempString[1]==0x81)
{
//离线模式 将数据存入flash,根据是否写入flash成功进行回应
if(flashBufLength==0)
{
memcpy(flashBuf,tempString,totalDataCount);
flashBufLength+=totalDataCount;
}
else
{
memcpy(flashBuf+flashBufLength,tempString,totalDataCount);
UART_WriteTransport(flashBuf, flashBufLength+totalDataCount);
flashBufLength+=totalDataCount;
//写入flash操作
}
//回应
myRespondData[0]=0X01;
myRespondData[1]=0X01;
qq_write(myRespondData, 2);
// 发送一个通知消息 SBP_UART_CHANGE_EVT, 以便把数据发送到空口
SimpleBLEPeripheral_enqueueMsg(SBP_UART_CHANGE_EVT, NULL);
}
else
{
//在线模式 将数据赋值给密码锁协议包直接下发,根据开锁是否成功进行回应
//回应
myRespondData[0]=0X00;
myRespondData[1]=0X01;
}
if(returnBytes>=18)//还有数据
{
memcpy(tempString,0,24);
memcpy(tempString,newValue+frontDataCount,backDataCount);//从新开始黏贴
frontDataCount=totalDataCount-backDataCount;
}
Else//没有数据了
{
memcpy(tempString,0,24);
incompleteFlag=0;
frontDataCount=0;
backDataCount=18;
}
}
else //完整
{
if(newValue[0]==0x02&&newValue[1]==0x81)//如果头不符合则判定为错误数据
{
memcpy(tempString,newValue,backDataCount);//将18个字节直接黏到临时数组里
frontDataCount=totalDataCount-backDataCount;//我的协议数组是24-18=6个字节还没有得到,要第二次接收才能得到(第一次为例)
}
}
if(frontDataCount!=0)//零个字节没得到,则是完整数据
incompleteFlag=1;
else
incompleteFlag=0;
}