From 0c07eccf17a41b138d32376abbe9c177747d62a6 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Thu, 3 Jun 2021 15:30:15 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=AE=8C=E5=96=84=E7=BB=88=E7=AB=AF=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=91=BD=E4=BB=A4=E5=8F=82=E6=95=B0=E7=9A=84=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=8F=8A=E5=AF=B9=E5=BA=94=E7=9A=84=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=91=BD=E4=BB=A4=E5=8F=82=E6=95=B0=202.=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=9F=BA=E4=BA=8E=E7=BB=88=E7=AB=AF=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E5=8F=82=E6=95=B0=E7=9A=84demo13=203.?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 + .../MessageBody/JT808_0x8105Test.cs | 1 + src/JT808.Protocol.Test/Simples/Demo13.cs | 275 ++++++++++++++++++ ...JT808_0x8105_CommandParameterExtensions.cs | 4 +- .../Internal/JT808_0x8105_Cusotm_Factory.cs | 4 +- src/JT808.Protocol/JT808.Protocol.xml | 9 +- .../MessageBody/JT808_0x8105.cs | 26 +- 7 files changed, 314 insertions(+), 12 deletions(-) create mode 100644 src/JT808.Protocol.Test/Simples/Demo13.cs diff --git a/README.md b/README.md index e95ab28..dbef725 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,13 @@ JT808Serializer DT2JT808Serializer = new JT808Serializer(DT2JT808Config); >注意:只适用于已知的设备厂家协议才行 +### 举个栗子13 + +场景: +由于粤标的设备把2019版本的0x8105终端控制消息命令参数做了扩展,所以需要兼容。 + +[可以参考Simples的Demo13](https://github.com/SmallChi/JT808/blob/master/src/JT808.Protocol.Test/Simples/Demo13.cs) + ## NuGet安装 | Package Name| Version| Preview Version |Downloads|Remark| diff --git a/src/JT808.Protocol.Test/MessageBody/JT808_0x8105Test.cs b/src/JT808.Protocol.Test/MessageBody/JT808_0x8105Test.cs index ea3c5a5..0dc6094 100644 --- a/src/JT808.Protocol.Test/MessageBody/JT808_0x8105Test.cs +++ b/src/JT808.Protocol.Test/MessageBody/JT808_0x8105Test.cs @@ -9,6 +9,7 @@ namespace JT808.Protocol.Test.MessageBody public class JT808_0x8105Test { JT808Serializer JT808Serializer = new JT808Serializer(); + [Fact] public void Test1() { diff --git a/src/JT808.Protocol.Test/Simples/Demo13.cs b/src/JT808.Protocol.Test/Simples/Demo13.cs new file mode 100644 index 0000000..38b5e95 --- /dev/null +++ b/src/JT808.Protocol.Test/Simples/Demo13.cs @@ -0,0 +1,275 @@ +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; +using System.Linq; +using JT808.Protocol.Test.JT808LocationAttach; +using static JT808.Protocol.MessageBody.JT808_0x8105; +using System.Buffers.Binary; +using Newtonsoft.Json; + +namespace JT808.Protocol.Test.Simples +{ + public class Demo13 + { + JT808Serializer JT808Serializer; + + public Demo13() + { + IJT808Config jT808Config = new DefaultGlobalConfig(); + jT808Config.JT808_0x8105_Cusotm_Factory.SetMap(); + jT808Config.JT808_0x8105_Cusotm_Factory.SetMap(); + jT808Config.JT808_0x8105_Cusotm_Factory.SetMap(); + JT808Serializer = new JT808Serializer(jT808Config); + } + + [Fact] + public void Test1() + { + JT808Package jT808Package = new JT808Package + { + Header = new JT808Header + { + MsgId = Enums.JT808MsgId.终端控制.ToUInt16Value(), + ManualMsgNum = 1, + TerminalPhoneNo = "12345678900", + }, + Bodies = new JT808_0x8105 + { + CommandWord = 1, + CustomCommandParameters=new List + { + new Koike1CommandParameter + { + Value=23 + }, + new Koike2CommandParameter + { + Value="SmallChi" + }, + new Koike3CommandParameter + { + Value=new Koike3Object + { + Value1=0xff, + Value2="Happy" + } + } + } + } + }; + var hex = JT808Serializer.Serialize(jT808Package).ToHexString(); + Assert.Equal("7E8105002A0123456789000001013B3B3B3B3B3B3B3B3B3B3B3B3B000000173B536D616C6C43686900003BFF486170707900000000003B827E", hex); + } + + [Fact] + public void Test2() + { + byte[] bytes = "7E8105002A0123456789000001013B3B3B3B3B3B3B3B3B3B3B3B3B000000173B536D616C6C43686900003BFF486170707900000000003B827E".ToHexBytes(); + var jT808Package = JT808Serializer.Deserialize(bytes); + Assert.Equal(Enums.JT808MsgId.终端控制.ToUInt16Value(), jT808Package.Header.MsgId); + Assert.Equal(1, jT808Package.Header.MsgNum); + Assert.Equal("12345678900", jT808Package.Header.TerminalPhoneNo); + var JT808_0x8105 = (JT808_0x8105)jT808Package.Bodies; + Assert.Equal(1, JT808_0x8105.CommandWord); + Assert.Equal(23u, JT808_0x8105.CustomCommandParameters.GetCommandParameter().Value.Value); + Assert.Equal("SmallChi", JT808_0x8105.CustomCommandParameters.GetCommandParameter().Value); + Assert.Equal(new Koike3Object() + { + Value1 = 0xff, + Value2 = "Happy" + }, JT808_0x8105.CustomCommandParameters.GetCommandParameter().Value); + } + + [Fact] + public void Test3() + { + byte[] bytes = "7E8105002A0123456789000001013B3B3B3B3B3B3B3B3B3B3B3B3B000000173B536D616C6C43686900003BFF486170707900000000003B827E".ToHexBytes(); + var json = JT808Serializer.Analyze(bytes); + } + + [Fact] + public void Test4() + { + var ex= Assert.Throws(() => + { + IJT808Config jT808Config = new DefaultGlobalConfig(); + jT808Config.JT808_0x8105_Cusotm_Factory.SetMap(); + }); + Assert.Equal(ex.Message, $"{typeof(ErrorCommandParameter).FullName} Order is {3}. We're starting at 13 and we're incremying by 1."); + } + + /// + /// ICusotmCommandParameter 自定义命令参数接口 + /// ICommandParameterValue<> 对应的数据类型值 + /// 注意:Order必须从13开始逐一递增 + /// + public class Koike1CommandParameter : ICusotmCommandParameter, ICommandParameterValue + { + public int Order => 13; + + public string CommandName => "Koike1"; + + public uint? Value { get; set; } + + /// + /// + /// + /// + public byte[] ToBytes() + { + if (!Value.HasValue) return default; + var value = new byte[4]; + BinaryPrimitives.WriteUInt32BigEndian(value, Value.Value); + return value; + } + /// + /// + /// + /// + public void ToValue(byte[] bytes) + { + if (bytes != null && bytes.Length > 0) + { + Value = BinaryPrimitives.ReadUInt32BigEndian(bytes); + } + } + } + /// + /// ICusotmCommandParameter 自定义命令参数接口 + /// ICommandParameterValue<> 对应的数据类型值 + /// 注意:Order必须从13开始逐一递增 + /// + public class Koike2CommandParameter : ICusotmCommandParameter, ICommandParameterValue + { + public int Order => 14; + public string CommandName => "Koike2"; + public string Value { get; set; } + /// + /// + /// + /// + public byte[] ToBytes() + { + if (string.IsNullOrEmpty(Value)) return default; + return JT808Constants.Encoding.GetBytes(Value.PadRight(10, '\0')); + } + /// + /// + /// + /// + public void ToValue(byte[] bytes) + { + if (bytes != null && bytes.Length > 0) + { + Value = JT808Constants.Encoding.GetString(bytes).Trim('\0'); + } + } + } + /// + /// ICusotmCommandParameter 自定义命令参数接口 + /// ICommandParameterValue<> 对应的数据类型值 + /// 注意:Order必须从13开始逐一递增 + /// + public class Koike3CommandParameter : ICusotmCommandParameter, ICommandParameterValue + { + public int Order => 15; + public string CommandName => "Koike3"; + public Koike3Object Value { get; set; } + /// + /// + /// + /// + public byte[] ToBytes() + { + if (Value==null) return default; + return Value.ToBytes(); + } + /// + /// + /// + /// + public void ToValue(byte[] bytes) + { + if (bytes != null && bytes.Length > 0) + { + Value = new Koike3Object(); + Value.ToValue(bytes); + } + } + } + /// + /// Koike3为对象 + /// ICommandParameterConvert:命令参数转换 + /// ToString:为对象类型用于分析器自定义显示 + /// + public record Koike3Object : ICommandParameterConvert + { + public byte Value1 { get; set; } + public string Value2 { get; set; } + public byte[] ToBytes() + { + byte[] value = new byte[11]; + value[0] = Value1; + var val2 = JT808Constants.Encoding.GetBytes(Value2.PadRight(10, '\0')); + Array.Copy(val2, 0, value, 1, val2.Length); + return value; + } + public void ToValue(byte[] bytes) + { + if (bytes != null && bytes.Length > 0) + { + var val = bytes.AsSpan(); + Value1 = val[0]; + Value2 = JT808Constants.Encoding.GetString(val.Slice(1)).Trim('\0'); + } + } + /// + /// 用于分析器描述 + /// + /// + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } + } + + /// + /// ICusotmCommandParameter 自定义命令参数接口 + /// ICommandParameterValue<> 对应的数据类型值 + /// 注意:Order必须从13开始逐一递增 + /// + public class ErrorCommandParameter : ICusotmCommandParameter, ICommandParameterValue + { + public int Order => 3; + public string CommandName => "Error"; + public bool Value { get; set; } + /// + /// + /// + /// + public byte[] ToBytes() + { + return default; + } + /// + /// + /// + /// + public void ToValue(byte[] bytes) + { + + } + } + } +} diff --git a/src/JT808.Protocol/Extensions/JT808_0x8105_CommandParameterExtensions.cs b/src/JT808.Protocol/Extensions/JT808_0x8105_CommandParameterExtensions.cs index 010e08f..194e600 100644 --- a/src/JT808.Protocol/Extensions/JT808_0x8105_CommandParameterExtensions.cs +++ b/src/JT808.Protocol/Extensions/JT808_0x8105_CommandParameterExtensions.cs @@ -85,9 +85,9 @@ namespace JT808.Protocol.Extensions { var name = nameof(ICommandParameterValue.Value); var property = commandParameter.GetType().GetProperty(name); - if (property == null) return default; + if (property == null) return "空值"; var value= property.GetValue(commandParameter); - if (value == null) return default; + if (value == null) return "空值"; return value.ToString(); } } diff --git a/src/JT808.Protocol/Internal/JT808_0x8105_Cusotm_Factory.cs b/src/JT808.Protocol/Internal/JT808_0x8105_Cusotm_Factory.cs index 0a5b210..3397dbe 100644 --- a/src/JT808.Protocol/Internal/JT808_0x8105_Cusotm_Factory.cs +++ b/src/JT808.Protocol/Internal/JT808_0x8105_Cusotm_Factory.cs @@ -47,11 +47,11 @@ namespace JT808.Protocol.Internal var order = (int)type.GetProperty(nameof(ICusotmCommandParameter.Order)).GetValue(instance); if(order < CommandParameterCount) { - throw new ArgumentException($"{type.FullName} {order} We're starting at 13 and we're incremying by 1."); + throw new ArgumentException($"{type.FullName} Order is {order}. We're starting at 13 and we're incremying by 1."); } if (Map.ContainsKey(order)) { - throw new ArgumentException($"{type.FullName} {order} An element with the same Order already exists."); + throw new ArgumentException($"{type.FullName} Order is {order}. An element with the same Order already exists."); } else { diff --git a/src/JT808.Protocol/JT808.Protocol.xml b/src/JT808.Protocol/JT808.Protocol.xml index a1f9d9c..ceb5f7e 100644 --- a/src/JT808.Protocol/JT808.Protocol.xml +++ b/src/JT808.Protocol/JT808.Protocol.xml @@ -15340,13 +15340,18 @@ 命令名称 - + + + 命令参数值的转换 + + + 转为byte数组 - + 将byte数组转为命令值 diff --git a/src/JT808.Protocol/MessageBody/JT808_0x8105.cs b/src/JT808.Protocol/MessageBody/JT808_0x8105.cs index b3cad24..6bee7db 100644 --- a/src/JT808.Protocol/MessageBody/JT808_0x8105.cs +++ b/src/JT808.Protocol/MessageBody/JT808_0x8105.cs @@ -129,12 +129,12 @@ namespace JT808.Protocol.MessageBody writer.WriteByte(value.CommandWord); if (value.CommandWord == 1 || value.CommandWord == 2) { - if (CommandParameters != null && CommandParameters.Count > 0) + if (value.CommandParameters != null && value.CommandParameters.Count > 0) { //由于标准的命令参数是有顺序的,所以先判断有几个标准的命令参数 for (int i = 0; i < CommandParameterCount; i++) { - var cmd = CommandParameters.FirstOrDefault(f => f.Order == i); + var cmd = value.CommandParameters.FirstOrDefault(f => f.Order == i); if (cmd != null) { writer.WriteArray(cmd.ToBytes()); @@ -146,10 +146,17 @@ namespace JT808.Protocol.MessageBody } } } - if (CustomCommandParameters != null && CustomCommandParameters.Count > 0) + else + { + for (int i = 0; i < CommandParameterCount; i++) + { + writer.WriteChar(CommandParameterSeparator); + } + } + if (value.CustomCommandParameters != null && value.CustomCommandParameters.Count > 0) { //自定义命令参数扩展 - foreach (var cmd in CustomCommandParameters.OrderBy(o => o.Order)) + foreach (var cmd in value.CustomCommandParameters.OrderBy(o => o.Order)) { var bytes = cmd.ToBytes(); if (bytes != null && bytes.Length > 0) @@ -230,7 +237,7 @@ namespace JT808.Protocol.MessageBody if (commandParameter != null) { commandParameter.ToValue(cmd); - writer.WriteString($"[{cmd.ToHexString()}]{commandParameter.CommandName}", commandParameter.ToValueString()); + writer.WriteString($"[{cmd?.ToHexString()}]{commandParameter.CommandName}", commandParameter.ToValueString()); } } } @@ -243,7 +250,7 @@ namespace JT808.Protocol.MessageBody /// /// 命令参数接口 /// - public interface ICommandParameter + public interface ICommandParameter:ICommandParameterConvert { /// /// 排序 @@ -253,6 +260,13 @@ namespace JT808.Protocol.MessageBody /// 命令名称 /// string CommandName { get; } + + } + /// + /// 命令参数值的转换 + /// + public interface ICommandParameterConvert + { /// /// 转为byte数组 ///