作用
将硬件发来的原始字节流(List<int>)解析成结构化的消息对象,并处理可能的分包(多个数据包拼成一条完整消息)。
分包机制解析
Dart
假设要发送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 时,说明接收完成
定义变量,根据需要和协议的协定,定义变量
Dart
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;
构造函数
Dart
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");
}
合并后续分片的方法
Dart
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方法
Dart
//判断是否已接收完所有分片
bool get isAll => size == offset;
//命令执行是否成功
bool get isSuccess {
if(_response ) {
if(payload.last != 0) {
return false;
}
}
return true;
}
代码示例
Dart
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项目,与充电宝项目无关
}