import 'dart:convert'; import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/talk/startChart/constant/message_type_constant.dart'; import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart'; import 'package:star_lock/talk/startChart/entity/heartbeat_response.dart'; import 'package:star_lock/talk/startChart/entity/login_response.dart'; import 'package:star_lock/talk/startChart/proto/ble_message.pb.dart'; import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart'; import 'package:star_lock/talk/startChart/proto/gateway_transfer.pb.dart'; import 'package:star_lock/talk/startChart/proto/generic.pb.dart'; import 'package:star_lock/talk/startChart/proto/remote_unlock.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_accept.pbserver.dart'; import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_hangup.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_ping.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_push.pbserver.dart'; import 'package:star_lock/talk/startChart/proto/talk_receiver_transfer.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_reject.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_request.pb.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}'; } 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 (字符串,记录长度) if (FromPeerId != null) { bytes.addAll(utf8.encode(FromPeerId!)); } // ToPeerId (字符串,假设长度固定为32字节) if (ToPeerId != null) { bytes.addAll(utf8.encode(ToPeerId!)); } // 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 { // 如果不是字符串则需要外部转为字节数组,这里直接添加 bytes.addAll(Payload); } // 转16进制字符串 final bytesToHexString = bytesToHex(bytes); return bytesToHexString; } static ScpMessage deserialize(List bytes) { final message = ScpMessage(); int offset = 0; // 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!); // print('sublist:$sublist'); offset += message.PayloadLength!; message.Payload = _handlePayLoad( payloadType: message.PayloadType ?? 0, messageType: message.MessageType ?? 0, byte: sublist, offset: offset, PayloadLength: message.PayloadLength, ); } else { throw FormatException("Invalid Payload or PayloadLength"); } return message; } 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; } // 根据不同payloadType序列化对应的payload结构体 static dynamic _handlePayLoad({ required int payloadType, required int messageType, required List byte, int? offset, int? PayloadLength, }) { try { switch (payloadType) { case PayloadTypeConstant.goOnline: // 上线 LoginResponse loginResp = LoginResponse.fromBytes(byte); return loginResp; case PayloadTypeConstant.heartbeat: // 心跳 HeartbeatResponse heartbeatResponse = HeartbeatResponse.fromBytes(byte); return heartbeatResponse; case PayloadTypeConstant.echoTest: // 回声测试 String payload = utf8.decode(byte); return payload; case PayloadTypeConstant.gatewayReset: // 初始化网关 if (messageType == MessageTypeConstant.Resp) { final GatewayResetResp gatewayResetResp = GatewayResetResp.fromBuffer(byte); return gatewayResetResp; } else if (messageType == MessageTypeConstant.Req) { final GatewayResetReq gatewayResetReq = GatewayResetReq.fromBuffer(byte); return gatewayResetReq; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.callRequest: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkReq talkReq = TalkReq.fromBuffer(byte); return talkReq; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkAccept: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkAcceptReq talkAccept = TalkAcceptReq.fromBuffer(byte); return talkAccept; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.gatewayTransfer: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final GatewayTransferReq gatewayTransferReq = GatewayTransferReq.fromBuffer(byte); return gatewayTransferReq; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.blePassthrough: final BleResp bleResp = BleResp.fromBuffer(byte); return bleResp; case PayloadTypeConstant.remoteUnlock: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final RemoteUnlockResp remoteUnlockResp = RemoteUnlockResp.fromBuffer(byte); return remoteUnlockResp; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkReceiverTransfer: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkReceiverTransfer talkReceiverTransfer = TalkReceiverTransfer.fromBuffer(byte); return talkReceiverTransfer; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkPush: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkPush talkPush = TalkPush.fromBuffer(byte); return talkPush; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkReject: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkReject talkReject = TalkReject.fromBuffer(byte); return talkReject; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkPing: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkPing talkPing = TalkPing.fromBuffer(byte); return talkPing; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkExpect: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.Req) { final TalkExpect talkExpect = TalkExpect.fromBuffer(byte); return talkExpect; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkData: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.RealTimeData) { final TalkData talkData = TalkData.fromBuffer(byte); return talkData; } else { String payload = utf8.decode(byte); return payload; } case PayloadTypeConstant.talkHangup: if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp.fromBuffer(byte); return genericResp; } else if (messageType == MessageTypeConstant.RealTimeData) { final TalkHangup talkHangup = TalkHangup.fromBuffer(byte); return talkHangup; } else { String payload = utf8.decode(byte); return payload; } default: print('❌未知的payloadType类型,按照字符串解析'); String payload = utf8.decode(byte); return payload; } } catch (e) { _log(text: '❌反序列化udp数据时遇到错误----》$e'); String payload = utf8.decode(byte); return payload; } } static void _log({required String text}) { AppLog.log('=====${text}'); } }