From 359a347cec6a1ee1ce3544d8ca399a94cadd9484 Mon Sep 17 00:00:00 2001 From: SmallChi <564952747@qq.com> Date: Sat, 23 Feb 2019 00:02:57 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0JT809=E5=A4=B4=E9=83=A8?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8C=85=E8=A7=A3=E6=9E=90=E5=8F=8A=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=202.=E5=B0=86809=E7=BC=96=E8=A7=A3=E7=A0=81=E7=A7=BB?= =?UTF-8?q?=E5=88=B0=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JT809Packages/JT809HeaderPackageTest.cs | 32 +++++++ .../Formatters/JT809HeaderPackageFromatter.cs | 84 +++++++++++++++++ .../Formatters/JT809PackageFormatter.cs | 84 +---------------- src/JT809.Protocol/JT809HeaderPackage.cs | 25 ++++++ src/JT809.Protocol/JT809Util.cs | 89 +++++++++++++++++++ 5 files changed, 232 insertions(+), 82 deletions(-) create mode 100644 src/JT809.Protocol.Test/JT809Packages/JT809HeaderPackageTest.cs create mode 100644 src/JT809.Protocol/Formatters/JT809HeaderPackageFromatter.cs create mode 100644 src/JT809.Protocol/JT809HeaderPackage.cs create mode 100644 src/JT809.Protocol/JT809Util.cs diff --git a/src/JT809.Protocol.Test/JT809Packages/JT809HeaderPackageTest.cs b/src/JT809.Protocol.Test/JT809Packages/JT809HeaderPackageTest.cs new file mode 100644 index 0000000..c13c150 --- /dev/null +++ b/src/JT809.Protocol.Test/JT809Packages/JT809HeaderPackageTest.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; +using JT809.Protocol; +using JT809.Protocol.Extensions; +using JT809.Protocol.MessageBody; +using JT809.Protocol.Enums; + +namespace JT809.Protocol.Test.JT809Packages +{ + public class JT809HeaderPackageTest + { + [Fact] + public void Test1() + { + var bytes = "5B 00 00 00 48 00 00 00 85 10 01 01 33 EF B8 01 00 00 00 00 00 27 0F 01 33 EF B8 32 30 31 38 30 39 32 30 31 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 29 6A 91 5D".ToHexBytes(); + JT809HeaderPackage jT809HeaderPackage = JT809Serializer.Deserialize(bytes); + Assert.Equal((uint)72, jT809HeaderPackage.Header.MsgLength); + Assert.Equal((uint)133, jT809HeaderPackage.Header.MsgSN); + Assert.Equal((uint)9999, jT809HeaderPackage.Header.EncryptKey); + Assert.Equal((uint)20180920, jT809HeaderPackage.Header.MsgGNSSCENTERID); + Assert.Equal(JT809BusinessType.主链路登录请求消息, jT809HeaderPackage.Header.BusinessType); + Assert.Equal(new JT809Header_Version().ToString(), jT809HeaderPackage.Header.Version.ToString()); + JT809_0x1001 jT809_0X1001 = JT809Serializer.Deserialize(jT809HeaderPackage.Bodies); + Assert.Equal((uint)20180920, jT809_0X1001.UserId); + Assert.Equal("20180920", jT809_0X1001.Password); + Assert.Equal("127.0.0.1", jT809_0X1001.DownLinkIP); + Assert.Equal((ushort)809, jT809_0X1001.DownLinkPort); + } + } +} diff --git a/src/JT809.Protocol/Formatters/JT809HeaderPackageFromatter.cs b/src/JT809.Protocol/Formatters/JT809HeaderPackageFromatter.cs new file mode 100644 index 0000000..791c286 --- /dev/null +++ b/src/JT809.Protocol/Formatters/JT809HeaderPackageFromatter.cs @@ -0,0 +1,84 @@ +using JT809.Protocol.Attributes; +using JT809.Protocol.Enums; +using JT809.Protocol.Exceptions; +using JT809.Protocol.Extensions; +using System; + +namespace JT809.Protocol.Formatters +{ + public class JT809HeaderPackageFromatter : IJT809Formatter + { + public JT809HeaderPackage Deserialize(ReadOnlySpan bytes, out int readSize) + { + int offset = 0; + JT809HeaderPackage jT809HeaderPackage = new JT809HeaderPackage(); + // 转义还原——>验证校验码——>解析消息 + // 1. 解码(转义还原) + ReadOnlySpan buffer = JT809Util.JT809DeEscape(bytes); + // 2. 验证校验码 + // 2.1. 获取校验位索引 + int checkIndex = buffer.Length - 3; + // 2.2. 获取校验码 + int crcCodeOffset = 0; + jT809HeaderPackage.CRCCode = JT809BinaryExtensions.ReadUInt16Little(buffer.Slice(checkIndex, 2), ref crcCodeOffset); + if (!JT809GlobalConfig.Instance.SkipCRCCode) + { + // 2.3. 从消息头到校验码前一个字节 + ushort checkCode = buffer.ToCRC16_CCITT(1, checkIndex); + // 2.4. 验证校验码 + if (jT809HeaderPackage.CRCCode != checkCode) + { + throw new JT809Exception(JT809ErrorCode.CRC16CheckInvalid, $"{jT809HeaderPackage.CRCCode.ToString()}!={checkCode.ToString()}"); + } + } + jT809HeaderPackage.BeginFlag = JT809BinaryExtensions.ReadByteLittle(buffer, ref offset); + // 3.初始化消息头 + try + { + jT809HeaderPackage.Header = JT809FormatterExtensions.GetFormatter().Deserialize(buffer.Slice(offset, JT809Header.FixedByteLength), out readSize); + } + catch (Exception ex) + { + throw new JT809Exception(JT809ErrorCode.HeaderParseError, $"offset>{offset.ToString()}", ex); + } + offset += readSize; + // 5.数据体处理 + // 5.1 判断是否有数据体(总长度-固定长度)> 0 + if ((jT809HeaderPackage.Header.MsgLength - JT809Package.FixedByteLength) > 0) + { + //JT809.Protocol.Enums.JT809BusinessType 映射对应消息特性 + JT809BodiesTypeAttribute jT809BodiesTypeAttribute = jT809HeaderPackage.Header.BusinessType.GetAttribute(); + if (jT809BodiesTypeAttribute != null) + { + try + { + // 5.2 是否加密 + switch (jT809HeaderPackage.Header.EncryptFlag) + { + case JT809Header_Encrypt.None: + //5.3 处理消息体 + jT809HeaderPackage.Bodies = buffer.Slice(offset, checkIndex - offset).ToArray(); + break; + case JT809Header_Encrypt.Common: + byte[] bodiesData = JT809GlobalConfig.Instance.Encrypt.Decrypt(buffer.Slice(offset, checkIndex - offset).ToArray(), jT809HeaderPackage.Header.EncryptKey); + jT809HeaderPackage.Bodies = bodiesData; + break; + } + } + catch (Exception ex) + { + throw new JT809Exception(JT809ErrorCode.BodiesParseError, $"offset>{offset.ToString()}", ex); + } + } + } + jT809HeaderPackage.EndFlag = buffer[buffer.Length - 1]; + readSize = buffer.Length; + return jT809HeaderPackage; + } + + public int Serialize(ref byte[] bytes, int offset, JT809HeaderPackage value) + { + throw new NotImplementedException("只适用反序列化"); + } + } +} diff --git a/src/JT809.Protocol/Formatters/JT809PackageFormatter.cs b/src/JT809.Protocol/Formatters/JT809PackageFormatter.cs index 0015462..d7ca3d7 100644 --- a/src/JT809.Protocol/Formatters/JT809PackageFormatter.cs +++ b/src/JT809.Protocol/Formatters/JT809PackageFormatter.cs @@ -17,7 +17,7 @@ namespace JT809.Protocol.Formatters JT809Package jT809Package = new JT809Package(); // 转义还原——>验证校验码——>解析消息 // 1. 解码(转义还原) - ReadOnlySpan buffer = JT809DeEscape(bytes); + ReadOnlySpan buffer = JT809Util.JT809DeEscape(bytes); // 2. 验证校验码 // 2.1. 获取校验位索引 int checkIndex = buffer.Length - 3; @@ -132,87 +132,7 @@ namespace JT809.Protocol.Formatters // 5.终止符 offset += JT809BinaryExtensions.WriteByteLittle(bytes, offset, value.EndFlag); // 6.转义 - return JT809Escape(ref bytes, offset); - } - - internal static ReadOnlySpan JT809DeEscape(ReadOnlySpan buffer) - { - byte[] tmpBuffer = JT809ArrayPool.Rent(buffer.Length - 1); - try - { - int offset = 0; - tmpBuffer[offset++] = buffer[0]; - for (int i = 1; i < buffer.Length - 1; i++) - { - byte first = buffer[i]; - byte second = buffer[i + 1]; - if (first == 0x5a && second == 0x01) - { - tmpBuffer[offset++] = 0x5b; - i++; - } - else if (first == 0x5a && second == 0x02) - { - tmpBuffer[offset++] = 0x5a; - i++; - } - else if (first == 0x5e && second == 0x01) - { - tmpBuffer[offset++] = 0x5d; - i++; - } - else if (first == 0x5e && second == 0x02) - { - tmpBuffer[offset++] = 0x5e; - i++; - } - else - { - tmpBuffer[offset++] = first; - } - } - tmpBuffer[offset++] = buffer[buffer.Length - 1]; - return tmpBuffer.AsSpan(0, offset).ToArray(); - } - finally - { - JT809ArrayPool.Return(tmpBuffer); - } - } - - internal static int JT809Escape(ref byte[] buffer, int offset) - { - byte[] tmpBuffer = buffer.AsSpan(0, offset).ToArray(); - int tmpOffset = 0; - buffer[tmpOffset++] = tmpBuffer[0]; - for (int i = 1; i < offset - 1; i++) - { - var item = tmpBuffer[i]; - switch (item) - { - case 0x5b: - buffer[tmpOffset++] = 0x5a; - buffer[tmpOffset++] = 0x01; - break; - case 0x5a: - buffer[tmpOffset++] = 0x5a; - buffer[tmpOffset++] = 0x02; - break; - case 0x5d: - buffer[tmpOffset++] = 0x5e; - buffer[tmpOffset++] = 0x01; - break; - case 0x5e: - buffer[tmpOffset++] = 0x5e; - buffer[tmpOffset++] = 0x02; - break; - default: - buffer[tmpOffset++] = item; - break; - } - } - buffer[tmpOffset++]= tmpBuffer[tmpBuffer.Length - 1]; - return tmpOffset; + return JT809Util.JT809Escape(ref bytes, offset); } } } diff --git a/src/JT809.Protocol/JT809HeaderPackage.cs b/src/JT809.Protocol/JT809HeaderPackage.cs new file mode 100644 index 0000000..159dcdc --- /dev/null +++ b/src/JT809.Protocol/JT809HeaderPackage.cs @@ -0,0 +1,25 @@ +using JT809.Protocol.Attributes; +using JT809.Protocol.Formatters; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.Protocol +{ + /// + /// JT809头部数据包 + /// + [JT809Formatter(typeof(JT809HeaderPackageFromatter))] + public class JT809HeaderPackage + { + public byte BeginFlag { get; set; } = JT809Package.BEGINFLAG; + + public JT809Header Header { get; set; } + + public byte[] Bodies { get; set; } + + public ushort CRCCode { get; set; } + + public byte EndFlag { get; set; } = JT809Package.ENDFLAG; + } +} diff --git a/src/JT809.Protocol/JT809Util.cs b/src/JT809.Protocol/JT809Util.cs new file mode 100644 index 0000000..9be01a9 --- /dev/null +++ b/src/JT809.Protocol/JT809Util.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.Protocol +{ + public static class JT809Util + { + internal static ReadOnlySpan JT809DeEscape(ReadOnlySpan buffer) + { + byte[] tmpBuffer = JT809ArrayPool.Rent(buffer.Length - 1); + try + { + int offset = 0; + tmpBuffer[offset++] = buffer[0]; + for (int i = 1; i < buffer.Length - 1; i++) + { + byte first = buffer[i]; + byte second = buffer[i + 1]; + if (first == 0x5a && second == 0x01) + { + tmpBuffer[offset++] = 0x5b; + i++; + } + else if (first == 0x5a && second == 0x02) + { + tmpBuffer[offset++] = 0x5a; + i++; + } + else if (first == 0x5e && second == 0x01) + { + tmpBuffer[offset++] = 0x5d; + i++; + } + else if (first == 0x5e && second == 0x02) + { + tmpBuffer[offset++] = 0x5e; + i++; + } + else + { + tmpBuffer[offset++] = first; + } + } + tmpBuffer[offset++] = buffer[buffer.Length - 1]; + return tmpBuffer.AsSpan(0, offset).ToArray(); + } + finally + { + JT809ArrayPool.Return(tmpBuffer); + } + } + + internal static int JT809Escape(ref byte[] buffer, int offset) + { + byte[] tmpBuffer = buffer.AsSpan(0, offset).ToArray(); + int tmpOffset = 0; + buffer[tmpOffset++] = tmpBuffer[0]; + for (int i = 1; i < offset - 1; i++) + { + var item = tmpBuffer[i]; + switch (item) + { + case 0x5b: + buffer[tmpOffset++] = 0x5a; + buffer[tmpOffset++] = 0x01; + break; + case 0x5a: + buffer[tmpOffset++] = 0x5a; + buffer[tmpOffset++] = 0x02; + break; + case 0x5d: + buffer[tmpOffset++] = 0x5e; + buffer[tmpOffset++] = 0x01; + break; + case 0x5e: + buffer[tmpOffset++] = 0x5e; + buffer[tmpOffset++] = 0x02; + break; + default: + buffer[tmpOffset++] = item; + break; + } + } + buffer[tmpOffset++] = tmpBuffer[tmpBuffer.Length - 1]; + return tmpOffset; + } + } +}