diff --git a/README.md b/README.md index 5516b31..05ffdd2 100644 --- a/README.md +++ b/README.md @@ -290,6 +290,13 @@ JT808Serializer DT2JT808Serializer = new JT808Serializer(DT2JT808Config); [可以参考Simples的Demo9](https://github.com/SmallChi/JT808/blob/master/src/JT808.Protocol.Test/Simples/Demo9.cs) +### 举个栗子10 + +场景: +有些设备,不会按照国标的附加信息Id来搞,把附加信息Id搞为两个字节,这样在上报上来的数据就会存在重复的附加Id,导致平台解析出错。 + +[可以参考Simples的Demo10](https://github.com/SmallChi/JT808/blob/master/src/JT808.Protocol.Test/Simples/Demo10.cs) + ## NuGet安装 | Package Name | Version | Downloads | diff --git a/src/JT808.Protocol.Test/MessageBody/JT808_0x0100Test.cs b/src/JT808.Protocol.Test/MessageBody/JT808_0x0100Test.cs index ca8441b..8925a07 100644 --- a/src/JT808.Protocol.Test/MessageBody/JT808_0x0100Test.cs +++ b/src/JT808.Protocol.Test/MessageBody/JT808_0x0100Test.cs @@ -54,13 +54,6 @@ namespace JT808.Protocol.Test.MessageBody Assert.Equal("smallchi123000000000", JT808Bodies.TerminalModel); } - [Fact] - public void Test1_2() - { - byte[] bytes = "7E01000022040666575073004A00000000373231303447354C00000000003430363636353702D5E3483137323030000F7E".ToHexBytes(); - string json = JT808Serializer.Analyze(bytes); - } - [Fact] public void Test2019_1() { diff --git a/src/JT808.Protocol.Test/MessageBody/JT808_0x0200Test.cs b/src/JT808.Protocol.Test/MessageBody/JT808_0x0200Test.cs index b04364a..3e2f102 100644 --- a/src/JT808.Protocol.Test/MessageBody/JT808_0x0200Test.cs +++ b/src/JT808.Protocol.Test/MessageBody/JT808_0x0200Test.cs @@ -18,13 +18,18 @@ namespace JT808.Protocol.Test.MessageBody public class JT808_0x0200Test { JT808Serializer JT808Serializer; + JT808Serializer JT808Serializer1; public JT808_0x0200Test() { IJT808Config jT808Config = new DefaultGlobalConfig(); + IJT808Config jT808Config1 = new DefaultGlobalConfig(); + jT808Config1.SkipCRCCode = true; jT808Config.JT808_0X0200_Custom_Factory.SetMap(); JT808Serializer = new JT808Serializer(jT808Config); + JT808Serializer1 = new JT808Serializer(jT808Config1); } + [Fact] public void Test1() { @@ -337,6 +342,52 @@ namespace JT808.Protocol.Test.MessageBody string json = JT808Serializer.Analyze(bodys); } + [Fact] + public void Test7() + { + //"附加信息列表": [ + // { + // "[01]附加信息Id": 1, + // "[04]附加信息长度": 4, + // "[000024C7]里程": 9415 + // }, + // { + // "[2B]附加信息Id": 43, + // "[04]附加信息长度": 4, + // "[0B290B29]模拟量": 187239209 + // }, + // { + // "[30]附加信息Id": 48, + // "[01]附加信息长度": 1, + // "[17]无线通信网络信号强度": 23 + // }, + // { + // "[31]附加信息Id": 49, + // "[01]附加信息长度": 1, + // "[1B]GNSS定位卫星数": 27 + // }, + // { + // "[00]未知附加信息Id": 0, 坑爹,相同的 + // "[04]未知附加信息长度": 4, + // "未知附加信息": "000400CE0B29" + // }, + // { + // "[00]未知附加信息Id": 0, 坑爹,相同的 + // "[0C]未知附加信息长度": 12, + // "未知附加信息": "000C00B289860620150013559848" + // }, + // { + // "[EB]未知附加信息Id": 235, + // "[0E]未知附加信息长度": 14, + // "未知附加信息": "EB0E000C00B289860620150013559848" + // } + //] + byte[] bodys = "7E020000520111111111100002000000000000000301789B3406238AFA0000018B00F62104020046090104000024C72B040B290B2930011731011B000400CE0B29000C00B289860620150013559848EB0E000C00B2898606201500135598486C7E".ToHexBytes(); + var package = JT808Serializer1.Deserialize(bodys); + JT808_0x0200 jT808UploadLocationRequest = (JT808_0x0200)package.Bodies; + Assert.Single(jT808UploadLocationRequest.ExceptionLocationAttachOriginalData); + } + [Fact] public void Test_all_attcahids() { diff --git a/src/JT808.Protocol.Test/Simples/Demo10.cs b/src/JT808.Protocol.Test/Simples/Demo10.cs new file mode 100644 index 0000000..79c6ca8 --- /dev/null +++ b/src/JT808.Protocol.Test/Simples/Demo10.cs @@ -0,0 +1,124 @@ +using JT808.Protocol.Enums; +using JT808.Protocol.Interfaces; +using JT808.Protocol.Internal; +using JT808.Protocol.Extensions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; +using JT808.Protocol.MessageBody; +using JT808.Protocol.Formatters; +using JT808.Protocol.MessagePack; +using System.Text.Json; +using JT808.Protocol.MessageBody.CarDVR; + +namespace JT808.Protocol.Test.Simples +{ + public class Demo10 + { + JT808Serializer JT808Serializer; + + public Demo10() + { + IJT808Config jT808Config = new DefaultGlobalConfig(); + jT808Config.JT808_0X0200_Custom_Factory.SetMap(); + JT808Serializer = new JT808Serializer(jT808Config); + } + + [Fact] + public void Test1() + { + JT808_0x0200 jT808UploadLocationRequest = new JT808_0x0200 + { + AlarmFlag = 1, + Altitude = 40, + GPSTime = DateTime.Parse("2021-04-03 11:10:10"), + Lat = 12222222, + Lng = 132444444, + Speed = 60, + Direction = 0, + StatusFlag = 2, + JT808CustomLocationAttachData = new Dictionary(), + ExceptionLocationAttachData = new List() + }; + jT808UploadLocationRequest.JT808CustomLocationAttachData.Add(0x00, new JT808LocationAttachImpl0x00 + { + TestValue=new byte[] {0,1,2,3} + }); + jT808UploadLocationRequest.ExceptionLocationAttachData.Add(new JT808LocationAttachImpl0x00 + { + TestId= "012345678912" + }); + var hex = JT808Serializer.Serialize(jT808UploadLocationRequest).ToHexString(); + Assert.Equal("000000010000000200BA7F0E07E4F11C0028003C0000210403111010000400010203000C303132333435363738393132", hex); + } + + [Fact] + public void Test1_1() + { + byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C0000210403111010000400010203000C303132333435363738393132".ToHexBytes(); + JT808_0x0200 jT808UploadLocationRequest = JT808Serializer.Deserialize(bodys); + Assert.Equal((uint)1, jT808UploadLocationRequest.AlarmFlag); + Assert.Equal(DateTime.Parse("2021-04-03 11:10:10"), jT808UploadLocationRequest.GPSTime); + Assert.Equal(12222222, jT808UploadLocationRequest.Lat); + Assert.Equal(132444444, jT808UploadLocationRequest.Lng); + Assert.Equal(60, jT808UploadLocationRequest.Speed); + Assert.Equal((uint)2, jT808UploadLocationRequest.StatusFlag); + Assert.Equal(new byte[] { 0, 1, 2, 3 }, ((JT808LocationAttachImpl0x00)jT808UploadLocationRequest.JT808CustomLocationAttachData[0x00]).TestValue); + Assert.Equal("012345678912", ((JT808LocationAttachImpl0x00)jT808UploadLocationRequest.ExceptionLocationAttachData[0]).TestId); + } + } + + public class JT808LocationAttachImpl0x00 : JT808_0x0200_CustomBodyBase, IJT808MessagePackFormatter + { + /// + /// 附加Id 0x00 + /// + public override byte AttachInfoId { get; set; } = 0x00; + /// + /// 不固定 + /// + public override byte AttachInfoLength { get; set; } + /// + /// 只能存在一个 AttachInfoLength == 12 + /// + public string TestId { get; set; } + + /// + /// 只能存在一个 AttachInfoLength == 4 + /// + public byte[] TestValue { get; set; } + + public JT808LocationAttachImpl0x00 Deserialize(ref JT808MessagePackReader reader, IJT808Config config) + { + JT808LocationAttachImpl0x00 jT808LocationAttachImpl0X00 = new JT808LocationAttachImpl0x00(); + jT808LocationAttachImpl0X00.AttachInfoId = reader.ReadByte(); + jT808LocationAttachImpl0X00.AttachInfoLength = reader.ReadByte(); + if (jT808LocationAttachImpl0X00.AttachInfoLength == 12) + { + jT808LocationAttachImpl0X00.TestId = reader.ReadString(12); + } + else if(jT808LocationAttachImpl0X00.AttachInfoLength == 4) + { + jT808LocationAttachImpl0X00.TestValue = reader.ReadArray(4).ToArray(); + } + return jT808LocationAttachImpl0X00; + } + + public void Serialize(ref JT808MessagePackWriter writer, JT808LocationAttachImpl0x00 value, IJT808Config config) + { + writer.WriteByte(value.AttachInfoId); + if (!string.IsNullOrEmpty(value.TestId)) + { + writer.WriteByte(12); + writer.WriteString(value.TestId.ValiString(nameof(TestId), 12)); + } + else if (value.TestValue != null) + { + writer.WriteByte(4); + writer.WriteArray(value.TestValue.ValiBytes(nameof(TestValue), 4)); + } + } + } +} diff --git a/src/JT808.Protocol/JT808.Protocol.csproj b/src/JT808.Protocol/JT808.Protocol.csproj index 83f755c..6b24e4c 100644 --- a/src/JT808.Protocol/JT808.Protocol.csproj +++ b/src/JT808.Protocol/JT808.Protocol.csproj @@ -15,7 +15,7 @@ https://github.com/SmallChi/JT808/blob/master/LICENSE JT808.Protocol.xml false - 2.3.6 + 2.3.7 LICENSE latest true diff --git a/src/JT808.Protocol/JT808.Protocol.xml b/src/JT808.Protocol/JT808.Protocol.xml index 3bc4fd4..581be6c 100644 --- a/src/JT808.Protocol/JT808.Protocol.xml +++ b/src/JT808.Protocol/JT808.Protocol.xml @@ -8879,6 +8879,34 @@ 依赖平台录入的设备类型 + + + 有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。 + 形如: + 00 0C 这个是长度 + 00 B2 这个是长度 + 实际解析 + 00 附加信息Id + 0C 附加信息长度 + 00 附加信息Id + B2 附加信息长度 + 只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧 + + + + + 有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。 + 形如: + 00 0C 这个是长度 + 00 B2 这个是长度 + 实际解析 + 00 附加信息Id + 0C 附加信息长度 + 00 附加信息Id + B2 附加信息长度 + 只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧 + + diff --git a/src/JT808.Protocol/JT808Package.cs b/src/JT808.Protocol/JT808Package.cs index 1b8ce34..12ca5ab 100644 --- a/src/JT808.Protocol/JT808Package.cs +++ b/src/JT808.Protocol/JT808Package.cs @@ -294,7 +294,7 @@ namespace JT808.Protocol writer.WriteNumber($"[{protocolVersion.ReadNumber()}]协议版本号(2019)", protocolVersion); // 3.4.读取终端手机号 var terminalPhoneNo = reader.ReadBCD(20, config.Trim); - writer.WriteString($"[{terminalPhoneNo}]终端手机号", terminalPhoneNo); + writer.WriteString($"[{terminalPhoneNo.PadLeft(20,'0')}]终端手机号", terminalPhoneNo); } else { @@ -309,7 +309,7 @@ namespace JT808.Protocol // 3.3.读取终端手机号 var terminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, false); //消息体属性对象 结束 - writer.WriteString($"[{terminalPhoneNo}]终端手机号", terminalPhoneNo); + writer.WriteString($"[{terminalPhoneNo.PadLeft(config.TerminalPhoneNoLength, '0')}]终端手机号", terminalPhoneNo); } // 3.4.读取消息流水号 var msgNum = reader.ReadUInt16(); diff --git a/src/JT808.Protocol/MessageBody/JT808_0x0100.cs b/src/JT808.Protocol/MessageBody/JT808_0x0100.cs index e408814..6911a2f 100644 --- a/src/JT808.Protocol/MessageBody/JT808_0x0100.cs +++ b/src/JT808.Protocol/MessageBody/JT808_0x0100.cs @@ -147,7 +147,7 @@ namespace JT808.Protocol.MessageBody writer.WriteString($"[{tmSpan.ToArray().ToHexString()}]终端型号(30)", jT808_0X0100.TerminalModel); ReadOnlySpan tidSpan = reader.ReadVirtualArray(30); jT808_0X0100.TerminalId = reader.ReadString(30); - writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端型号(30)", jT808_0X0100.TerminalId); + writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端ID(30)", jT808_0X0100.TerminalId); } else { @@ -159,13 +159,13 @@ namespace JT808.Protocol.MessageBody writer.WriteString($"[{tmSpan.ToArray().ToHexString()}]终端型号(20)", jT808_0X0100.TerminalModel); ReadOnlySpan tidSpan = reader.ReadVirtualArray(7); jT808_0X0100.TerminalId = reader.ReadString(7); - writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端型号(7)", jT808_0X0100.TerminalId); + writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端ID(7)", jT808_0X0100.TerminalId); } jT808_0X0100.PlateColor = reader.ReadByte(); writer.WriteNumber($"[{jT808_0X0100.PlateColor.ReadNumber()}]车牌颜色", jT808_0X0100.PlateColor); ReadOnlySpan vnoSpan = reader.ReadVirtualArray(reader.ReadCurrentRemainContentLength()); jT808_0X0100.PlateNo = reader.ReadRemainStringContent(); - writer.WriteString($"[{vnoSpan.ToArray().ToHexString()}]车牌颜色", jT808_0X0100.PlateNo); + writer.WriteString($"[{vnoSpan.ToArray().ToHexString()}]车牌号码", jT808_0X0100.PlateNo); } } } diff --git a/src/JT808.Protocol/MessageBody/JT808_0x0200.cs b/src/JT808.Protocol/MessageBody/JT808_0x0200.cs index 44210b5..3beebaf 100644 --- a/src/JT808.Protocol/MessageBody/JT808_0x0200.cs +++ b/src/JT808.Protocol/MessageBody/JT808_0x0200.cs @@ -81,6 +81,32 @@ namespace JT808.Protocol.MessageBody /// public Dictionary JT808CustomLocationAttachData { get; set; } /// + /// 有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。 + /// 形如: + /// 00 0C 这个是长度 + /// 00 B2 这个是长度 + /// 实际解析 + /// 00 附加信息Id + /// 0C 附加信息长度 + /// 00 附加信息Id + /// B2 附加信息长度 + /// 只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧 + /// + public List ExceptionLocationAttachOriginalData { get; set; } + /// + /// 有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。 + /// 形如: + /// 00 0C 这个是长度 + /// 00 B2 这个是长度 + /// 实际解析 + /// 00 附加信息Id + /// 0C 附加信息长度 + /// 00 附加信息Id + /// B2 附加信息长度 + /// 只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧 + /// + public List ExceptionLocationAttachData { get; set; } + /// /// /// /// @@ -115,27 +141,57 @@ namespace JT808.Protocol.MessageBody jT808_0X0200.JT808LocationAttachData = new Dictionary(); jT808_0X0200.JT808CustomLocationAttachData = new Dictionary(); jT808_0X0200.JT808UnknownLocationAttachOriginalData = new Dictionary(); + jT808_0X0200.ExceptionLocationAttachOriginalData = new List(); + jT808_0X0200.ExceptionLocationAttachData = new List(); while (reader.ReadCurrentRemainContentLength() > 0) { try { ReadOnlySpan attachSpan = reader.GetVirtualReadOnlySpan(2); byte attachId = attachSpan[0]; - byte attachLen = attachSpan[1]; + byte attachLen = attachSpan[1]; if (config.JT808_0X0200_Factory.Map.TryGetValue(attachId, out object jT808LocationAttachInstance)) { - dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(jT808LocationAttachInstance, ref reader, config); - jT808_0X0200.JT808LocationAttachData.Add(attachImpl.AttachInfoId, attachImpl); + if (jT808_0X0200.JT808LocationAttachData.ContainsKey(attachId)) + { + //存在重复的就不解析,把数据统一放在异常定位数据里面 + reader.Skip(2); + jT808_0X0200.ExceptionLocationAttachOriginalData.Add(reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + reader.Skip(attachLen); + } + else + { + dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(jT808LocationAttachInstance, ref reader, config); + jT808_0X0200.JT808LocationAttachData.Add(attachImpl.AttachInfoId, attachImpl); + } } else if (config.JT808_0X0200_Custom_Factory.Map.TryGetValue(attachId,out object customAttachInstance)) { - dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(customAttachInstance, ref reader, config); - jT808_0X0200.JT808CustomLocationAttachData.Add(attachImpl.AttachInfoId, attachImpl); + if (jT808_0X0200.JT808CustomLocationAttachData.ContainsKey(attachId)) + { + //目前根据坑爹的协议只做了附加Id相同的情况下,长度不同的解析方式。 + //在已知的情况:附加Id相同,但是长度不同的时候,只能当做用长度来识别是对应的哪个,然后把数据剩下一个放在异常附加数据里面 + dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(customAttachInstance, ref reader, config); + jT808_0X0200.ExceptionLocationAttachData.Add(attachImpl); + } + else + { + dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(customAttachInstance, ref reader, config); + jT808_0X0200.JT808CustomLocationAttachData.Add(attachImpl.AttachInfoId, attachImpl); + } } else { reader.Skip(2); - jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + if (jT808_0X0200.JT808UnknownLocationAttachOriginalData.ContainsKey(attachId)) + { + //未知的情况下:存在重复的就不解析,把数据统一放在异常定位数据里面 + jT808_0X0200.ExceptionLocationAttachOriginalData.Add(reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + } + else + { + jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + } reader.Skip(attachLen); } } @@ -145,7 +201,15 @@ namespace JT808.Protocol.MessageBody { byte attachId = reader.ReadByte(); byte attachLen = reader.ReadByte(); - jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + if (jT808_0X0200.JT808UnknownLocationAttachOriginalData.ContainsKey(attachId)) + { + //未知的情况下:存在重复的就不解析,把数据统一放在异常定位数据里面 + jT808_0X0200.ExceptionLocationAttachOriginalData.Add(reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + } + else + { + jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray()); + } reader.Skip(attachLen); } catch (Exception ex) @@ -220,6 +284,13 @@ namespace JT808.Protocol.MessageBody JT808MessagePackFormatterResolverExtensions.JT808DynamicSerialize(item.Value, ref writer, item.Value, config); } } + if (value.ExceptionLocationAttachData != null && value.ExceptionLocationAttachData.Count > 0) + { + foreach (var item in value.ExceptionLocationAttachData) + { + JT808MessagePackFormatterResolverExtensions.JT808DynamicSerialize(item, ref writer, item, config); + } + } } /// ///