Files
flutterApp/lib/core/bluetooth/protocol_parser.dart
2026-08-07 08:49:29 +08:00

123 lines
3.0 KiB
Dart

import 'dart:typed_data';
class BlePacket {
final int command;
final Uint8List payload;
const BlePacket({required this.command, required this.payload});
}
/// 有状态的 BLE 协议解析器
/// 支持分片接收:多次调用 [append] 累积数据,[parse] 提取完整帧
class ProtocolParser {
static const int _header1 = 0xAB;
static const int _header2 = 0xAA;
static const int _tail1 = 0xAA;
static const int _tail2 = 0xAB;
final List<int> _buffer = [];
/// 清空缓冲区
void clear() {
_buffer.clear();
}
/// 获取缓冲区长度
int get bufferLength => _buffer.length;
/// 打包命令为字节帧(用于发送)
/// CRC16 覆盖 command + payload 确保整帧完整性
static Uint8List pack(int command, List<int> payload) {
final dataToCheck = [command, ...payload];
final crc = _crc16(dataToCheck);
final builder = BytesBuilder()
..addByte(_header1)
..addByte(_header2)
..addByte(command)
..add(payload)
..addByte(crc & 0xFF)
..addByte((crc >> 8) & 0xFF)
..addByte(_tail1)
..addByte(_tail2);
return builder.takeBytes();
}
/// 追加新接收的数据到缓冲区
void append(List<int> data) {
_buffer.addAll(data);
}
/// 从缓冲区解析所有完整的数据包
/// 未完成的帧保留在缓冲区等待后续数据
List<BlePacket> parse() {
final List<BlePacket> packets = [];
while (_buffer.length >= 6) {
// 1. 查找帧头
int headIdx = -1;
for (int i = 0; i < _buffer.length - 1; i++) {
if (_buffer[i] == _header1 && _buffer[i + 1] == _header2) {
headIdx = i;
break;
}
}
if (headIdx == -1) {
// 无有效帧头,清空缓冲区
_buffer.clear();
break;
}
// 移除帧头前的垃圾数据
if (headIdx > 0) _buffer.removeRange(0, headIdx);
// 2. 查找帧尾
int tailIdx = -1;
for (int i = 2; i < _buffer.length - 1; i++) {
if (_buffer[i] == _tail1 && _buffer[i + 1] == _tail2) {
tailIdx = i;
break;
}
}
if (tailIdx == -1) {
// 帧尾未找到,可能是分片数据,等待更多数据
break;
}
// 3. 提取数据包
if (_buffer.length >= 5) {
final cmd = _buffer[2];
final payload = Uint8List.fromList(_buffer.sublist(3, tailIdx));
packets.add(BlePacket(command: cmd, payload: payload));
}
// 4. 移除已处理的帧
_buffer.removeRange(0, tailIdx + 2);
}
return packets;
}
/// 便捷方法:追加数据并立即解析
List<BlePacket> appendAndParse(List<int> data) {
append(data);
return parse();
}
/// CRC16-Modbus: polynomial=0x8005, init=0xFFFF, refIn/refOut=true
static int _crc16(List<int> data) {
int crc = 0xFFFF;
for (final b in data) {
crc ^= b;
for (int j = 0; j < 8; j++) {
if ((crc & 0x0001) != 0) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
}