import 'dart:convert'; import 'dart:typed_data'; import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/talk/starChart/exception/start_chart_message_exception.dart'; import 'package:star_lock/talk/starChart/handle/impl/udp_heart_beat_handler.dart'; import 'package:star_lock/talk/starChart/handle/scp_message_handle.dart'; import 'package:star_lock/talk/starChart/handle/scp_message_handler_factory.dart'; class ScpMessage { ScpMessage({ this.ProtocolFlag, this.MessageType, this.MessageId, this.SpTotal, this.SpIndex, this.FromPeerId, this.ToPeerId, this.PayloadType, this.PayloadCRC, this.PayloadLength, this.Payload, }); String? ProtocolFlag; int? MessageType; int? MessageId; int? SpTotal; int? SpIndex; String? FromPeerId; String? ToPeerId; int? PayloadType; int? PayloadCRC; int? PayloadLength; dynamic Payload; // Payload可以是任何类型,这里用dynamic表示 ScpMessage.fromJson(dynamic json) { ProtocolFlag = json['ProtocolFlag']; MessageType = json['MessageType']; MessageId = json['MessageId']; SpTotal = json['SpTotal']; SpIndex = json['SpIndex']; FromPeerId = json['FromPeerId']; ToPeerId = json['ToPeerId']; PayloadType = json['PayloadType']; PayloadCRC = json['PayloadCRC']; PayloadLength = json['PayloadLength']; Payload = json['Payload']; } Map toJson() { return { 'ProtocolFlag': ProtocolFlag, 'MessageType': MessageType, 'MessageId': MessageId, 'SpTotal': SpTotal, 'SpIndex': SpIndex, 'FromPeerId': FromPeerId, 'ToPeerId': ToPeerId, 'PayloadType': PayloadType, 'PayloadCRC': PayloadCRC, 'PayloadLength': PayloadLength, 'Payload': Payload, }; } @override String toString() { return 'ScpMessage{ProtocolFlag: $ProtocolFlag, MessageType: $MessageType, MessageId: $MessageId, SpTotal: $SpTotal, SpIndex: $SpIndex, FromPeerId: $FromPeerId, ToPeerId: $ToPeerId, PayloadType: $PayloadType, PayloadCRC: $PayloadCRC, PayloadLength: $PayloadLength, Payload: $Payload}'; } // 辅助函数:定长字符串编码 List encodeFixedLengthString(String? str, int length) { final bytes = utf8.encode(str ?? ''); if (bytes.length > length) { return bytes.sublist(0, length); } else if (bytes.length < length) { return bytes + List.filled(length - bytes.length, 0); } else { return bytes; } } String serialize() { final bytes = []; // ProtocolFlag (4 bytes) if (ProtocolFlag != null) { bytes.addAll(utf8.encode(ProtocolFlag!)); } // MessageType (1 byte) if (MessageType != null) { bytes.add(MessageType!); } // MessageId (2 bytes) if (MessageId != null) { final highByteMessageId = (MessageId! >> 8) & 0xFF; final lowByteMessageId = MessageId! & 0xFF; bytes.add(lowByteMessageId); // 交换位置 bytes.add(highByteMessageId); // 交换位置 } // SpTotal (1 byte) if (SpTotal != null) { bytes.add(SpTotal!); } // SpIndex (1 byte) if (SpIndex != null) { bytes.add(SpIndex!); } // FromPeerId (字符串,长度固定为44字节) if (FromPeerId != null) { bytes.addAll(utf8.encode(FromPeerId!)); } // FromPeerId (44字节定长) // bytes.addAll(encodeFixedLengthString(FromPeerId, 44)); // ToPeerId (字符串,长度固定为44字节) if (ToPeerId != null) { bytes.addAll(utf8.encode(ToPeerId!)); } // ToPeerId (44字节定长) // bytes.addAll(encodeFixedLengthString(ToPeerId, 44)); // PayloadType (2 bytes) if (PayloadType != null) { final highBytePayloadType = (PayloadType! >> 8) & 0xFF; final lowBytePayloadType = PayloadType! & 0xFF; bytes.add(lowBytePayloadType); // 交换位置 bytes.add(highBytePayloadType); // 交换位置 } // 计算 PayloadCRC (2 bytes) if (PayloadCRC != null) { final highBytePayloadCRC = (PayloadCRC! >> 8) & 0xFF; final lowBytePayloadCRC = PayloadCRC! & 0xFF; bytes.add(lowBytePayloadCRC); // 交换位置 bytes.add(highBytePayloadCRC); // 交换位置 } // PayloadLength (4 bytes) if (PayloadLength != null) { bytes.add(PayloadLength! & 0xFF); bytes.add((PayloadLength! >> 8) & 0xFF); bytes.add((PayloadLength! >> 16) & 0xFF); bytes.add((PayloadLength! >> 24) & 0xFF); } // Payload (字符串,转换为字节) if (Payload != null && Payload is String) { bytes.addAll(utf8.encode(Payload!)); } else if (Payload != null) { // 如果不是字符串则需要外部转为字节数组,这里直接添加 bytes.addAll(Payload); } // 转16进制字符串 final bytesToHexString = bytesToHex(bytes); return bytesToHexString; } static ScpMessage deserialize(Uint8List bytes) { final message = ScpMessage(); final length = bytes.length; int offset = 0; // 提前检查字节数组长度是否足够 if (length < 4 + 1 + 2 + 1 + 1 + 44 + 44 + 2 + 2 + 4) { throw FormatException("Invalid message length"); } // 使用 ByteData 读取多字节数据 final byteData = ByteData.sublistView(bytes); // ProtocolFlag (4 bytes) message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4)); offset += 4; // MessageType (1 byte) message.MessageType = bytes[offset]; offset += 1; // MessageId (2 bytes, little-endian) message.MessageId = byteData.getUint16(offset, Endian.little); offset += 2; // SpTotal (1 byte) message.SpTotal = bytes[offset]; offset += 1; // SpIndex (1 byte) message.SpIndex = bytes[offset]; offset += 1; // FromPeerId (44 bytes) message.FromPeerId = utf8.decode(bytes.sublist(offset, offset + 44)).trimRight(); offset += 44; // ToPeerId (44 bytes) message.ToPeerId = utf8.decode(bytes.sublist(offset, offset + 44)).trimRight(); offset += 44; // PayloadType (2 bytes, little-endian) message.PayloadType = byteData.getUint16(offset, Endian.little); offset += 2; // PayloadCRC (2 bytes, little-endian) message.PayloadCRC = byteData.getUint16(offset, Endian.little); offset += 2; // PayloadLength (4 bytes, little-endian) message.PayloadLength = byteData.getUint32(offset, Endian.little); offset += 4; // 检查 Payload 长度是否有效 if (message.PayloadLength == null || length - offset < message.PayloadLength!) { throw FormatException("Invalid Payload or PayloadLength"); } // 处理 Payload final payloadBytes = bytes.sublist(offset, offset + message.PayloadLength!); offset += message.PayloadLength!; message.Payload = _handlePayLoad( payloadType: message.PayloadType ?? 0, messageType: message.MessageType ?? 0, byte: payloadBytes, offset: offset, PayloadLength: message.PayloadLength, spIndex: message.SpIndex, spTotal: message.SpTotal, messageId: message.MessageId, ); return message; } // static ScpMessage deserialize(Uint8List bytes) { // final message = ScpMessage(); // int offset = 0; // // // String hexString = // // bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); // // // _log(text: 'result bytes hex: ${hexString}'); // // _log( // // text: // // '\n result bytes hex: ${hexString} \n payload hex: ${hexString.substring(210)}'); // // // ProtocolFlag (4 bytes) // if (bytes.length - offset >= 4) { // message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4)); // offset += 4; // } else { // throw FormatException("Invalid ProtocolFlag length"); // } // // // MessageType (1 byte) // if (bytes.length - offset >= 1) { // message.MessageType = bytes[offset]; // offset += 1; // } else { // throw FormatException("Invalid MessageType length"); // } // // // MessageId (2 bytes, little-endian) // if (bytes.length - offset >= 2) { // message.MessageId = (bytes[offset + 1] << 8) | bytes[offset]; // offset += 2; // } else { // throw FormatException("Invalid MessageId length"); // } // // // SpTotal (1 byte) // if (bytes.length - offset >= 1) { // message.SpTotal = bytes[offset]; // offset += 1; // } else { // throw FormatException("Invalid SpTotal length"); // } // // // SpIndex (1 byte) // if (bytes.length - offset >= 1) { // message.SpIndex = bytes[offset]; // offset += 1; // } else { // throw FormatException("Invalid SpIndex length"); // } // // // FromPeerId (字符串,长度固定为44字节) // if (bytes.length - offset >= 44) { // message.FromPeerId = // utf8.decode(bytes.sublist(offset, offset + 44)).trimRight(); // offset += 44; // } else { // throw FormatException("Invalid FromPeerId length"); // } // // // ToPeerId (字符串,长度固定为44字节) // if (bytes.length - offset >= 44) { // message.ToPeerId = // utf8.decode(bytes.sublist(offset, offset + 44)).trimRight(); // offset += 44; // } else { // throw FormatException("Invalid ToPeerId length"); // } // // // PayloadType (2 bytes, little-endian) // if (bytes.length - offset >= 2) { // message.PayloadType = (bytes[offset + 1] << 8) | bytes[offset]; // offset += 2; // } else { // throw FormatException("Invalid PayloadType length"); // } // // // PayloadCRC (2 bytes, little-endian) // if (bytes.length - offset >= 2) { // message.PayloadCRC = (bytes[offset + 1] << 8) | bytes[offset]; // offset += 2; // } else { // throw FormatException("Invalid PayloadCRC length"); // } // // // PayloadLength (4 bytes, little-endian) // if (bytes.length - offset >= 4) { // message.PayloadLength = (bytes[offset] | // (bytes[offset + 1] << 8) | // (bytes[offset + 2] << 16) | // (bytes[offset + 3] << 24)); // 修正为 little-endian // offset += 4; // } else { // throw FormatException("Invalid PayloadLength length"); // } // // // 处理其他类型的Payload // if (message.PayloadLength != null && // bytes.length - offset >= message.PayloadLength!) { // final sublist = bytes.sublist(offset, offset + message.PayloadLength!); // offset += message.PayloadLength!; // message.Payload = _handlePayLoad( // payloadType: message.PayloadType ?? 0, // messageType: message.MessageType ?? 0, // byte: sublist, // offset: offset, // PayloadLength: message.PayloadLength, // spIndex: message.SpIndex, // spTotal: message.SpTotal, // messageId: message.MessageId, // ); // } else { // throw FormatException("Invalid Payload or PayloadLength"); // } // // return message; // } // 根据不同payloadType序列化对应的payload结构体 static dynamic _handlePayLoad({ required int payloadType, required int messageType, required List byte, int? offset, int? PayloadLength, int? spTotal, int? spIndex, int? messageId, }) { try { // 构造工厂 final ScpMessageHandler handler = ScpMessageHandlerFactory.createHandler(payloadType); // 处理荷载信息并返回 final payload = handler.deserializePayload( payloadType: payloadType, messageType: messageType, byte: byte, offset: offset, PayloadLength: PayloadLength, spTotal: spTotal, spIndex: spIndex, messageId: messageId, ); return payload; } catch (e, stackTrace) { throw StartChartMessageException('❌反序列化udp数据时遇到错误----》$e \n$stackTrace'); } } static String bytesToHex(List bytes) { return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(''); } // 辅助函数:将16进制字符串转换为字节数组 static List hexToBytes(String hexString) { final bytes = []; for (int i = 0; i < hexString.length; i += 2) { final hexByte = hexString.substring(i, i + 2); bytes.add(int.parse(hexByte, radix: 16)); } return bytes; } static void _log({required String text}) { AppLog.log('=====${text}'); } }