import 'dart:typed_data'; import 'package:starwork_flutter/base/app_logger.dart'; /// ✨✨✨ 数据包解析结果类 ✨✨✨ class ParsedPacket { final bool isValid; final int packetType; final int packetSequence; final int version; final int encryptType; final int encryptedDataLength; final int originalDataLength; final List data; final int crc16; final String? errorMessage; ParsedPacket({ required this.isValid, required this.packetType, required this.packetSequence, required this.version, required this.encryptType, required this.encryptedDataLength, required this.originalDataLength, required this.data, required this.crc16, this.errorMessage, }); @override String toString() { if (!isValid) { return 'ParsedPacket(invalid: $errorMessage)'; } return 'ParsedPacket(type: 0x${packetType.toRadixString(16).padLeft(2, '0')}, ' + 'seq: $packetSequence, version: ${version >> 4}, encrypt: $encryptType, ' + 'dataLen: $originalDataLength, crc: 0x${crc16.toRadixString(16).padLeft(4, '0')})'; } } /// ✨✨✨ 蓝牙命令基类 - 提供数据包组装功能 ✨✨✨ abstract class BaseBleCommand { /// 包头固定值: 0XEF01EE02 static const List PACKET_HEADER = [0xEF, 0x01, 0xEE, 0x02]; /// 包类型 static const int PACKET_TYPE_REQUEST = 0x01; // 请求包 static const int PACKET_TYPE_RESPONSE = 0x11; // 应答包 /// 包版本 (高4位) static const int PACKET_VERSION = 0x10; // 版本1.0 /// 加密类型 (低4位) static const int ENCRYPT_TYPE_PLAIN = 0x00; // 明文 static const int ENCRYPT_TYPE_AES128 = 0x01; // AES128 static const int ENCRYPT_TYPE_SM4_PRESET = 0x02; // SM4(事先约定密钥) static const int ENCRYPT_TYPE_SM4_DEVICE = 0x03; // SM4(设备指定密钥) /// 最大单包数据长度 (可根据MTU调整) static int MAX_PACKET_DATA_SIZE = 100; /// 全局包序号计数器 static int _globalPacketSequence = 1; /// ✨✨✨ 获取下一个包序号 ✨✨✨ static int getNextPacketSequence() { int sequence = _globalPacketSequence; _globalPacketSequence++; if (_globalPacketSequence > 0xFFFF) { _globalPacketSequence = 1; // 2字节范围内循环 } return sequence; } /// ✨✨✨ 组装包头 ✨✨✨ /// [packetType] 包类型 (0x01请求包, 0x11应答包) /// [packetSequence] 包序号 (2字节) /// [encryptType] 加密类型 (0:明文, 1:AES128, 2:SM4事先约定, 3:SM4设备指定) /// [dataLength] 数据长度 (高16位:加密后长度, 低16位:原始长度) static List buildPacketHeader({ required int packetType, required int packetSequence, int encryptType = ENCRYPT_TYPE_PLAIN, required int encryptedDataLength, required int originalDataLength, }) { List header = []; // 1. 包头 (4字节) header.addAll(PACKET_HEADER); // 2. 包类型 (1字节) header.add(packetType); // 3. 包序号 (2字节,大端序) header.add((packetSequence >> 8) & 0xFF); // 高字节 header.add(packetSequence & 0xFF); // 低字节 // 4. 包标识 (1字节: 高4位版本 + 低4位加密类型) int packetFlag = (PACKET_VERSION & 0xF0) | (encryptType & 0x0F); header.add(packetFlag); // 5. 数据长度 (4字节,大端序: 高16位加密后长度 + 低16位原始长度) int combinedLength = (encryptedDataLength << 16) | originalDataLength; header.add((combinedLength >> 24) & 0xFF); // 最高字节 header.add((combinedLength >> 16) & 0xFF); // 次高字节 header.add((combinedLength >> 8) & 0xFF); // 次低字节 header.add(combinedLength & 0xFF); // 最低字节 return header; } /// ✨✨✨ 组装包尾 (CRC16校验) ✨✨✨ /// [packetData] 完整的数据包(包头+数据块) static List buildPacketTail(List packetData) { int crc16 = calculateCRC16Kermit(packetData); // CRC16校验位 (2字节,大端序) List tail = [ (crc16 >> 8) & 0xFF, // 高字节 crc16 & 0xFF, // 低字节 ]; return tail; } /// ✨✨✨ 计算CRC16-KERMIT校验 ✨✨✨ static int calculateCRC16Kermit(List data) { const int polynomial = 0x1021; // CRC16-KERMIT多项式 const int initialValue = 0x0000; int crc = initialValue; for (int byte in data) { crc ^= (byte << 8); for (int i = 0; i < 8; i++) { if ((crc & 0x8000) != 0) { crc = (crc << 1) ^ polynomial; } else { crc <<= 1; } crc &= 0xFFFF; // 保持16位 } } // KERMIT CRC需要交换字节序 int result = ((crc & 0xFF) << 8) | ((crc >> 8) & 0xFF); return result; } /// ✨✨✨ 分包处理 - 将大数据分割成多个包 ✨✨✨ /// [originalData] 原始数据 /// [encryptType] 加密类型 /// 返回多个完整的数据包 static List> splitIntoPackets({ required List originalData, int encryptType = ENCRYPT_TYPE_PLAIN, }) { List> packets = []; // 计算需要分成多少包 int totalPackets = (originalData.length / MAX_PACKET_DATA_SIZE).ceil(); for (int i = 0; i < totalPackets; i++) { int startIndex = i * MAX_PACKET_DATA_SIZE; int endIndex = (startIndex + MAX_PACKET_DATA_SIZE > originalData.length) ? originalData.length : startIndex + MAX_PACKET_DATA_SIZE; // 获取当前包的数据 List currentPacketData = originalData.sublist(startIndex, endIndex); int originalDataLength = currentPacketData.length; // ✨✨✨ 根据加密类型计算加密后数据长度 ✨✨✨ int encryptedDataLength = originalDataLength; // 默认情况下加密后长度与原始长度相同 if (encryptType != ENCRYPT_TYPE_PLAIN) { // TODO: 根据具体加密算法计算加密后长度 // 例如AES128加密通常会填充到16字节的倍数 switch (encryptType) { case ENCRYPT_TYPE_AES128: // AES128加密填充到16字节边界 encryptedDataLength = ((originalDataLength + 15) ~/ 16) * 16; break; case ENCRYPT_TYPE_SM4_PRESET: case ENCRYPT_TYPE_SM4_DEVICE: // SM4加密填充到16字节边界 encryptedDataLength = ((originalDataLength + 15) ~/ 16) * 16; break; } } // 获取分包序号 int packetSequence = getNextPacketSequence(); // 组装包头 List header = buildPacketHeader( packetType: PACKET_TYPE_REQUEST, packetSequence: packetSequence, encryptType: encryptType, encryptedDataLength: encryptedDataLength, originalDataLength: originalDataLength, ); // 组装完整包 (包头 + 数据) List packetWithHeader = []; packetWithHeader.addAll(header); packetWithHeader.addAll(currentPacketData); // 计算并添加包尾 List tail = buildPacketTail(packetWithHeader); // 完整的数据包 List completePacket = []; completePacket.addAll(packetWithHeader); completePacket.addAll(tail); packets.add(completePacket); } return packets; } /// ✨✨✨ 抽象方法 - 子类需要实现具体的数据构建逻辑 ✨✨✨ List buildData(); /// ✨✨✨ 获取当前命令的加密类型 - 子类可以重写此方法 ✨✨✨ /// 默认返回明文类型,子类可以根据需要重写 int getEncryptType() { return ENCRYPT_TYPE_PLAIN; } /// ✨✨✨ 构建完整的命令包 ✨✨✨ /// 使用子类定义的加密类型自动组装数据包 List> build() { // 获取子类实现的数据 List commandData = buildData(); // 使用子类定义的加密类型 int encryptType = getEncryptType(); // 分包处理 List> packets = splitIntoPackets( originalData: commandData, encryptType: encryptType, ); return packets; } /// ✨✨✨ 解析接收到的数据包 ✨✨✨ /// [rawData] 接收到的原始数据包字节 /// 返回解析结果,包含包的各个字段信息 static ParsedPacket parsePacket(List rawData) { try { // 1. 检查最小长度 (包头4 + 包类型1 + 包序号2 + 包标识1 + 数据长度4 + CRC2 = 14字节) if (rawData.length < 14) { return ParsedPacket( isValid: false, packetType: 0, packetSequence: 0, version: 0, encryptType: 0, encryptedDataLength: 0, originalDataLength: 0, data: [], crc16: 0, errorMessage: '数据包长度不足: ${rawData.length}字节 < 14字节', ); } int offset = 0; // 2. 检查包头 List header = rawData.sublist(offset, offset + 4); offset += 4; if (!_isValidHeader(header)) { return ParsedPacket( isValid: false, packetType: 0, packetSequence: 0, version: 0, encryptType: 0, encryptedDataLength: 0, originalDataLength: 0, data: [], crc16: 0, errorMessage: '包头不正确: ${header.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' ')}', ); } // 3. 解析包类型 int packetType = rawData[offset++]; // 4. 解析包序号 (大端序) int packetSequence = (rawData[offset] << 8) | rawData[offset + 1]; offset += 2; // 5. 解析包标识 (高4位版本 + 低4位加密类型) int packetFlag = rawData[offset++]; int version = (packetFlag & 0xF0); int encryptType = (packetFlag & 0x0F); // 6. 解析数据长度 (大端序: 高16位加密后长度 + 低16位原始长度) int combinedLength = (rawData[offset] << 24) | (rawData[offset + 1] << 16) | (rawData[offset + 2] << 8) | rawData[offset + 3]; offset += 4; int encryptedDataLength = (combinedLength >> 16) & 0xFFFF; int originalDataLength = combinedLength & 0xFFFF; AppLogger.debug('📏 数据长度: 加密后=$encryptedDataLength, 原始=$originalDataLength'); // 7. 检查数据包完整性 // ✨✨✨ 根据加密类型确定实际数据长度 ✨✨✨ int actualDataLength = (encryptType == ENCRYPT_TYPE_PLAIN) ? originalDataLength : encryptedDataLength; int expectedTotalLength = 12 + actualDataLength + 2; // 包头到数据长度(12) + 数据块 + CRC(2) if (rawData.length != expectedTotalLength) { return ParsedPacket( isValid: false, packetType: packetType, packetSequence: packetSequence, version: version, encryptType: encryptType, encryptedDataLength: encryptedDataLength, originalDataLength: originalDataLength, data: [], crc16: 0, errorMessage: '数据包长度不匹配: 实际${rawData.length}字节 != 期望${expectedTotalLength}字节', ); } // 8. 提取数据块 // ✨✨✨ 根据加密类型提取相应长度的数据 ✨✨✨ List data = rawData.sublist(offset, offset + actualDataLength); offset += actualDataLength; // // 9. 提取CRC16校验位 (大端序) int crc16 = (rawData[offset] << 8) | rawData[offset + 1]; // // // 10. 验证CRC16校验 // List dataToCheck = rawData.sublist(0, rawData.length - 2); // 除去CRC的数据 // int calculatedCRC = calculateCRC16Kermit(dataToCheck); // bool crcValid = (calculatedCRC == crc16); // AppLogger.debug('🔍 CRC16验证: 计算值=0x${calculatedCRC.toRadixString(16).padLeft(4, '0')}, 接收值=0x${crc16.toRadixString(16).padLeft(4, '0')}, ${crcValid ? '✅通过' : '❌失败'}'); // // if (!crcValid) { // return ParsedPacket( // isValid: false, // packetType: packetType, packetSequence: packetSequence, version: version, encryptType: encryptType, // encryptedDataLength: encryptedDataLength, originalDataLength: originalDataLength, data: data, // crc16: crc16, errorMessage: 'CRC16校验失败: 计算值=0x${calculatedCRC.toRadixString(16).padLeft(4, '0')}, 接收值=0x${crc16.toRadixString(16).padLeft(4, '0')}', // ); // } return ParsedPacket( isValid: true, packetType: packetType, packetSequence: packetSequence, version: version, encryptType: encryptType, encryptedDataLength: encryptedDataLength, originalDataLength: originalDataLength, data: data, crc16: crc16, ); } catch (e) { AppLogger.error('❌ 数据包解析异常', error: e); return ParsedPacket( isValid: false, packetType: 0, packetSequence: 0, version: 0, encryptType: 0, encryptedDataLength: 0, originalDataLength: 0, data: [], crc16: 0, errorMessage: '解析异常: $e', ); } } /// ✨✨✨ 验证包头是否正确 ✨✨✨ static bool _isValidHeader(List header) { if (header.length != 4) return false; for (int i = 0; i < 4; i++) { if (header[i] != PACKET_HEADER[i]) { return false; } } return true; } // 获取固定长度的数组 List getFixedLengthList(List data, int length) { for (int i = 0; i < length; i++) { data.add(0); } return data; } }