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; }
|