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 _buffer = []; /// 清空缓冲区 void clear() { _buffer.clear(); } /// 获取缓冲区长度 int get bufferLength => _buffer.length; /// 打包命令为字节帧(用于发送) /// CRC16 覆盖 command + payload 确保整帧完整性 static Uint8List pack(int command, List 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 data) { _buffer.addAll(data); } /// 从缓冲区解析所有完整的数据包 /// 未完成的帧保留在缓冲区等待后续数据 List parse() { final List 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 appendAndParse(List data) { append(data); return parse(); } /// CRC16-Modbus: polynomial=0x8005, init=0xFFFF, refIn/refOut=true static int _crc16(List 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; } }