using JT809.Protocol.Enums; using JT809.Protocol.Exceptions; using JT809.Protocol.Extensions; using JT809.Protocol.Formatters; using JT809.Protocol.Interfaces; using JT809.Protocol.MessagePack; using System; using System.Text.Json; namespace JT809.Protocol { public class JT809Package:IJT809MessagePackFormatter, IJT809Analyze, IJT809_2019_Version { public const byte BEGINFLAG = 0X5B; public const byte ENDFLAG = 0X5D; /// /// 固定为26个字节长度 /// Head flag + Message Header + CRC Code + End Flag /// 1 + 22 + 2 + 1 = 26 /// public const int FixedByteLength = 26; /// /// 固定为26个字节长度 /// Head flag + Message Header + CRC Code + End Flag /// 1 + 30 + 2 + 1 = 26 /// public const int FixedByteLength_2019 = 34; public byte BeginFlag { get; set; } = BEGINFLAG; public JT809Header Header { get; set; } public JT809Bodies Bodies { get; set; } public ushort CRCCode { get; set; } public byte EndFlag { get; set; } = ENDFLAG; public JT809Package Deserialize(ref JT809MessagePackReader reader, IJT809Config config) { // 1. 验证校验码 if (!config.SkipCRCCode) { // 1.2. 验证校验码 if (!reader.CheckXorCodeVali) { throw new JT809Exception(JT809ErrorCode.CRC16CheckInvalid, $"{reader.CalculateCheckXorCode}!={reader.RealCheckXorCode}"); } } JT809Package jT809Package = new JT809Package(); // 2.读取起始头 jT809Package.BeginFlag = reader.ReadStart(); // 3.初始化消息头 try { jT809Package.Header = config.GetMessagePackFormatter().Deserialize(ref reader, config); } catch (Exception ex) { throw new JT809Exception(JT809ErrorCode.HeaderParseError, $"offset>{reader.ReadCurrentRemainContentLength()}", ex); } // 5.数据体处理 // 5.1 判断是否有数据体(总长度-固定长度)> 0 int fixedByteLength = config.Version == JT809Version.JTT2019 ? FixedByteLength_2019 : FixedByteLength; if ((jT809Package.Header.MsgLength - fixedByteLength) > 0) { if (config.BusinessTypeFactory.TryGetValue(jT809Package.Header.BusinessType, config.Version, out object instance)) { try { // 5.2 是否加密 switch (jT809Package.Header.EncryptFlag) { case JT809Header_Encrypt.None: // 5.3 处理消息体 jT809Package.Bodies = JT809MessagePackFormatterResolverExtensions.JT809DynamicDeserialize(instance,ref reader, config); break; case JT809Header_Encrypt.Common: // 5.4. 处理加密消息体 byte[] bodiesData = config.Encrypt.Decrypt(reader.ReadContent(), config.EncryptOptions, jT809Package.Header.EncryptKey); JT809MessagePackReader bodiesReader = new JT809MessagePackReader(bodiesData); jT809Package.Bodies = JT809MessagePackFormatterResolverExtensions.JT809DynamicDeserialize(instance,ref bodiesReader, config); break; } } catch (Exception ex) { throw new JT809Exception(JT809ErrorCode.BodiesParseError, $"offset>{reader.ReadCurrentRemainContentLength().ToString()}", ex); } } } jT809Package.CRCCode = reader.ReadUInt16(); jT809Package.EndFlag = reader.ReadEnd(); return jT809Package; } public void Serialize(ref JT809MessagePackWriter writer, JT809Package value, IJT809Config config) { // -----------开始组包---------- // 1.起始符 writer.WriteByte(value.BeginFlag); // 2.写入头部数据 // 2.1.跳过数据长度的写入 writer.Skip(4, out int lengthPosition); // 2.2.报文序列号 value.Header.MsgSN = value.Header.MsgSN > 0 ? value.Header.MsgSN : config.MsgSNDistributed.Increment(); writer.WriteUInt32(value.Header.MsgSN); // 2.3.业务数据类型 writer.WriteUInt16(value.Header.BusinessType); // 2.4.下级平台接入码 writer.WriteUInt32(value.Header.MsgGNSSCENTERID); // 2.5.版本号 writer.WriteArray(value.Header.Version.Buffer); // 2.6.报文加密 writer.WriteByte((byte)value.Header.EncryptFlag); // 2.7.数据加密密钥 writer.WriteUInt32(value.Header.EncryptKey); if(config.Version== JT809Version.JTT2019) { // 2.8.UTC时间戳 writer.WriteUTCDateTime(value.Header.Time); } // 3.写入数据体 // 3.1.记录当前开始位置 int startIndex = writer.GetCurrentPosition(); // 3.2.写入数据对应数据体 if (value.Bodies != null) { JT809MessagePackFormatterResolverExtensions.JT809DynamicSerialize(value.Bodies,ref writer, value.Bodies,config); } // 3.3.记录当前结束位置 int endIndex = writer.GetCurrentPosition(); int contentLength = endIndex - startIndex; if (contentLength > 0) { // 3.4. 数据加密 switch (value.Header.EncryptFlag) { case JT809Header_Encrypt.None: break; case JT809Header_Encrypt.Common: // 3.5. 提取数据体并进行加密处理 byte[] messageBodyDatEncrypted = config.Encrypt.Encrypt(writer.Extract(startIndex), config.EncryptOptions, value.Header.EncryptKey); int flagLength = messageBodyDatEncrypted.Length - contentLength; if (flagLength == 0) { // 相等复制 writer.CopyTo(messageBodyDatEncrypted, startIndex); } else if (flagLength > 0) { // 扩容 writer.Skip(flagLength, out _); writer.CopyTo(messageBodyDatEncrypted, startIndex); } else { // 缩减 writer.CopyTo(messageBodyDatEncrypted, startIndex); writer.Shrink(-flagLength); } break; } } // 4.计算内容的总长度(校验码2+终止符1=3) writer.WriteInt32Return(writer.GetCurrentPosition() + 3, lengthPosition); // 5.校验码 writer.WriteCRC16(); // 6.终止符 writer.WriteByte(value.EndFlag); // 7.转义 writer.WriteEncode(); // -----------组包完成---------- } public void Analyze(ref JT809MessagePackReader reader, Utf8JsonWriter writer, IJT809Config config) { JT809Package jT809Package = new JT809Package(); writer.WriteStartObject(); // 2.读取起始头 jT809Package.BeginFlag = reader.ReadStart(); writer.WriteNumber($"[{jT809Package.BeginFlag.ReadNumber()}]起始标识", jT809Package.BeginFlag); // 3.初始化消息头 JT809Header jT809Header=new JT809Header(); writer.WriteStartObject("消息头"); try { jT809Header.MsgLength = reader.ReadUInt32(); writer.WriteNumber($"[{jT809Header.MsgLength.ReadNumber()}]数据长度", jT809Header.MsgLength); jT809Header.MsgSN = reader.ReadUInt32(); writer.WriteNumber($"[{jT809Header.MsgSN.ReadNumber()}]报文序列号", jT809Header.MsgSN); jT809Header.BusinessType = reader.ReadUInt16(); writer.WriteString($"[{jT809Header.BusinessType.ReadNumber()}]业务类型标识", ((JT809BusinessType)jT809Header.BusinessType).ToString()); jT809Header.MsgGNSSCENTERID = reader.ReadUInt32(); writer.WriteNumber($"[{jT809Header.MsgGNSSCENTERID.ReadNumber()}]下级平台接入码", jT809Header.MsgGNSSCENTERID); var virtualHex = reader.ReadVirtualArray(JT809Header_Version.FixedByteLength); jT809Header.Version = new JT809Header_Version(reader.ReadArray(JT809Header_Version.FixedByteLength)); writer.WriteString($"[{virtualHex.ToArray().ToHexString()}]协议版本号标识", jT809Header.Version.ToString()); jT809Header.EncryptFlag = (JT809Header_Encrypt)reader.ReadByte(); writer.WriteString($"[{ jT809Header.EncryptFlag.ToByteValue()}]报文加密标识位", jT809Header.EncryptFlag.ToString()); jT809Header.EncryptKey = reader.ReadUInt32(); writer.WriteNumber($"[{jT809Header.EncryptKey.ReadNumber()}]数据加密的密匙", jT809Header.EncryptKey); if (config.Version == JT809Version.JTT2019) { virtualHex = reader.ReadVirtualArray(8); jT809Header.Time = reader.ReadUTCDateTime(); writer.WriteString($"[{virtualHex.ToArray().ToHexString()}]发送消息时的系统UTC时间", jT809Header.Time); } } catch (Exception ex) { writer.WriteString($"[{(int)JT809ErrorCode.HeaderParseError}]消息头异常", $"offset>{reader.ReadCurrentRemainContentLength()},异常消息:{ex.Message}"); } writer.WriteEndObject(); writer.WriteStartObject("消息体"); // 5.数据体处理 // 5.1 判断是否有数据体(总长度-固定长度)> 0 int fixedByteLength = config.Version == JT809Version.JTT2019 ? FixedByteLength_2019 : FixedByteLength; if ((jT809Header.MsgLength - fixedByteLength) > 0) { if (config.BusinessTypeFactory.TryGetValue(jT809Header.BusinessType, config.Version, out object instance)) { try { // 5.2 是否加密 switch (jT809Header.EncryptFlag) { case JT809Header_Encrypt.None: // 5.3 处理消息体 instance.Analyze(ref reader, writer, config); break; case JT809Header_Encrypt.Common: // 5.4. 处理加密消息体 byte[] bodiesData = config.Encrypt.Decrypt(reader.ReadContent(), config.EncryptOptions, jT809Header.EncryptKey); JT809MessagePackReader bodiesReader = new JT809MessagePackReader(bodiesData); instance.Analyze(ref bodiesReader, writer, config); break; } } catch (Exception ex) { writer.WriteString($"[{(int)JT809ErrorCode.BodiesParseError}]消息体异常", $"offset>{reader.ReadCurrentRemainContentLength()},异常消息:{ex.Message}"); } } } writer.WriteEndObject(); jT809Package.CRCCode = reader.ReadUInt16(); writer.WriteNumber($"[{jT809Package.CRCCode.ReadNumber()}]校验码", jT809Package.CRCCode); // 1. 验证校验码 if (!config.SkipCRCCode) { // 1.2. 验证校验码 if (!reader.CheckXorCodeVali) { writer.WriteString($"[{(int)JT809ErrorCode.CRC16CheckInvalid}]校验码异常", $"{reader.CalculateCheckXorCode}!={reader.RealCheckXorCode}"); } } jT809Package.EndFlag = reader.ReadEnd(); writer.WriteNumber($"[{jT809Package.EndFlag.ReadNumber()}]结束标识", jT809Package.EndFlag); writer.WriteEndObject(); } } }