Charge-BleMessage
作用
将硬件发来的原始字节流(List<int>)解析成结构化的消息对象,并处理可能的分包(多个数据包拼成一条完整消息)。
分包机制解析
假设要发送100字节的数据,但蓝牙MTU限制每次只能传20字节 硬件会把数据分成5个包发送 第1包: size=5, offset=1, data=[前20字节] 第2包: size=5, offset=2, data=[第21-40字节] 第3包: size=5, offset=3, data=[第41-60字节] 第4包: size=5, offset=4, data=[第61-80字节] 第5包: size=5, offset=5, data=[第81-100字节] BleMessage 的工作: 1. 从第一包知道总共有5包 2. 接收每一包,把数据合并到 payload 3. 当 size == offset 时,说明接收完成定义变量,根据需要和协议的协定,定义变量
late int cmd; //命令类型 List<int> payload = []; //实际数据内容 late int len; //数据长度 bool _response = false; //判断是否为回复 bool success = true; //通信是否成功 late final List<int> raw; //原始数据 /// 总包数 int size = 0; /// 当前包 int offset = 0;构造函数
BleMessage.from(List<int> data) { //协议头 cmd = data[1] & 0xFF; //命令类型 _response = data[2] == 0x02; //判断是否为回复 size = (data[3] & 0xF0) >> 4; //前四位为总帧数 offset = data[3] & 0x0F; //后四位为帧序号 len = data[4] & 0xFF; //数据长度 //提取实际数据 payload.addAll( data.sublist(5)); //如果是回复包,检查最后一个字节 if(_response ) { success = data.last == 0; //协议协定 } raw = data; Log.d("size: $size length: $len"); }合并后续分片的方法
void contact(List<int> data) { raw.addAll(data); //保存原始数据 //空安全检查 if(size == 0 || data[1] != cmd || data[3] & 0x0F == 0) { Log.d("message contact error"); return; } Log.d("size: $size offset $offset"); offset = data[3] & 0x0F; //更新当前包序号 payload.addAll(data.sublist(5)); //合并数据 }提供给外部的get方法
//判断是否已接收完所有分片 bool get isAll => size == offset; //命令执行是否成功 bool get isSuccess { if(_response ) { if(payload.last != 0) { return false; } } return true; }代码示例
import '../log.dart'; import 'cmd_type.dart'; ///蓝牙接收类(处理分包) // enum ErrorCode{ //OTA项目,与充电宝项目无关 // success, // failed, // lengthError, // cmdError, // indexError, // notSupport, // switchError, // checkError, // packetLost, // } class BleMessage { //变量定义 late int cmd; //命令类型 List<int> payload = []; //实际数据内容 late int len; //数据长度 bool _response = false; //判断是否为回复 bool success = true; //通信是否成功 late final List<int> raw; //原始数据 /// 总包数 int size = 0; /// 当前包 int offset = 0; // bool get response { //耳机项目,与充电宝无关 // if(payload.isNotEmpty && // payload.length > 1 && // (payload[0] == DeviceInfoType.battery || // payload[0] == DeviceInfoType.firmware || // payload[0] == DeviceInfoType.port || // payload[0] == DeviceInfoType.capacity || // payload[0] == DeviceInfoType.model || // payload[0] == DeviceInfoType.temperature // payload[0] == DeviceInfoType.mtu || // payload[0] == DeviceInfoType.tws || // payload[0] == DeviceInfoType.twsState || // payload[0] == DeviceInfoType.eq || // payload[0] == DeviceInfoType.noiseLevel || // payload[0] == DeviceInfoType.noiseLevelCount || // payload[0] == DeviceInfoType.transparentLevel || // payload[0] == DeviceInfoType.transparentLevelCount || // payload[0] == DeviceInfoType.name || // payload[0] == DeviceInfoType.version || // payload[0] == DeviceInfoType.button || // payload[0] == DeviceInfoType.language || // payload[0] == DeviceInfoType.autoAnswer || // payload[0] == DeviceInfoType.led || // payload[0] == DeviceInfoType.mode || // payload[0] == DeviceInfoType.face // )) { // return false; // } // return _response; // } //构造函数 BleMessage.from(List<int> data) { //协议头 cmd = data[1] & 0xFF; //命令类型 _response = data[2] == 0x02; //判断是否为回复 size = (data[3] & 0xF0) >> 4; //前四位为总帧数 offset = data[3] & 0x0F; //后四位为帧序号 len = data[4] & 0xFF; //数据长度 //提取实际数据 payload.addAll( data.sublist(5)); //如果是回复包,检查最后一个字节 if(_response ) { success = data.last == 0; //协议协定 } raw = data; Log.d("size: $size length: $len"); } //合并后续分片数据 void contact(List<int> data) { raw.addAll(data); //保存原始数据 //空安全检查 if(size == 0 || data[1] != cmd || data[3] & 0x0F == 0) { Log.d("message contact error"); return; } Log.d("size: $size offset $offset"); offset = data[3] & 0x0F; //更新当前包序号 payload.addAll(data.sublist(5)); //合并数据 } //判断是否已接收完所有分片 bool get isAll => size == offset; //命令执行是否成功 bool get isSuccess { if(_response ) { if(payload.last != 0) { return false; } } return true; } // int get errorCode => payload.last; //OTA项目,与充电宝项目无关 }