diff --git a/README.md b/README.md index 38863d9..9644f9e 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,9 @@ ### 数据头[JT809Header] -|数据长度|报文序列号|业务数据类型|下级平台接入码|协议版本号标识|报文加密标识位|数据加密的密匙| -|:------:|:------:|:------:|:------:|:------:|:------:|:------:| -| MsgLength | MsgSN | BusinessType | MsgGNSSCENTERID | Version |EncryptFlag | EncryptKey | +|数据长度|报文序列号|业务数据类型|下级平台接入码|协议版本号标识|报文加密标识位|数据加密的密匙|发送消息的系统时间(2019版本)| +|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:| +| MsgLength | MsgSN | BusinessType | MsgGNSSCENTERID | Version |EncryptFlag | EncryptKey |Time| ### 数据体[JT809Bodies] diff --git a/src/JT809.Protocol.Test/JT809MessageBody/JT809_0x9101Test.cs b/src/JT809.Protocol.Test/JT809MessageBody/JT809_0x9101Test.cs index 4ce9dde..b1bfeaf 100644 --- a/src/JT809.Protocol.Test/JT809MessageBody/JT809_0x9101Test.cs +++ b/src/JT809.Protocol.Test/JT809MessageBody/JT809_0x9101Test.cs @@ -17,8 +17,8 @@ namespace JT809.Protocol.Test.JT809MessageBody { JT809_0x9101 jT809_0X9101 = new JT809_0x9101(); jT809_0X9101.DynamicInfoTotal = 10000; - jT809_0X9101.StartTime = 1537513862; - jT809_0X9101.EndTime = 1537531862; + jT809_0X9101.StartTime = DateTime.Parse("2018-09-21 15:11:02"); + jT809_0X9101.EndTime = DateTime.Parse("2018-09-21 20:11:02"); var hex = JT809Serializer.Serialize(jT809_0X9101).ToHexString(); Assert.Equal("00002710000000005BA49986000000005BA4DFD6",hex); } @@ -29,8 +29,8 @@ namespace JT809.Protocol.Test.JT809MessageBody var bytes = "00 00 27 10 00 00 00 00 5B A4 99 86 00 00 00 00 5B A4 DF D6".ToHexBytes(); JT809_0x9101 jT809_0X9101 = JT809Serializer.Deserialize(bytes); Assert.Equal((uint)10000, jT809_0X9101.DynamicInfoTotal); - Assert.Equal((ulong)1537513862, jT809_0X9101.StartTime); - Assert.Equal((ulong)1537531862, jT809_0X9101.EndTime); + Assert.Equal(DateTime.Parse("2018-09-21 15:11:02"), jT809_0X9101.StartTime); + Assert.Equal(DateTime.Parse("2018-09-21 20:11:02"), jT809_0X9101.EndTime); } } } diff --git a/src/JT809.Protocol/Enums/JT809BusinessType.cs b/src/JT809.Protocol/Enums/JT809BusinessType.cs index 6821493..a2adbe9 100644 --- a/src/JT809.Protocol/Enums/JT809BusinessType.cs +++ b/src/JT809.Protocol/Enums/JT809BusinessType.cs @@ -151,6 +151,46 @@ namespace JT809.Protocol.Enums [JT809BodiesType(typeof(JT809_0x9101))] [JT809BusinessTypeDescription("DOWN_TOTAL_RECV_BACK_MSG", "接收车辆定位信息数量通知消息")] 接收车辆定位信息数量通知消息 = 0x9101, + /// + ///发送车辆定位信息数据量通知消息_2019 + ///DOWN_TOTAL_RECV_BACK_MSG + /// + [Description("接收车辆定位信息数量通知消息")] + [JT809BodiesType(typeof(JT809_2019_0x9101))] + [JT809BusinessTypeDescription("DOWN_TOTAL_RECV_BACK_MSG", "发送车辆定位信息数据量通知消息")] + 发送车辆定位信息数据量通知消息_2019 = 0x9101, + /// + ///发送车辆定位信息数据量通知消息_2019 + ///DOWN_TOTAL_RECV_BACK_MSG + /// + [Description("平台链路连接情况与车辆定位消息传输情况上报请求消息")] + [JT809BodiesType(typeof(JT809_0x9102))] + [JT809BusinessTypeDescription("DOWN_MANAGE_MSG_REQ", "平台链路连接情况与车辆定位消息传输情况上报请求消息")] + 平台链路连接情况与车辆定位消息传输情况上报请求消息_2019 = 0x9102, + /// + ///发送车辆定位信息数据量通知消息_2019 + ///UP_MANAGE_MSG_RSP + /// + [Description("平台链路连接情况与车辆定位消息传输情况上报应答消息")] + [JT809BodiesType(typeof(JT809_0x1102))] + [JT809BusinessTypeDescription("UP_MANAGE_MSG_RSP", "平台链路连接情况与车辆定位消息传输情况上报应答消息")] + 平台链路连接情况与车辆定位消息传输情况上报应答消息_2019 = 0x1102, + /// + ///上传平台间消息序列号通知消息 + ///UP_MANAGE_MSG_SN_INFORM + /// + [Description("上传平台间消息序列号通知消息")] + [JT809BodiesType(typeof(JT809_0x1102))] + [JT809BusinessTypeDescription("UP_MANAGE_MSG_SN_INFORM", "上传平台间消息序列号通知消息")] + 上传平台间消息序列号通知消息_2019 = 0x1103, + /// + ///下发平台间消息序列号通知消息 + ///UP_MANAGE_MSG_SN_INFORM + /// + [Description("下发平台间消息序列号通知消息")] + [JT809BodiesType(typeof(JT809_0x1102))] + [JT809BusinessTypeDescription("DOWN_MANAGE_MSG_SN_INFORM", "下发平台间消息序列号通知消息")] + 下发平台间消息序列号通知消息_2019 = 0x9103, #endregion #region 车辆动态信息交换 /// diff --git a/src/JT809.Protocol/Enums/JT809_0x1002_Result.cs b/src/JT809.Protocol/Enums/JT809_0x1002_Result.cs index 13f42a2..7515da1 100644 --- a/src/JT809.Protocol/Enums/JT809_0x1002_Result.cs +++ b/src/JT809.Protocol/Enums/JT809_0x1002_Result.cs @@ -15,6 +15,7 @@ namespace JT809.Protocol.Enums 用户没用注册=0x03, 密码错误=0x04, 资源紧张_稍后再连接_已经占用= 0x05, - 其他 =0x06 + 其他 =0x06, + 其他_2019 = 0xFF } } diff --git a/src/JT809.Protocol/Interfaces/IJT809BusinessTypeFactory.cs b/src/JT809.Protocol/Interfaces/IJT809BusinessTypeFactory.cs index 8725ed4..00fb8b2 100644 --- a/src/JT809.Protocol/Interfaces/IJT809BusinessTypeFactory.cs +++ b/src/JT809.Protocol/Interfaces/IJT809BusinessTypeFactory.cs @@ -1,4 +1,5 @@ -using System; +using JT809.Protocol.Enums; +using System; using System.Collections.Generic; namespace JT809.Protocol.Interfaces @@ -6,7 +7,8 @@ namespace JT809.Protocol.Interfaces public interface IJT809BusinessTypeFactory : IJT809ExternalRegister { IDictionary Map { get; } - bool TryGetValue(ushort msgId, out object instance); + IDictionary Map_2019 { get; } + bool TryGetValue(ushort msgId, JT809Version version , out object instance); IJT809BusinessTypeFactory SetMap() where TJT809Bodies : JT809Bodies; } } diff --git a/src/JT809.Protocol/Interfaces/IJT809Config.cs b/src/JT809.Protocol/Interfaces/IJT809Config.cs index fec8418..658cbd0 100644 --- a/src/JT809.Protocol/Interfaces/IJT809Config.cs +++ b/src/JT809.Protocol/Interfaces/IJT809Config.cs @@ -1,5 +1,6 @@ using JT808.Protocol.Formatters; using JT809.Protocol.Configs; +using JT809.Protocol.Enums; using JT809.Protocol.Interfaces; using System; using System.Collections.Generic; @@ -40,6 +41,7 @@ namespace JT809.Protocol IJT809BusinessTypeFactory BusinessTypeFactory { get; set; } IJT809SubBusinessTypeFactory SubBusinessTypeFactory { get; set; } IJT809FormatterFactory FormatterFactory { get; set; } + JT809Version Version { get; set; } /// /// 全局注册外部程序集 /// diff --git a/src/JT809.Protocol/Interfaces/JT809GlobalConfigBase.cs b/src/JT809.Protocol/Interfaces/JT809GlobalConfigBase.cs index cde49c3..9fd98f0 100644 --- a/src/JT809.Protocol/Interfaces/JT809GlobalConfigBase.cs +++ b/src/JT809.Protocol/Interfaces/JT809GlobalConfigBase.cs @@ -2,6 +2,7 @@ using JT808.Protocol.Internal; using JT809.Protocol.Configs; using JT809.Protocol.Encrypt; +using JT809.Protocol.Enums; using JT809.Protocol.Internal; using System; using System.Reflection; @@ -11,13 +12,14 @@ namespace JT809.Protocol.Interfaces { public abstract class JT809GlobalConfigBase : IJT809Config { - protected JT809GlobalConfigBase() + protected JT809GlobalConfigBase(JT809Version version= JT809Version.JTT2013) { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding = Encoding.GetEncoding("GBK"); BusinessTypeFactory = new JT809BusinessTypeFactory(); SubBusinessTypeFactory = new JT809SubBusinessTypeFactory(); FormatterFactory = new JT809FormatterFactory(); + Version = version; } public abstract string ConfigId { get; } public virtual IJT809MsgSNDistributed MsgSNDistributed { get; set; }= new DefaultMsgSNDistributedImpl(); @@ -29,6 +31,8 @@ namespace JT809.Protocol.Interfaces public IJT809BusinessTypeFactory BusinessTypeFactory { get ; set ; } public IJT809SubBusinessTypeFactory SubBusinessTypeFactory { get; set ; } public IJT809FormatterFactory FormatterFactory { get; set; } + public JT809Version Version { get; set; } + public virtual IJT809Config Register(params Assembly[] externalAssemblies) { if (externalAssemblies != null) diff --git a/src/JT809.Protocol/Internal/JT809BusinessTypeFactory.cs b/src/JT809.Protocol/Internal/JT809BusinessTypeFactory.cs index 576acdc..be74f03 100644 --- a/src/JT809.Protocol/Internal/JT809BusinessTypeFactory.cs +++ b/src/JT809.Protocol/Internal/JT809BusinessTypeFactory.cs @@ -14,15 +14,17 @@ namespace JT808.Protocol.Internal { public IDictionary Map { get; } + public IDictionary Map_2019 { get; } + internal JT809BusinessTypeFactory() { Map = new Dictionary(); + Map_2019 = new Dictionary(); InitMap(Assembly.GetExecutingAssembly()); } private void InitMap(Assembly assembly) { - // var types = assembly.GetTypes().Where(w => w.BaseType == typeof(JT809Bodies)).Where(w=>w != typeof(JT809ExchangeMessageBodies)).ToList(); var types = assembly.GetTypes() .Where(w => w.BaseType == typeof(JT809Bodies) || w.BaseType == typeof(JT809ExchangeMessageBodies)).ToList(); foreach (var type in types) @@ -30,17 +32,37 @@ namespace JT808.Protocol.Internal if (type.Name == nameof(JT809ExchangeMessageBodies)) continue; var instance = Activator.CreateInstance(type); ushort msgId = 0; + JT809Version version; try { msgId = (ushort)type.GetProperty(nameof(JT809Bodies.MsgId)).GetValue(instance); + version = (JT809Version)type.GetProperty(nameof(JT809Bodies.Version)).GetValue(instance); } catch (Exception ex) { continue; } + if (Map_2019.ContainsKey(msgId)) + { + if (version == JT809Version.JTT2019) + { + Map_2019[msgId] = instance; + } + else + { + throw new ArgumentException($"{type.FullName} {msgId} An element with the same key already exists."); + } + } + else + { + Map_2019.Add(msgId, instance); + } if (Map.ContainsKey(msgId)) { - throw new ArgumentException($"{type.FullName} {msgId} An element with the same key already exists."); + if (version != JT809Version.JTT2019) + { + throw new ArgumentException($"{type.FullName} {msgId} An element with the same key already exists."); + } } else { @@ -49,24 +71,38 @@ namespace JT808.Protocol.Internal } } - public bool TryGetValue(ushort msgId, out object instance) - { - return Map.TryGetValue(msgId, out instance); - } - public IJT809BusinessTypeFactory SetMap() where TJT809Bodies : JT809Bodies { Type type = typeof(TJT809Bodies); var instance = Activator.CreateInstance(type); var msgId = (ushort)type.GetProperty(nameof(JT809Bodies.MsgId)).GetValue(instance); + JT809Version version = (JT809Version)type.GetProperty(nameof(JT809Bodies.Version)).GetValue(instance); if (Map.ContainsKey(msgId)) { - throw new ArgumentException($"{type.FullName} {msgId} An element with the same key already exists."); + if (version != JT809Version.JTT2019) + { + throw new ArgumentException($"{type.FullName} {msgId} An element with the same key already exists."); + } } else { Map.Add(msgId, instance); } + if (Map_2019.ContainsKey(msgId)) + { + if (version == JT809Version.JTT2019) + { + Map_2019[msgId] = instance; + } + else + { + throw new ArgumentException($"{type.FullName} {msgId} An element with the same key already exists."); + } + } + else + { + Map_2019.Add(msgId, instance); + } return this; } @@ -74,5 +110,17 @@ namespace JT808.Protocol.Internal { InitMap(externalAssembly); } + + public bool TryGetValue(ushort msgId, JT809Version version, out object instance) + { + if(version== JT809Version.JTT2019) + { + return Map_2019.TryGetValue(msgId, out instance); + } + else + { + return Map.TryGetValue(msgId, out instance); + } + } } } diff --git a/src/JT809.Protocol/JT809Bodies.cs b/src/JT809.Protocol/JT809Bodies.cs index 411dacf..1f0dc63 100644 --- a/src/JT809.Protocol/JT809Bodies.cs +++ b/src/JT809.Protocol/JT809Bodies.cs @@ -11,11 +11,9 @@ namespace JT809.Protocol /// 当数据体为空的时候,使用null作为空包感觉不适合,所以就算使用空包也需要new一下来表达意思。 /// public virtual bool SkipSerialization { get; set; } = false; - + public virtual JT809Version Version => JT809Version.JTT2013; public abstract ushort MsgId { get; } - public abstract JT809_LinkType LinkType { get; } - public abstract string Description { get; } } } diff --git a/src/JT809.Protocol/JT809Header.cs b/src/JT809.Protocol/JT809Header.cs index a152f58..878da5b 100644 --- a/src/JT809.Protocol/JT809Header.cs +++ b/src/JT809.Protocol/JT809Header.cs @@ -1,5 +1,7 @@ -using JT809.Protocol.Formatters; +using JT809.Protocol.Enums; +using JT809.Protocol.Formatters; using JT809.Protocol.MessagePack; +using System; namespace JT809.Protocol { @@ -12,6 +14,12 @@ namespace JT809.Protocol /// public const int FixedByteLength = 22; /// + /// 2019版本固定为30个字节长度 + /// MSG LENGTH + MSG_SN + MSG_ID + MSG_GNSSCENTERID + VERSION_FLAG + ENCRYPT_FLAG + ENCRYPT_KEY+TIME + /// 4 + 4 + 2 + 4 + 3 + 1 + 4 +8 = 30 + /// + public const int FixedByteLength_2019 = 30; + /// /// 数据长度(包括头标识、数据头、数据体和尾标识) /// 头标识 + 数据头 + 数据体 + 尾标识 /// 1 + 22 + n + 1 @@ -44,6 +52,10 @@ namespace JT809.Protocol /// 数据加密的密匙,长度为 4 个字节 /// public uint EncryptKey { get; set; } + /// + /// 发送消息时的系统UTC时间,长度为8个字节 + /// + public DateTime Time { get; set; } = DateTime.Now; public JT809Header Deserialize(ref JT809MessagePackReader reader, IJT809Config config) { @@ -55,6 +67,10 @@ namespace JT809.Protocol jT809Header.Version = new JT809Header_Version(reader.ReadArray(JT809Header_Version.FixedByteLength)); jT809Header.EncryptFlag = (JT809Header_Encrypt)reader.ReadByte(); jT809Header.EncryptKey = reader.ReadUInt32(); + if(config.Version== JT809Version.JTT2019) + { + Time = reader.ReadUTCDateTime(); + } return jT809Header; } @@ -67,6 +83,10 @@ namespace JT809.Protocol writer.WriteArray(value.Version.Buffer); writer.WriteByte((byte)value.EncryptFlag); writer.WriteUInt32(value.EncryptKey); + if (config.Version == JT809Version.JTT2019) + { + writer.WriteUTCDateTime(value.Time); + } } } } diff --git a/src/JT809.Protocol/JT809Package.cs b/src/JT809.Protocol/JT809Package.cs index 5c15cde..942adc4 100644 --- a/src/JT809.Protocol/JT809Package.cs +++ b/src/JT809.Protocol/JT809Package.cs @@ -2,12 +2,13 @@ using JT809.Protocol.Exceptions; using JT809.Protocol.Extensions; using JT809.Protocol.Formatters; +using JT809.Protocol.Interfaces; using JT809.Protocol.MessagePack; using System; namespace JT809.Protocol { - public class JT809Package:IJT809MessagePackFormatter + public class JT809Package:IJT809MessagePackFormatter, IJT809_2019_Version { public const byte BEGINFLAG = 0X5B; @@ -19,6 +20,12 @@ namespace JT809.Protocol /// 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; @@ -38,7 +45,7 @@ namespace JT809.Protocol // 1.2. 验证校验码 if (!reader.CheckXorCodeVali) { - throw new JT809Exception(JT809ErrorCode.CRC16CheckInvalid, $"{reader.CalculateCheckXorCode.ToString()}!={reader.RealCheckXorCode.ToString()}"); + throw new JT809Exception(JT809ErrorCode.CRC16CheckInvalid, $"{reader.CalculateCheckXorCode}!={reader.RealCheckXorCode}"); } } JT809Package jT809Package = new JT809Package(); @@ -52,12 +59,13 @@ namespace JT809.Protocol catch (Exception ex) { throw new JT809Exception(JT809ErrorCode.HeaderParseError, $"offset>{reader.ReadCurrentRemainContentLength()}", ex); - } + } // 5.数据体处理 // 5.1 判断是否有数据体(总长度-固定长度)> 0 - if ((jT809Package.Header.MsgLength - FixedByteLength) > 0) + int fixedByteLength = config.Version == JT809Version.JTT2019 ? FixedByteLength_2019 : FixedByteLength; + if ((jT809Package.Header.MsgLength - fixedByteLength) > 0) { - if (config.BusinessTypeFactory.TryGetValue(jT809Package.Header.BusinessType, out object instance)) + if (config.BusinessTypeFactory.TryGetValue(jT809Package.Header.BusinessType, config.Version, out object instance)) { try { @@ -82,6 +90,7 @@ namespace JT809.Protocol } } } + jT809Package.CRCCode = reader.CalculateCheckXorCode; jT809Package.EndFlag = reader.ReadEnd(); return jT809Package; @@ -108,6 +117,11 @@ namespace JT809.Protocol 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(); diff --git a/src/JT809.Protocol/MessageBody/JT809_0x1001.cs b/src/JT809.Protocol/MessageBody/JT809_0x1001.cs index d6b8f32..32f8c3a 100644 --- a/src/JT809.Protocol/MessageBody/JT809_0x1001.cs +++ b/src/JT809.Protocol/MessageBody/JT809_0x1001.cs @@ -1,6 +1,7 @@ using JT809.Protocol.Enums; using JT809.Protocol.Extensions; using JT809.Protocol.Formatters; +using JT809.Protocol.Interfaces; using JT809.Protocol.MessagePack; @@ -13,7 +14,7 @@ namespace JT809.Protocol.MessageBody /// 业务数据类型标识: UP-CONNECT-REQ /// 描述:下级平台向上级平台发送用户名和密码等登录信息 /// - public class JT809_0x1001: JT809Bodies,IJT809MessagePackFormatter + public class JT809_0x1001: JT809Bodies,IJT809MessagePackFormatter, IJT809_2019_Version { /// /// 用户名 @@ -25,6 +26,10 @@ namespace JT809.Protocol.MessageBody /// public string Password { get; set; } /// + /// 下级平台接入码 + /// + public uint MsgGNSSCENTERID { get; set; } + /// /// 下级平台提供对应的从链路服务端 IP 地址 /// 32位 /// @@ -45,6 +50,10 @@ namespace JT809.Protocol.MessageBody JT809_0x1001 jT809_0X1001 = new JT809_0x1001(); jT809_0X1001.UserId = reader.ReadUInt32(); jT809_0X1001.Password = reader.ReadString(8); + if(config.Version== JT809Version.JTT2019) + { + jT809_0X1001.MsgGNSSCENTERID = reader.ReadUInt32(); + } jT809_0X1001.DownLinkIP = reader.ReadString(32); jT809_0X1001.DownLinkPort = reader.ReadUInt16(); return jT809_0X1001; @@ -54,6 +63,10 @@ namespace JT809.Protocol.MessageBody { writer.WriteUInt32(value.UserId); writer.WriteStringPadRight(value.Password, 8); + if (config.Version == JT809Version.JTT2019) + { + writer.WriteUInt32(value.MsgGNSSCENTERID); + } writer.WriteStringPadRight(value.DownLinkIP, 32); writer.WriteUInt16(value.DownLinkPort); } diff --git a/src/JT809.Protocol/MessageBody/JT809_0x1002.cs b/src/JT809.Protocol/MessageBody/JT809_0x1002.cs index e701cf3..1944eb9 100644 --- a/src/JT809.Protocol/MessageBody/JT809_0x1002.cs +++ b/src/JT809.Protocol/MessageBody/JT809_0x1002.cs @@ -1,6 +1,7 @@ using JT809.Protocol.Enums; using JT809.Protocol.Extensions; using JT809.Protocol.Formatters; +using JT809.Protocol.Interfaces; using JT809.Protocol.MessagePack; using System; using System.Collections.Generic; @@ -15,7 +16,7 @@ namespace JT809.Protocol.MessageBody /// 业务数据类型标识:UP_CONNCCT_RSP /// 描述:上级平台对下级平台登录请求信息、进行安全验证后,返回相应的验证结果。 /// - public class JT809_0x1002 : JT809Bodies, IJT809MessagePackFormatter + public class JT809_0x1002 : JT809Bodies, IJT809MessagePackFormatter, IJT809_2019_Version { public override ushort MsgId => JT809BusinessType.主链路登录应答消息.ToUInt16Value(); diff --git a/src/JT809.Protocol/MessageBody/JT809_0x1102.cs b/src/JT809.Protocol/MessageBody/JT809_0x1102.cs new file mode 100644 index 0000000..772f517 --- /dev/null +++ b/src/JT809.Protocol/MessageBody/JT809_0x1102.cs @@ -0,0 +1,78 @@ +using JT809.Protocol.Enums; +using JT809.Protocol.Extensions; +using JT809.Protocol.Formatters; +using JT809.Protocol.MessagePack; +using JT809.Protocol.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.Protocol.MessageBody +{ + /// + /// 平台链路连接情况与车辆定位消息传输情况上报应答消息 + /// 链路类型:主链路 + /// 消息方向:上级平台往下级平台 + /// 业务类型标识:UP_MANAGE_MSG_RSP + /// + public class JT809_0x1102 : JT809ExchangeMessageBodies, IJT809MessagePackFormatter,IJT809_2019_Version + { + public override ushort MsgId => JT809BusinessType.平台链路连接情况与车辆定位消息传输情况上报应答消息_2019.ToUInt16Value(); + public override string Description => "平台链路连接情况与车辆定位消息传输情况上报应答消息"; + public override JT809_LinkType LinkType => JT809_LinkType.main; + + public override JT809Version Version => JT809Version.JTT2019; + + /// + /// 平台唯一编码 + /// + public string PlateformId { get; set; } + /// + /// 开始时间,用 UTC 时间表示 + /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. + /// + public DateTime StartTime { get; set; } + /// + /// 结束时间,用 UTC 时间表示 + /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. + /// + public DateTime EndTime { get; set; } + /// + /// START_TIME~END_TIME期间下级平台丢失得车辆定位消息总数 + /// + public uint LoseDymamicSum { get; set; } + /// + /// START_TIME~END_TIME期间下级监控平台链路断开次数 + /// + public byte DisconnectNum { get; set; } + /// + /// START_TIME~END_TIME期间下级监控平台链路断开总时长,用秒表示 + /// + public uint DisconnectTime { get; set; } + public JT809_0x1102 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) + { + JT809_0x1102 value = new JT809_0x1102(); + value.SubBusinessType = reader.ReadUInt16(); + value.DataLength = reader.ReadUInt32(); + value.PlateformId = reader.ReadBigNumber(11); + value.StartTime = reader.ReadUTCDateTime(); + value.EndTime = reader.ReadUTCDateTime(); + value.LoseDymamicSum = reader.ReadUInt32(); + value.DisconnectNum = reader.ReadByte(); + value.DisconnectTime = reader.ReadUInt32(); + return value; + } + + public void Serialize(ref JT809MessagePackWriter writer, JT809_0x1102 value, IJT809Config config) + { + writer.WriteUInt16(value.SubBusinessType); + writer.WriteUInt32(36); + writer.WriteBigNumber(value.PlateformId, 11); + writer.WriteUTCDateTime(value.StartTime); + writer.WriteUTCDateTime(value.EndTime); + writer.WriteUInt32(value.LoseDymamicSum); + writer.WriteByte(value.DisconnectNum); + writer.WriteUInt32(value.DisconnectTime); + } + } +} diff --git a/src/JT809.Protocol/MessageBody/JT809_0x1103.cs b/src/JT809.Protocol/MessageBody/JT809_0x1103.cs new file mode 100644 index 0000000..d36274e --- /dev/null +++ b/src/JT809.Protocol/MessageBody/JT809_0x1103.cs @@ -0,0 +1,61 @@ +using JT809.Protocol.Enums; +using JT809.Protocol.Extensions; +using JT809.Protocol.Formatters; +using JT809.Protocol.MessagePack; +using JT809.Protocol.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; +using JT809.Protocol.Metadata; + +namespace JT809.Protocol.MessageBody +{ + /// + /// 上传平台间消息序列号通知消息 + /// 链路类型:主链路 + /// 消息方向:上级平台往下级平台 + /// 业务类型标识:UP_MANAGE_MSG_SN_INFORM + /// + public class JT809_0x1103 : JT809ExchangeMessageBodies, IJT809MessagePackFormatter,IJT809_2019_Version + { + public override ushort MsgId => JT809BusinessType.上传平台间消息序列号通知消息_2019.ToUInt16Value(); + public override string Description => "上传平台间消息序列号通知消息"; + public override JT809_LinkType LinkType => JT809_LinkType.main; + public override JT809Version Version => JT809Version.JTT2019; + + public List ManageMsgSNInform { get; set; } = new List(); + public byte Count { get; set; } + + public JT809_0x1103 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) + { + JT809_0x1103 value = new JT809_0x1103(); + value.SubBusinessType = reader.ReadUInt16(); + value.DataLength = reader.ReadUInt32(); + value.Count = reader.ReadByte(); + for(int i=0;i < value.Count; i++) + { + JT809ManageMsgSNInform item = new JT809ManageMsgSNInform(); + item.SubBusinessType = reader.ReadUInt16(); + item.MsgSN = reader.ReadUInt32(); + item.Time = reader.ReadUTCDateTime(); + value.ManageMsgSNInform.Add(item); + } + return value; + } + + public void Serialize(ref JT809MessagePackWriter writer, JT809_0x1103 value, IJT809Config config) + { + writer.WriteUInt16(value.SubBusinessType); + // 先写入内容,然后在根据内容反写内容长度 + writer.Skip(4, out int subContentLengthPosition); + writer.WriteByte((byte)value.ManageMsgSNInform.Count); + foreach(var item in value.ManageMsgSNInform) + { + writer.WriteUInt16(item.SubBusinessType); + writer.WriteUInt32(item.MsgSN); + writer.WriteUTCDateTime(item.Time); + } + writer.WriteInt32Return(writer.GetCurrentPosition() - subContentLengthPosition - 4, subContentLengthPosition); + } + } +} diff --git a/src/JT809.Protocol/MessageBody/JT809_0x9101.cs b/src/JT809.Protocol/MessageBody/JT809_0x9101.cs index ec31bed..16e3e58 100644 --- a/src/JT809.Protocol/MessageBody/JT809_0x9101.cs +++ b/src/JT809.Protocol/MessageBody/JT809_0x9101.cs @@ -29,26 +29,26 @@ namespace JT809.Protocol.MessageBody /// 开始时间,用 UTC 时间表示 /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. /// - public ulong StartTime { get; set; } + public DateTime StartTime { get; set; } /// /// 结束时间,用 UTC 时间表示 /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. /// - public ulong EndTime { get; set; } + public DateTime EndTime { get; set; } public JT809_0x9101 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) { - JT809_0x9101 jT809_0X9101 = new JT809_0x9101(); - jT809_0X9101.DynamicInfoTotal = reader.ReadUInt32(); - jT809_0X9101.StartTime = reader.ReadUInt64(); - jT809_0X9101.EndTime = reader.ReadUInt64(); - return jT809_0X9101; + JT809_0x9101 value = new JT809_0x9101(); + value.DynamicInfoTotal = reader.ReadUInt32(); + value.StartTime = reader.ReadUTCDateTime(); + value.EndTime = reader.ReadUTCDateTime(); + return value; } public void Serialize(ref JT809MessagePackWriter writer, JT809_0x9101 value, IJT809Config config) { writer.WriteUInt32(value.DynamicInfoTotal); - writer.WriteUInt64(value.StartTime); - writer.WriteUInt64(value.EndTime); + writer.WriteUTCDateTime(value.StartTime); + writer.WriteUTCDateTime(value.EndTime); } } } diff --git a/src/JT809.Protocol/MessageBody/JT809_0x9102.cs b/src/JT809.Protocol/MessageBody/JT809_0x9102.cs new file mode 100644 index 0000000..854b8d4 --- /dev/null +++ b/src/JT809.Protocol/MessageBody/JT809_0x9102.cs @@ -0,0 +1,60 @@ +using JT809.Protocol.Enums; +using JT809.Protocol.Extensions; +using JT809.Protocol.Formatters; +using JT809.Protocol.MessagePack; +using JT809.Protocol.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.Protocol.MessageBody +{ + /// + /// 平台链路连接情况与车辆定位消息传输情况上报请求消息 + /// 链路类型:从链路 + /// 消息方向:上级平台往下级平台 + /// 业务类型标识:DOWN_MANAGE_MSG_REQ + /// + public class JT809_0x9102 : JT809ExchangeMessageBodies, IJT809MessagePackFormatter,IJT809_2019_Version + { + public override ushort MsgId => JT809BusinessType.平台链路连接情况与车辆定位消息传输情况上报请求消息_2019.ToUInt16Value(); + public override string Description => "平台链路连接情况与车辆定位消息传输情况上报请求消息"; + public override JT809_LinkType LinkType => JT809_LinkType.subordinate; + + public override JT809Version Version => JT809Version.JTT2019; + + /// + /// 平台唯一编码 + /// + public string PlateformId { get; set; } + /// + /// 开始时间,用 UTC 时间表示 + /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. + /// + public DateTime StartTime { get; set; } + /// + /// 结束时间,用 UTC 时间表示 + /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. + /// + public DateTime EndTime { get; set; } + public JT809_0x9102 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) + { + JT809_0x9102 value = new JT809_0x9102(); + value.SubBusinessType = reader.ReadUInt16(); + value.DataLength = reader.ReadUInt32(); + value.PlateformId = reader.ReadBigNumber(11); + value.StartTime = reader.ReadUTCDateTime(); + value.EndTime = reader.ReadUTCDateTime(); + return value; + } + + public void Serialize(ref JT809MessagePackWriter writer, JT809_0x9102 value, IJT809Config config) + { + writer.WriteUInt16(value.SubBusinessType); + writer.WriteUInt32(27); + writer.WriteBigNumber(value.PlateformId, 11); + writer.WriteUTCDateTime(value.StartTime); + writer.WriteUTCDateTime(value.EndTime); + } + } +} diff --git a/src/JT809.Protocol/MessageBody/JT809_0x9103.cs b/src/JT809.Protocol/MessageBody/JT809_0x9103.cs new file mode 100644 index 0000000..83024fe --- /dev/null +++ b/src/JT809.Protocol/MessageBody/JT809_0x9103.cs @@ -0,0 +1,61 @@ +using JT809.Protocol.Enums; +using JT809.Protocol.Extensions; +using JT809.Protocol.Formatters; +using JT809.Protocol.MessagePack; +using JT809.Protocol.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; +using JT809.Protocol.Metadata; + +namespace JT809.Protocol.MessageBody +{ + /// + /// 下发平台间消息序列号通知消息 + /// 链路类型:从链路 + /// 消息方向:上级平台往下级平台 + /// 业务类型标识:DOWN_MANAGE_MSG_SN_INFORM + /// + public class JT809_0x9103 : JT809ExchangeMessageBodies, IJT809MessagePackFormatter,IJT809_2019_Version + { + public override ushort MsgId => JT809BusinessType.下发平台间消息序列号通知消息_2019.ToUInt16Value(); + public override string Description => "下发平台间消息序列号通知消息"; + public override JT809_LinkType LinkType => JT809_LinkType.subordinate; + public override JT809Version Version => JT809Version.JTT2019; + + public List ManageMsgSNInform { get; set; } = new List(); + public byte Count { get; set; } + + public JT809_0x9103 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) + { + JT809_0x9103 value = new JT809_0x9103(); + value.SubBusinessType = reader.ReadUInt16(); + value.DataLength = reader.ReadUInt32(); + value.Count = reader.ReadByte(); + for(int i=0;i < value.Count; i++) + { + JT809ManageMsgSNInform item = new JT809ManageMsgSNInform(); + item.SubBusinessType = reader.ReadUInt16(); + item.MsgSN = reader.ReadUInt32(); + item.Time = reader.ReadUTCDateTime(); + value.ManageMsgSNInform.Add(item); + } + return value; + } + + public void Serialize(ref JT809MessagePackWriter writer, JT809_0x9103 value, IJT809Config config) + { + writer.WriteUInt16(value.SubBusinessType); + // 先写入内容,然后在根据内容反写内容长度 + writer.Skip(4, out int subContentLengthPosition); + writer.WriteByte((byte)value.ManageMsgSNInform.Count); + foreach(var item in value.ManageMsgSNInform) + { + writer.WriteUInt16(item.SubBusinessType); + writer.WriteUInt32(item.MsgSN); + writer.WriteUTCDateTime(item.Time); + } + writer.WriteInt32Return(writer.GetCurrentPosition() - subContentLengthPosition - 4, subContentLengthPosition); + } + } +} diff --git a/src/JT809.Protocol/MessageBody/JT809_2019_0x9101.cs b/src/JT809.Protocol/MessageBody/JT809_2019_0x9101.cs new file mode 100644 index 0000000..a4286af --- /dev/null +++ b/src/JT809.Protocol/MessageBody/JT809_2019_0x9101.cs @@ -0,0 +1,56 @@ +using JT809.Protocol.Enums; +using JT809.Protocol.Extensions; +using JT809.Protocol.Formatters; +using JT809.Protocol.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.Protocol.MessageBody +{ + /// + /// 发送车辆定位信息数据量通知消息 + /// 链路类型:主链路 + /// 消息方向:下级平台往上级平台 + /// 业务类型标识: DOWN_TOTAL_RECV_BACK_MSG + /// 描述:下级平台向上级平台定量通知已经上传的车辆定位信息数量(如:每收到10,000 条车辆定位信息通知一次) + /// 本条消息不需下级平台应答。 + /// + public class JT809_2019_0x9101 : JT809Bodies, IJT809MessagePackFormatter + { + public override ushort MsgId => JT809BusinessType.发送车辆定位信息数据量通知消息_2019.ToUInt16Value(); + public override string Description => "发送车辆定位信息数据量通知消息"; + public override JT809_LinkType LinkType => JT809_LinkType.main; + public override JT809Version Version => JT809Version.JTT2019; + + /// + /// START_TIME_END_TIME共收到的车辆定位信息数量 + /// + public uint DynamicInfoTotal { get; set; } + /// + /// 开始时间,用 UTC 时间表示 + /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. + /// + public ulong StartTime { get; set; } + /// + /// 结束时间,用 UTC 时间表示 + /// 注:采用 UTC 时间表示,如 2010-1-10 9:7:54 的 UTC 值为 1263085674,其在协议中表示为0x000000004B49286A. + /// + public ulong EndTime { get; set; } + public JT809_2019_0x9101 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) + { + JT809_2019_0x9101 value = new JT809_2019_0x9101(); + value.DynamicInfoTotal = reader.ReadUInt32(); + value.StartTime = reader.ReadUInt64(); + value.EndTime = reader.ReadUInt64(); + return value; + } + + public void Serialize(ref JT809MessagePackWriter writer, JT809_2019_0x9101 value, IJT809Config config) + { + writer.WriteUInt32(value.DynamicInfoTotal); + writer.WriteUInt64(value.StartTime); + writer.WriteUInt64(value.EndTime); + } + } +} diff --git a/src/JT809.Protocol/Metadata/JT809ManageMsgSNInform.cs b/src/JT809.Protocol/Metadata/JT809ManageMsgSNInform.cs new file mode 100644 index 0000000..470ffb6 --- /dev/null +++ b/src/JT809.Protocol/Metadata/JT809ManageMsgSNInform.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.Protocol.Metadata +{ + public class JT809ManageMsgSNInform + { + /// + /// 子业务类型标识 + /// + public ushort SubBusinessType { get; set; } + /// + /// 对应得子夜吴数据类型报文序列号 + /// + public uint MsgSN { get; set; } + /// + /// 系统UTC时间 + /// + public DateTime Time { get; set; } + } +} diff --git a/src/JT809.Protocol/SubMessageBody/JT809_0x1200_0x1201.cs b/src/JT809.Protocol/SubMessageBody/JT809_0x1200_0x1201.cs index 4d43d15..8a75e8f 100644 --- a/src/JT809.Protocol/SubMessageBody/JT809_0x1200_0x1201.cs +++ b/src/JT809.Protocol/SubMessageBody/JT809_0x1200_0x1201.cs @@ -2,16 +2,17 @@ using JT809.Protocol.Formatters; using JT809.Protocol.MessagePack; using JT809.Protocol.Extensions; +using JT809.Protocol.Interfaces; namespace JT809.Protocol.SubMessageBody { /// /// 上传车辆注册信息消息 - /// 子业务类型标识:UP_ EXG_ MSG_ REGISTER + /// 子业务类型标识:UP_EXG_MSG_REGISTER /// 描述:监控平台收到车载终端鉴权信息后,启动本命令向上级监管平台上传该车辆注册信息.各级监管平台再逐级向上级平台上传该信息 /// 本条消息服务端无需应答 /// - public class JT809_0x1200_0x1201:JT809SubBodies, IJT809MessagePackFormatter + public class JT809_0x1200_0x1201:JT809SubBodies, IJT809MessagePackFormatter, IJT809_2019_Version { public override ushort SubMsgId => JT809SubBusinessType.上传车辆注册信息.ToUInt16Value(); @@ -30,6 +31,11 @@ namespace JT809.Protocol.SubMessageBody /// public string TerminalModelType { get; set; } /// + /// 车载终端通讯模块IMEI码 + /// 2019版本 + /// + public string IMIEId { get; set; } + /// /// 车载终端编号,大写字母和数字组成 /// public string TerminalId { get; set; } @@ -40,23 +46,48 @@ namespace JT809.Protocol.SubMessageBody public JT809_0x1200_0x1201 Deserialize(ref JT809MessagePackReader reader, IJT809Config config) { - JT809_0x1200_0x1201 jT809_0X1200_0X1201 = new JT809_0x1200_0x1201(); - jT809_0X1200_0X1201.PlateformId = reader.ReadBigNumber(11); - jT809_0X1200_0X1201.ProducerId = reader.ReadBigNumber(11); - jT809_0X1200_0X1201.TerminalModelType = reader.ReadString(20); - jT809_0X1200_0X1201.TerminalId = reader.ReadString(7); - jT809_0X1200_0X1201.TerminalId = jT809_0X1200_0X1201.TerminalId.ToUpper(); - jT809_0X1200_0X1201.TerminalSimCode = reader.ReadString(12); - return jT809_0X1200_0X1201; + JT809_0x1200_0x1201 value = new JT809_0x1200_0x1201(); + if(config.Version== JT809Version.JTT2013) + { + value.PlateformId = reader.ReadBigNumber(11); + value.ProducerId = reader.ReadBigNumber(11); + value.TerminalModelType = reader.ReadString(20); + value.TerminalId = reader.ReadString(7); + value.TerminalId = value.TerminalId.ToUpper(); + value.TerminalSimCode = reader.ReadString(12); + } + else + { + value.PlateformId = reader.ReadBigNumber(11); + value.ProducerId = reader.ReadBigNumber(11); + value.TerminalModelType = reader.ReadString(30); + value.IMIEId = reader.ReadString(15); + value.TerminalId = reader.ReadString(30); + value.TerminalId = value.TerminalId.ToUpper(); + value.TerminalSimCode = reader.ReadString(13); + } + return value; } public void Serialize(ref JT809MessagePackWriter writer, JT809_0x1200_0x1201 value, IJT809Config config) { - writer.WriteBigNumber(value.PlateformId, 11); - writer.WriteBigNumber(value.ProducerId, 11); - writer.WriteStringPadRight(value.TerminalModelType, 20); - writer.WriteStringPadRight(value.TerminalId.ToUpper(), 7); - writer.WriteStringPadRight(value.TerminalSimCode, 12); + if(config.Version== JT809Version.JTT2013) + { + writer.WriteBigNumber(value.PlateformId, 11); + writer.WriteBigNumber(value.ProducerId, 11); + writer.WriteStringPadRight(value.TerminalModelType, 20); + writer.WriteStringPadRight(value.TerminalId.ToUpper(), 7); + writer.WriteStringPadLeft(value.TerminalSimCode, 12); + } + else + { + writer.WriteBigNumber(value.PlateformId, 11); + writer.WriteBigNumber(value.ProducerId, 11); + writer.WriteStringPadRight(value.TerminalModelType, 30); + writer.WriteStringPadRight(value.IMIEId, 15); + writer.WriteStringPadRight(value.TerminalId.ToUpper(), 30); + writer.WriteStringPadLeft(value.TerminalSimCode, 13); + } } } }