From 58a67ed5e4da58995fd45a12adea0d992acb9e48 Mon Sep 17 00:00:00 2001
From: SmallChi <564952747@qq.com>
Date: Mon, 21 Jan 2019 20:10:55 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=95=B4=E6=96=B0=E8=83=BD=E6=BA=90?=
 =?UTF-8?q?=E5=8D=8F=E8=AE=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../JTNE.Protocol.Test.csproj                 |  19 ++
 src/JTNE.Protocol.Test/JTNEPackageTest.cs     |  18 ++
 .../Attributes/JTNEBodiesTypeAttribute.cs     |  14 ++
 .../Attributes/JTNEFormatterAttribute.cs      |  25 +++
 .../JTNEMsgIdDescriptionAttribute.cs          |  20 ++
 src/JTNE.Protocol/Enums/JTNEAskId.cs          |  29 +++
 src/JTNE.Protocol/Enums/JTNEEncryptMethod.cs  |  34 +++
 src/JTNE.Protocol/Enums/JTNEErrorCode.cs      |  26 +++
 src/JTNE.Protocol/Enums/JTNEMsgId.cs          |  57 +++++
 src/JTNE.Protocol/Exceptions/JTNEException.cs |  22 ++
 .../Extensions/JTNEBCDExtensions.cs           |  45 ++++
 .../Extensions/JTNEBinaryExtensions.cs        | 120 ++++++++++
 .../Extensions/JTNEDateTimeExtensions.cs      | 170 ++++++++++++++
 .../Extensions/JTNEEnumExtensions.cs          | 207 ++++++++++++++++++
 .../Extensions/JTNEFormatterExtensions.cs     |  50 +++++
 .../JTNEFormatterResolverExtensions.cs        |  81 +++++++
 .../Extensions/JTNEHexExtensions.cs           | 130 +++++++++++
 .../Extensions/JTNEStringExtensions.cs        |  70 ++++++
 .../Extensions/JTNEXorExtensions.cs           |  45 ++++
 .../Formatters/IJTNEFormatterOfT.cs           |  12 +
 .../Formatters/JTNEPackageFormatter.cs        |  43 ++++
 src/JTNE.Protocol/JTNE.Protocol.csproj        |   2 +-
 src/JTNE.Protocol/JTNEArrayPool.cs            |  27 +++
 src/JTNE.Protocol/JTNEBodies.cs               |  14 ++
 src/JTNE.Protocol/JTNEGlobalConfigs.cs        |  34 +++
 src/JTNE.Protocol/JTNEPackage.cs              |  29 ++-
 src/JTNE.Protocol/JTNESerializer.cs           |  49 +++++
 src/JTNewEnergy.sln                           |  24 +-
 28 files changed, 1403 insertions(+), 13 deletions(-)
 create mode 100644 src/JTNE.Protocol.Test/JTNE.Protocol.Test.csproj
 create mode 100644 src/JTNE.Protocol.Test/JTNEPackageTest.cs
 create mode 100644 src/JTNE.Protocol/Attributes/JTNEBodiesTypeAttribute.cs
 create mode 100644 src/JTNE.Protocol/Attributes/JTNEFormatterAttribute.cs
 create mode 100644 src/JTNE.Protocol/Attributes/JTNEMsgIdDescriptionAttribute.cs
 create mode 100644 src/JTNE.Protocol/Enums/JTNEAskId.cs
 create mode 100644 src/JTNE.Protocol/Enums/JTNEEncryptMethod.cs
 create mode 100644 src/JTNE.Protocol/Enums/JTNEErrorCode.cs
 create mode 100644 src/JTNE.Protocol/Enums/JTNEMsgId.cs
 create mode 100644 src/JTNE.Protocol/Exceptions/JTNEException.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEBCDExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEBinaryExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEDateTimeExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEFormatterExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEFormatterResolverExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEHexExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEStringExtensions.cs
 create mode 100644 src/JTNE.Protocol/Extensions/JTNEXorExtensions.cs
 create mode 100644 src/JTNE.Protocol/Formatters/IJTNEFormatterOfT.cs
 create mode 100644 src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs
 create mode 100644 src/JTNE.Protocol/JTNEArrayPool.cs
 create mode 100644 src/JTNE.Protocol/JTNEBodies.cs
 create mode 100644 src/JTNE.Protocol/JTNEGlobalConfigs.cs
 create mode 100644 src/JTNE.Protocol/JTNESerializer.cs

diff --git a/src/JTNE.Protocol.Test/JTNE.Protocol.Test.csproj b/src/JTNE.Protocol.Test/JTNE.Protocol.Test.csproj
new file mode 100644
index 0000000..880d991
--- /dev/null
+++ b/src/JTNE.Protocol.Test/JTNE.Protocol.Test.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
+    <PackageReference Include="xunit" Version="2.4.0" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\JTNE.Protocol\JTNE.Protocol.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/JTNE.Protocol.Test/JTNEPackageTest.cs b/src/JTNE.Protocol.Test/JTNEPackageTest.cs
new file mode 100644
index 0000000..0b2450b
--- /dev/null
+++ b/src/JTNE.Protocol.Test/JTNEPackageTest.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+using JTNE.Protocol.Extensions;
+
+namespace JTNE.Protocol.Test
+{
+    public class JTNEPackageTest
+    {
+        [Fact]
+        public void Test1()
+        {
+            var hex = "23 23 05 FE 4C 47 48 43 34 56 31 44 33 48 45 32 30 32 36 35 32 01 00 08 12 06 08 12 06 3A 00 01 E9".ToHexBytes();
+            var package=JTNESerializer.Deserialize(hex);
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Attributes/JTNEBodiesTypeAttribute.cs b/src/JTNE.Protocol/Attributes/JTNEBodiesTypeAttribute.cs
new file mode 100644
index 0000000..65dff14
--- /dev/null
+++ b/src/JTNE.Protocol/Attributes/JTNEBodiesTypeAttribute.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace JTNE.Protocol.Attributes
+{
+    [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
+    public sealed class JTNEBodiesTypeAttribute : Attribute
+    {
+        public JTNEBodiesTypeAttribute(Type jT808BodiesType)
+        {
+            JT808BodiesType = jT808BodiesType;
+        }
+        public Type JT808BodiesType { get;}
+    }
+}
diff --git a/src/JTNE.Protocol/Attributes/JTNEFormatterAttribute.cs b/src/JTNE.Protocol/Attributes/JTNEFormatterAttribute.cs
new file mode 100644
index 0000000..3b6364a
--- /dev/null
+++ b/src/JTNE.Protocol/Attributes/JTNEFormatterAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Attributes
+{
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
+    public  sealed  class JTNEFormatterAttribute:Attribute
+    {
+        public Type FormatterType { get; private set; }
+
+        public object[] Arguments { get; private set; }
+
+        public JTNEFormatterAttribute(Type formatterType)
+        {
+            this.FormatterType = formatterType;
+        }
+
+        public JTNEFormatterAttribute(Type formatterType, params object[] arguments)
+        {
+            this.FormatterType = formatterType;
+            this.Arguments = arguments;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Attributes/JTNEMsgIdDescriptionAttribute.cs b/src/JTNE.Protocol/Attributes/JTNEMsgIdDescriptionAttribute.cs
new file mode 100644
index 0000000..3503a9d
--- /dev/null
+++ b/src/JTNE.Protocol/Attributes/JTNEMsgIdDescriptionAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Attributes
+{
+    [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
+    public sealed class JTNEMsgIdDescriptionAttribute : Attribute
+    {
+        public string Code { get; set; }
+
+        public string Name { get; set; }
+
+        public JTNEMsgIdDescriptionAttribute(string code,string name)
+        {
+            Code = code;
+            Name = name;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Enums/JTNEAskId.cs b/src/JTNE.Protocol/Enums/JTNEAskId.cs
new file mode 100644
index 0000000..83972a5
--- /dev/null
+++ b/src/JTNE.Protocol/Enums/JTNEAskId.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Enums
+{
+    /// <summary>
+    /// 应答标志
+    /// </summary>
+    public enum JTNEAskId:byte
+    {
+        /// <summary>
+        /// 接收到的信息正确
+        /// </summary>
+        Success=0x01,
+        /// <summary>
+        /// 设置未成功
+        /// </summary>
+        Error=0x02,
+        /// <summary>
+        /// VIN重复错误
+        /// </summary>
+        VinRepeatError=0x03,
+        /// <summary>
+        /// 数据包为命令包,而非应答包
+        /// </summary>
+        CMD=0xFE
+    }
+}
diff --git a/src/JTNE.Protocol/Enums/JTNEEncryptMethod.cs b/src/JTNE.Protocol/Enums/JTNEEncryptMethod.cs
new file mode 100644
index 0000000..3a83725
--- /dev/null
+++ b/src/JTNE.Protocol/Enums/JTNEEncryptMethod.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Enums
+{
+    /// <summary>
+    /// 数据单元加密方式
+    /// 0x01:数据不加密;0x02:数据经过 RSA 算法加密;0x03:数据经过 AES128 位算法加密;“0xFE”表示异常,“0xFF”表示无效
+    /// </summary>
+    public enum JTNEEncryptMethod:byte
+    {
+        /// <summary>
+        /// 数据不加密
+        /// </summary>
+        None = 0x01,
+        /// <summary>
+        /// 数据经过 RSA 算法加密
+        /// </summary>
+        RSA = 0x02,
+        /// <summary>
+        /// 数据经过 AES128 位算法加密
+        /// </summary>
+        AES128 = 0x03,
+        /// <summary>
+        /// 表示异常
+        /// </summary>
+        Exception = 0xFE,
+        /// <summary>
+        /// 表示无效
+        /// </summary>
+        Invalid = 0xFF
+    }
+}
diff --git a/src/JTNE.Protocol/Enums/JTNEErrorCode.cs b/src/JTNE.Protocol/Enums/JTNEErrorCode.cs
new file mode 100644
index 0000000..02da28d
--- /dev/null
+++ b/src/JTNE.Protocol/Enums/JTNEErrorCode.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Enums
+{
+    /// <summary>
+    /// 错误代码
+    /// </summary>
+    public enum JTNEErrorCode
+    {
+        /// <summary>
+        /// 开始标识错误
+        /// </summary>
+        BeginFlagError = 1001,
+        /// <summary>
+        /// BCC校验错误
+        /// </summary>
+        BCCCodeError = 1002,
+        /// <summary>
+        /// 没有标记
+        /// <see cref="JT808.Protocol.Attributes.JT808FormatterAttribute"/>
+        /// </summary>
+        GetFormatterAttributeError = 1003,
+    }
+}
diff --git a/src/JTNE.Protocol/Enums/JTNEMsgId.cs b/src/JTNE.Protocol/Enums/JTNEMsgId.cs
new file mode 100644
index 0000000..d56a78f
--- /dev/null
+++ b/src/JTNE.Protocol/Enums/JTNEMsgId.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Enums
+{
+    /// <summary>
+    /// 命令单元
+    /// </summary>
+    public enum JTNEMsgId:byte
+    {
+        /// <summary>
+        /// 车辆登入
+        /// </summary>
+        login = 0x01,
+        /// <summary>
+        /// 实时信息上传
+        /// </summary>
+        uploadim = 0x02,
+        /// <summary>
+        /// 补传信息上传
+        /// </summary>
+        uploadsup = 0x03,
+        /// <summary>
+        /// 车辆登出
+        /// </summary>
+        loginout = 0x04,
+        /// <summary>
+        /// 平台登入
+        /// </summary>
+        platformlogin = 0x05,
+        /// <summary>
+        /// 平台登出
+        /// </summary>
+        platformlogout = 0x06,
+        /// <summary>
+        /// 心跳
+        /// </summary>
+        heartbeat = 0x07,
+        /// <summary>
+        /// 终端校时
+        /// </summary>
+        checktime = 0x08,
+        /// <summary>
+        /// 查询命令
+        /// </summary>
+        query = 0x80,
+        /// <summary>
+        /// 设置命令
+        /// </summary>
+        settings = 0x81,
+        /// <summary>
+        /// 控制命令
+        /// </summary>
+        control = 0x82
+    }
+}
diff --git a/src/JTNE.Protocol/Exceptions/JTNEException.cs b/src/JTNE.Protocol/Exceptions/JTNEException.cs
new file mode 100644
index 0000000..48f6126
--- /dev/null
+++ b/src/JTNE.Protocol/Exceptions/JTNEException.cs
@@ -0,0 +1,22 @@
+using JTNE.Protocol.Enums;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Exceptions
+{
+    public class JTNEException:Exception
+    {
+        public JTNEException(JTNEErrorCode errorCode) : base(errorCode.ToString())
+        {
+            this.ErrorCode = errorCode;
+        }
+
+        public JTNEException(JTNEErrorCode errorCode, string message) : base(message)
+        {
+            this.ErrorCode = errorCode;
+        }
+
+        public JTNEErrorCode ErrorCode { get; }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEBCDExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEBCDExtensions.cs
new file mode 100644
index 0000000..68f7405
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEBCDExtensions.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace JTNE.Protocol.Extensions
+{
+    public static partial class JTNEBinaryExtensions
+    {
+        public static string ReadBCDLittle(ReadOnlySpan<byte> buf, ref int offset, int len)
+        {
+            int count = len / 2;
+            StringBuilder bcdSb = new StringBuilder(count);
+            for(int i = 0; i < count; i++)
+            {
+                bcdSb.Append(buf[offset + i].ToString("X2"));
+            }
+            offset = offset + count;
+            return bcdSb.ToString().TrimStart('0');
+        }
+
+        public static int WriteBCDLittle(byte[] bytes, int offset, string data,int len)
+        {
+            string bcdText = data == null ? "" : data;
+            int startIndex = 0;
+            int noOfZero = len - bcdText.Length;
+            if (noOfZero > 0)
+            {
+                bcdText = bcdText.Insert(startIndex, new string('0', noOfZero));
+            }
+            int byteIndex = 0;
+            int count = len / 2;
+            byte[] tempBytes = new byte[count];
+            while (startIndex < bcdText.Length && byteIndex < count)
+            {
+                tempBytes[byteIndex] = Convert.ToByte(bcdText.Substring(startIndex, 2), 16);
+                startIndex += 2;
+                byteIndex++;
+            }
+            Array.Copy(tempBytes, 0, bytes, offset, tempBytes.Length);
+            return count;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEBinaryExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEBinaryExtensions.cs
new file mode 100644
index 0000000..0634756
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEBinaryExtensions.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Extensions
+{
+    public static partial class JTNEBinaryExtensions
+    {
+        public static int ReadInt32Little(ReadOnlySpan<byte> read, ref int offset)
+        {
+            int value = ((read[offset] << 24) | (read[offset + 1] << 16) | (read[offset + 2] << 8) | read[offset + 3]);
+            offset = offset + 4;
+            return value;
+        }
+
+        public static uint ReadUInt32Little(ReadOnlySpan<byte> read, ref int offset)
+        {
+            uint value =(uint) ((read[offset] << 24) | (read[offset + 1] << 16) | (read[offset + 2] << 8) | read[offset + 3]);
+            offset = offset + 4;
+            return value;
+        }
+
+        public static ushort ReadUInt16Little(ReadOnlySpan<byte> read, ref int offset)
+        {
+            ushort value = (ushort)((read[offset] << 8) | (read[offset + 1]));
+            offset = offset + 2;
+            return value;
+        }
+
+        public static byte ReadByteLittle(ReadOnlySpan<byte> read, ref int offset)
+        {
+            byte value = read[offset];
+            offset = offset + 1;
+            return value;
+        }
+
+        public static byte[] ReadBytesLittle(ReadOnlySpan<byte> read, ref int offset,int len)
+        {
+            ReadOnlySpan<byte> temp = read.Slice(offset, len);
+            offset = offset + len;
+            return temp.ToArray();
+        }
+
+        public static byte[] ReadBytesLittle(ReadOnlySpan<byte> read, ref int offset)
+        {
+            ReadOnlySpan<byte> temp = read.Slice(offset);
+            offset = offset + temp.Length;
+            return temp.ToArray();
+        }
+
+        public static int WriteUInt32Little(byte[] write, int offset, uint data)
+        {
+            write[offset] = (byte)(data >> 24);
+            write[offset + 1] = (byte)(data >> 16);
+            write[offset + 2] = (byte)(data >> 8);
+            write[offset + 3] = (byte)data;
+            return 4;
+        }
+
+        public static int WriteInt32Little(byte[] write, int offset, int data)
+        {
+            write[offset] = (byte)(data >> 24);
+            write[offset + 1] = (byte)(data >> 16);
+            write[offset + 2] = (byte)(data >> 8);
+            write[offset + 3] = (byte)data;
+            return 4;
+        }
+
+        public static int WriteUInt16Little(byte[] write, int offset, ushort data)
+        {
+            write[offset] = (byte)(data >> 8);
+            write[offset + 1] = (byte)data;
+            return 2;
+        }
+
+        public static int WriteByteLittle(byte[] write, int offset, byte data)
+        {
+            write[offset] = data;
+            return 1;
+        }
+
+        public static int WriteBytesLittle(byte[] write, int offset, byte[] data)
+        {
+            Array.Copy(data, 0, write, offset, data.Length);
+            return data.Length;
+        }
+
+        public static IEnumerable<byte> ToBytes(this string data, Encoding coding)
+        {
+            return coding.GetBytes(data);
+        }
+
+        public static IEnumerable<byte> ToBytes(this string data)
+        {
+            return ToBytes(data, JTNEGlobalConfigs.Instance.Encoding);
+        }
+
+        public static IEnumerable<byte> ToBytes(this int data, int len)
+        {
+            List<byte> bytes = new List<byte>();
+            int n = 1;
+            for (int i = 0; i < len; i++)
+            {
+                bytes.Add((byte)(data >> 8 * (len - n)));
+                n++;
+            }
+            return bytes;
+        }
+
+        /// <summary>
+        /// 经纬度
+        /// </summary>
+        /// <param name="latlng"></param>
+        /// <returns></returns>
+        public static double ToLatLng(this int latlng)
+        {
+            return Math.Round(latlng / Math.Pow(10, 6), 6);
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEDateTimeExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEDateTimeExtensions.cs
new file mode 100644
index 0000000..c6cccdb
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEDateTimeExtensions.cs
@@ -0,0 +1,170 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Extensions
+{
+    public static partial class JTNEBinaryExtensions
+    {
+        /// <summary>
+        /// 日期限制于2000年
+        /// </summary>
+        private const int DateLimitYear = 2000;
+
+        private static readonly DateTime UTCBaseTime = new DateTime(1970, 1, 1);
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="buf"></param>
+        /// <param name="offset"></param>
+        /// <param name="format">D2: 10  X2:16</param>
+        /// <returns></returns>
+        public static DateTime ReadDateTime6Little(ReadOnlySpan<byte> buf, ref int offset,string format= "X2")
+        {
+            DateTime d = UTCBaseTime;
+            try
+            {
+                int year = Convert.ToInt32(buf[offset].ToString(format)) + DateLimitYear;
+                int month = Convert.ToInt32(buf[offset + 1].ToString(format));
+                int day = Convert.ToInt32(buf[offset + 2].ToString(format));
+                int hour = Convert.ToInt32(buf[offset + 3].ToString(format));
+                int minute = Convert.ToInt32(buf[offset + 4].ToString(format));
+                int second = Convert.ToInt32(buf[offset + 5].ToString(format));
+                d = new DateTime(year, month, day, hour, minute, second);
+            }
+            catch (Exception ex)
+            { 
+                d = UTCBaseTime;
+            }
+            offset = offset + 6;
+            return d;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="buf"></param>
+        /// <param name="offset"></param>
+        /// <param name="format">D2: 10  X2:16</param>
+        /// <returns></returns>
+        public static DateTime ReadDateTime4Little(ReadOnlySpan<byte> buf, ref int offset, string format = "X2")
+        {
+            DateTime d = UTCBaseTime;
+            try
+            {
+                d = new DateTime(
+                (Convert.ToInt32(buf[offset].ToString(format)) << 8) + Convert.ToByte(buf[offset + 1]),
+                Convert.ToInt32(buf[offset + 2].ToString(format)),
+                Convert.ToInt32(buf[offset + 3].ToString(format)));
+            }
+            catch (Exception)
+            {
+                d = UTCBaseTime;
+            }
+            offset = offset + 4;
+            return d;
+        }
+
+        public static DateTime ReadUTCDateTimeLittle(ReadOnlySpan<byte> buf, ref int offset)
+        {
+            ulong result = 0;
+            for (int i = 0; i < 8; i++)
+            {
+                ulong currentData = (ulong)buf[offset + i] << (8 * (8 - i - 1));
+                result += currentData;
+            }
+            offset += 8;
+            return UTCBaseTime.AddSeconds(result).AddHours(8);
+        }
+        /// <summary>
+        /// hh-mm-ss-msms
+        /// hh-mm-ss-fff
+        /// </summary>
+        /// <param name="buf"></param>
+        /// <param name="offset"></param>
+        /// <param name="format"></param>
+        /// <returns></returns>
+        public static DateTime ReadDateTime5Little(ReadOnlySpan<byte> buf, ref int offset, string format = "X2")
+        {
+
+            DateTime dateTime = new DateTime(
+                DateTime.Now.Year,
+                DateTime.Now.Month,
+                DateTime.Now.Day,
+                Convert.ToInt32(buf[offset].ToString(format)),
+                Convert.ToInt32(buf[offset + 1].ToString(format)),
+                Convert.ToInt32(buf[offset + 2].ToString(format)),
+                ((buf[offset + 3] << 8) + buf[offset + 4]));
+            offset = offset + 5;
+            return dateTime;
+        }
+
+        public static int WriteUTCDateTimeLittle(byte[] bytes, int offset, DateTime date)
+        {
+            ulong totalSecends = (ulong)(date.AddHours(-8) - UTCBaseTime).TotalSeconds;
+            //高位在前
+            for (int i = 7; i >= 0; i--)
+            {
+                bytes[offset + i] = (byte)(totalSecends & 0xFF);  //取低8位
+                totalSecends = totalSecends >> 8;
+            }
+            return 8;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="memoryOwner"></param>
+        /// <param name="offset"></param>
+        /// <param name="date"></param>
+        /// <param name="fromBase">BCD:10  HEX:16</param>
+        /// <returns></returns>
+        public static int WriteDateTime6Little(byte[] bytes, int offset, DateTime date,int fromBase=16)
+        {
+            bytes[offset] = Convert.ToByte(date.ToString("yy"), fromBase);
+            bytes[offset + 1] = Convert.ToByte(date.ToString("MM"), fromBase);
+            bytes[offset + 2] = Convert.ToByte(date.ToString("dd"), fromBase);
+            bytes[offset + 3] = Convert.ToByte(date.ToString("HH"), fromBase);
+            bytes[offset + 4] = Convert.ToByte(date.ToString("mm"), fromBase);
+            bytes[offset + 5] = Convert.ToByte(date.ToString("ss"), fromBase);
+            return 6;
+        }
+
+        /// <summary>
+        /// YYYYMMDD
+        /// </summary>
+        /// <param name="bytes"></param>
+        /// <param name="offset"></param>
+        /// <param name="date"></param>
+        /// <param name="fromBase">BCD:10  HEX:16</param>
+        /// <returns></returns>
+        public static int WriteDateTime4Little(byte[] bytes, int offset, DateTime date, int fromBase = 16)
+        {
+            bytes[offset] = (byte)(date.Year>>8);
+            bytes[offset + 1] = (byte)(date.Year);
+            bytes[offset + 2] = Convert.ToByte(date.ToString("MM"), fromBase);
+            bytes[offset + 3] = Convert.ToByte(date.ToString("dd"), fromBase);
+            return 4;
+        }
+        /// <summary>
+        /// hh-mm-ss-msms
+        /// hh-mm-ss-fff
+        /// </summary>
+        /// <param name="bytes"></param>
+        /// <param name="offset"></param>
+        /// <param name="date"></param>
+        /// <param name="fromBase"></param>
+        /// <returns></returns>
+        public static int WriteDateTime5Little(byte[] bytes, int offset, DateTime date, int fromBase = 16)
+        {
+            bytes[offset] = Convert.ToByte(date.ToString("HH"), fromBase);
+            bytes[offset + 1] = Convert.ToByte(date.ToString("mm"), fromBase);
+            bytes[offset + 2] = Convert.ToByte(date.ToString("ss"), fromBase);
+            bytes[offset + 3] = (byte)(date.Millisecond >> 8);
+            bytes[offset + 4] = (byte)(date.Millisecond);
+            return 5;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs
new file mode 100644
index 0000000..26fab03
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEEnumExtensions.cs
@@ -0,0 +1,207 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+
+namespace JTNE.Protocol.Extensions
+{
+    /// <summary>
+    /// 枚举扩展
+    /// </summary>
+    public static class JT808EnumExtensions
+    {
+        /// <summary>
+        /// 转为整型
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public static int ToValue<T>(this T t) where T : struct
+        {
+            return Convert.ToInt32(t);
+        }
+
+        /// <summary>
+        /// 转为 u16 整型
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public static ushort ToUInt16Value<T>(this T t) where T : struct
+        {
+            return Convert.ToUInt16(t);
+        }
+
+        /// <summary>
+        /// 转为Byte
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public static byte ToByteValue<T>(this T t) where T : struct
+        {
+            return Convert.ToByte(t);
+        }
+
+        /// <summary>
+        /// 转为整型
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public static string ToValueString<T>(this T t) where T : struct
+        {
+            return Convert.ToInt32(t).ToString();
+        }
+
+        /// <summary>
+        /// 字符转枚举
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static T ToEnum<T>(this string value) where T : struct
+        {
+            return (T)Enum.Parse(typeof(T), value);
+        }
+
+        /// <summary>
+        /// 获取枚举字符串
+        /// </summary>
+        /// <param name="valueEnum"></param>
+        public static string GetName(this Enum valueEnum)
+        {
+            return valueEnum.ToString();
+        }
+
+        /// <summary>
+        /// 获取DescriptionAttribute特性枚举值的描述
+        /// </summary>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static string GetDescription(this Enum value)
+        {
+            var attribute = value.GetAttribute<DescriptionAttribute>();
+            return attribute == null ? value.ToString() : attribute.Description;
+        }
+
+        /// <summary>
+        /// 验证是否是枚举类型
+        /// </summary>
+        /// <typeparam name="TEnum"></typeparam>
+        /// <param name="enumValue"></param>
+        /// <returns></returns>
+        public static bool IsEnumValid<TEnum>(this int enumValue)
+        {
+            return Enum.IsDefined(typeof(TEnum), enumValue);
+        }
+
+        /// <summary>
+        /// 获取DescriptionAttribute特性枚举及描述
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static Dictionary<string, string> GetDescriptionAttributeDictionary(this Enum value)
+        {
+            Dictionary<string, string> dictionary = new Dictionary<string, string>();
+            var fields = value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);
+            foreach (var fi in fields)
+            {
+                DescriptionAttribute attr = Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute), false) as DescriptionAttribute;
+                dictionary.Add(fi.Name, attr != null ? attr.Description : "");
+            }
+            return dictionary;
+        }
+
+        /// <summary>
+        /// 获取DisplayNameAttribute特性枚举值的描述
+        /// </summary>
+        /// <param name="obj">枚举值</param>
+        /// <returns></returns>
+        public static string GetDisplayName(this Enum value)
+        {
+            var attribute = value.GetAttribute<DisplayNameAttribute>();
+            return attribute == null ? value.ToString() : attribute.DisplayName;
+        }
+
+        /// <summary>
+        /// 获取DisplayNameAttribute特性枚举及描述
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static Dictionary<string, string> GetDisplayNameAttributeDictionary(this Enum value)
+        {
+            Dictionary<string, string> dictionary = new Dictionary<string, string>();
+            var fields = value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);
+            foreach (var fi in fields)
+            {
+                DisplayNameAttribute attr = Attribute.GetCustomAttribute(fi, typeof(DisplayNameAttribute), false) as DisplayNameAttribute;
+                dictionary.Add(fi.Name, attr != null ? attr.DisplayName : "");
+            }
+            return dictionary;
+        }
+
+        /// <summary>
+        /// 获取枚举对应特性
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static T GetAttribute<T>(this Enum value) where T : Attribute
+        {
+            try
+            {
+                var type = value.GetType();
+                var memberInfo = type.GetMember(value.ToString());
+                var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
+                return (T)attributes[0];
+            }
+            catch
+            {
+                return default;
+            }
+        }
+
+        /// <summary>
+        /// 根据值获取对应枚举类型集合
+        /// </summary>
+        /// <typeparam name="T">具体枚举类型</typeparam>
+        /// <param name="value">枚举值</param>
+        /// <param name="digit">位数(8,16,32)</param>
+        /// <param name="ignoreUnknown">是否忽略未知数据</param>
+        /// <returns></returns>
+        public static IEnumerable<T> GetEnumTypes<T>(this int value, int digit, bool ignoreUnknown=false) where T : Enum
+        {
+            List<T> values = new List<T>();
+            for (int i = 0; i < digit; i++)
+            {
+                if (Math.Pow(2, i) <= value) continue;
+                values.Add((T)Enum.ToObject(typeof(T), (int)Math.Pow(2, i - 1)));
+                value = value - (int)Math.Pow(2, i - 1);
+                i = 0;
+                if (value <= 0) break;
+            }
+            if (ignoreUnknown)
+            {
+                List<T> results = new List<T>();
+                foreach (var item in values)
+                {
+                    foreach (string itemChild in Enum.GetNames(typeof(T)))
+                    {
+                        if (item.ToString() == itemChild)
+                        {
+                            results.Add(item);
+                            break;
+                        }
+                    }
+                }
+                return results;
+            }
+            else
+            {
+                return values;
+            }
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEFormatterExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEFormatterExtensions.cs
new file mode 100644
index 0000000..0b9a1e9
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEFormatterExtensions.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Reflection;
+using JTNE.Protocol.Formatters;
+using JTNE.Protocol.Enums;
+using JTNE.Protocol.Attributes;
+using JTNE.Protocol.Exceptions;
+
+namespace JTNE.Protocol.Extensions
+{
+    public  static class JTNEFormatterExtensions
+    {
+        public static IJTNEFormatter<T> GetFormatter<T>()
+        {
+            IJTNEFormatter<T> formatter;
+            var attr = typeof(T).GetTypeInfo().GetCustomAttribute<JTNEFormatterAttribute>();
+            if (attr == null)
+            {
+                return default;
+            }
+            if (attr.Arguments == null)
+            {
+                formatter = (IJTNEFormatter<T>)Activator.CreateInstance(attr.FormatterType);
+            }
+            else
+            {
+                formatter = (IJTNEFormatter<T>)Activator.CreateInstance(attr.FormatterType, attr.Arguments);
+            }
+            return formatter;
+        }
+
+        public static object GetFormatter(Type formatterType)
+        {
+            object formatter;
+            var attr = formatterType.GetTypeInfo().GetCustomAttribute<JTNEFormatterAttribute>();
+            if (attr == null)
+            {
+                throw new JTNEException(JTNEErrorCode.GetFormatterAttributeError, formatterType.FullName);
+            }
+            if (attr.Arguments == null)
+            {
+                formatter = Activator.CreateInstance(attr.FormatterType);
+            }
+            else
+            {
+                formatter = Activator.CreateInstance(attr.FormatterType, attr.Arguments);
+            }
+            return formatter;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEFormatterResolverExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEFormatterResolverExtensions.cs
new file mode 100644
index 0000000..38f1263
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEFormatterResolverExtensions.cs
@@ -0,0 +1,81 @@
+using JTNE.Protocol.Formatters;
+using System;
+using System.Collections.Concurrent;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace JTNE.Protocol.Extensions
+{
+    /// <summary>
+    /// 
+    /// ref http://adamsitnik.com/Span/#span-must-not-be-a-generic-type-argument
+    /// ref http://adamsitnik.com/Span/
+    /// ref:MessagePack.Formatters.DynamicObjectTypeFallbackFormatter
+    /// </summary>
+    public static class JTNEFormatterResolverExtensions
+    {
+        delegate int JTNESerializeMethod(object dynamicFormatter, ref byte[] bytes, int offset, object value);
+
+        delegate dynamic JTNEDeserializeMethod(object dynamicFormatter, ReadOnlySpan<byte> bytes,  out int readSize);
+
+        static readonly ConcurrentDictionary<Type, (object Value, JTNESerializeMethod SerializeMethod)> jTNESerializers = new ConcurrentDictionary<Type, (object Value, JTNESerializeMethod SerializeMethod)>();
+
+        static readonly ConcurrentDictionary<Type, (object Value, JTNEDeserializeMethod DeserializeMethod)> jTNEDeserializes = new ConcurrentDictionary<Type, (object Value, JTNEDeserializeMethod DeserializeMethod)>();
+
+        public static int JTNEDynamicSerialize(object objFormatter, ref byte[] bytes, int offset, dynamic value)
+        {
+            Type type = value.GetType();
+            var ti = type.GetTypeInfo();
+            (object Value, JTNESerializeMethod SerializeMethod) formatterAndDelegate;
+            if (!jTNESerializers.TryGetValue(type, out formatterAndDelegate))
+            {
+                var t = type;
+                {
+                    var formatterType = typeof(IJTNEFormatter<>).MakeGenericType(t);
+                    var param0 = Expression.Parameter(typeof(object), "formatter");
+                    var param1 = Expression.Parameter(typeof(byte[]).MakeByRefType(), "bytes");
+                    var param2 = Expression.Parameter(typeof(int), "offset");
+                    var param3 = Expression.Parameter(typeof(object), "value");
+                    var serializeMethodInfo = formatterType.GetRuntimeMethod("Serialize", new[] { typeof(byte[]).MakeByRefType(), typeof(int), t});
+                    var body = Expression.Call(
+                        Expression.Convert(param0, formatterType),
+                        serializeMethodInfo,
+                        param1,
+                        param2,
+                        ti.IsValueType ? Expression.Unbox(param3, t) : Expression.Convert(param3, t));
+                    var lambda = Expression.Lambda<JTNESerializeMethod>(body, param0, param1, param2, param3).Compile();
+                    formatterAndDelegate = (objFormatter, lambda);
+                }
+                jTNESerializers.TryAdd(t, formatterAndDelegate);
+            }
+            return formatterAndDelegate.SerializeMethod(formatterAndDelegate.Value,ref bytes, offset, value);
+        }
+
+        public static dynamic JTNEDynamicDeserialize(object objFormatter,ReadOnlySpan<byte> bytes, out int readSize)
+        {
+            var type = objFormatter.GetType();
+            (object Value, JTNEDeserializeMethod DeserializeMethod) formatterAndDelegate;
+            if (!jTNEDeserializes.TryGetValue(type, out formatterAndDelegate))
+            {
+                var t = type;
+                {
+                    var formatterType = typeof(IJTNEFormatter<>).MakeGenericType(t);
+                    ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
+                    ParameterExpression param1 = Expression.Parameter(typeof(ReadOnlySpan<byte>), "bytes");
+                    ParameterExpression param2 = Expression.Parameter(typeof(int).MakeByRefType(), "readSize");
+                    var deserializeMethodInfo = type.GetRuntimeMethod("Deserialize", new[] { typeof(ReadOnlySpan<byte>), typeof(int).MakeByRefType() });
+                    var body = Expression.Call(
+                        Expression.Convert(param0, type),
+                        deserializeMethodInfo,
+                        param1,
+                        param2
+                        );
+                    var lambda = Expression.Lambda<JTNEDeserializeMethod>(body, param0, param1, param2).Compile();
+                    formatterAndDelegate = (objFormatter, lambda);
+                }
+                jTNEDeserializes.TryAdd(t, formatterAndDelegate);
+            }
+            return formatterAndDelegate.DeserializeMethod(formatterAndDelegate.Value, bytes,  out readSize);
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEHexExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEHexExtensions.cs
new file mode 100644
index 0000000..a3c0cd7
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEHexExtensions.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace JTNE.Protocol.Extensions
+{
+    /// <summary>
+    /// 
+    /// ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t"
+    /// </summary>
+    public static partial class JTNEBinaryExtensions
+    {
+        public static string ToHexString(this byte[] source)
+        {
+            return HexUtil.DoHexDump(source,0, source.Length).ToUpper();
+        }
+
+        public static int WriteHexStringLittle(byte[] bytes, int offset, string data, int len)
+        {
+            if (data == null) data = "";
+            data = data.Replace(" ", "");
+            int startIndex = 0;
+            if (data.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+            {
+                startIndex = 2;
+            }
+            int length = len;
+            if (length == -1)
+            {
+                length = (data.Length - startIndex) / 2;
+            }
+            int noOfZero = length * 2 + startIndex - data.Length;
+            if (noOfZero > 0)
+            {
+                data = data.Insert(startIndex, new string('0', noOfZero));
+            }
+            int byteIndex = 0;
+            while (startIndex < data.Length && byteIndex < length)
+            {
+                bytes[offset+byteIndex] = Convert.ToByte(data.Substring(startIndex, 2), 16);
+                startIndex += 2;
+                byteIndex++;
+            }
+            return length;
+        }
+
+        /// <summary>
+        /// 16进制字符串转16进制数组
+        /// </summary>
+        /// <param name="hexString"></param>
+        /// <param name="separator"></param>
+        /// <returns></returns>
+        public static byte[] ToHexBytes(this string hexString)
+        {
+            hexString = hexString.Replace(" ", "");
+            byte[] buf = new byte[hexString.Length / 2];
+            ReadOnlySpan<char> readOnlySpan = hexString.AsSpan();
+            for (int i = 0; i < hexString.Length; i++)
+            {
+                if (i % 2 == 0)
+                {
+                    buf[i / 2] = Convert.ToByte(readOnlySpan.Slice(i, 2).ToString(), 16);
+                }
+            }
+            return buf;
+        }
+
+        public static string ReadHexStringLittle(ReadOnlySpan<byte> read, ref int offset, int len)
+        {
+            ReadOnlySpan<byte> source = read.Slice(offset, len);
+            string hex = HexUtil.DoHexDump(read, offset, len);
+            offset += len;
+            return hex;
+        }
+
+        /// <summary>
+        /// ref dotnetty 
+        /// </summary>
+        static class HexUtil
+        {
+            static readonly char[] HexdumpTable = new char[256 * 4];
+
+            static HexUtil()
+            {
+                char[] digits = "0123456789abcdef".ToCharArray();
+                for (int i = 0; i < 256; i++)
+                {
+                    HexdumpTable[i << 1] = digits[(int)((uint)i >> 4 & 0x0F)];
+                    HexdumpTable[(i << 1) + 1] = digits[i & 0x0F];
+                }
+            }
+
+            public static string DoHexDump(ReadOnlySpan<byte> buffer, int fromIndex, int length)
+            {
+                if (length == 0)
+                {
+                    return "";
+                }
+                int endIndex = fromIndex + length;
+                var buf = new char[length << 1];
+                int srcIdx = fromIndex;
+                int dstIdx = 0;
+                for (; srcIdx < endIndex; srcIdx++, dstIdx += 2)
+                {
+                    Array.Copy(HexdumpTable, buffer[srcIdx] << 1,buf, dstIdx, 2);
+                }
+                return new string(buf);
+            }
+
+            public static string DoHexDump(byte[] array, int fromIndex, int length)
+            {
+                if (length == 0)
+                {
+                    return "";
+                }
+                int endIndex = fromIndex + length;
+                var buf = new char[length << 1];
+                int srcIdx = fromIndex;
+                int dstIdx = 0;
+                for (; srcIdx < endIndex; srcIdx++, dstIdx += 2)
+                {
+                    Array.Copy(HexdumpTable, (array[srcIdx] & 0xFF) << 1, buf, dstIdx, 2);
+               }
+                return new string(buf);
+            }
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEStringExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEStringExtensions.cs
new file mode 100644
index 0000000..6f91618
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEStringExtensions.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Buffers.Binary;
+using System.Buffers;
+
+namespace JTNE.Protocol.Extensions
+{
+    public static partial class JTNEBinaryExtensions
+    {
+        public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset, int len)
+        {
+            string value = JTNEGlobalConfigs.Instance.Encoding.GetString(read.Slice(offset, len).ToArray());
+            offset += len;
+            return value.Trim('\0');
+        }
+
+        public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset)
+        {
+            string value = JTNEGlobalConfigs.Instance.Encoding.GetString(read.Slice(offset).ToArray());
+            offset += value.Length;
+            return value.Trim('\0');
+        }
+
+        public static int WriteStringLittle(byte[] bytes, int offset, string data)
+        {
+            byte[] codeBytes = JTNEGlobalConfigs.Instance.Encoding.GetBytes(data);
+            Array.Copy(codeBytes, 0, bytes, offset, codeBytes.Length);
+            return codeBytes.Length;
+        }
+
+        public static int WriteStringLittle(byte[] bytes, int offset, string data, int len)
+        {
+            byte[] tempBytes = null;
+            if (string.IsNullOrEmpty(data))
+            {
+                tempBytes = new byte[0];
+            }
+            else
+            {
+                tempBytes = JTNEGlobalConfigs.Instance.Encoding.GetBytes(data);
+            }
+            byte[] rBytes = new byte[len];
+            for (int i = 0; i < tempBytes.Length; i++)
+            {
+                if (i >= len) break;
+                rBytes[i] = tempBytes[i];
+            }
+            Array.Copy(rBytes, 0, bytes, offset, rBytes.Length);
+            return rBytes.Length;
+        }
+
+        public static int WriteStringPadLeftLittle(byte[] bytes, int offset, string data, int len)
+        {
+            data = data.PadLeft(len, '\0');
+            byte[] codeBytes = JTNEGlobalConfigs.Instance.Encoding.GetBytes(data);
+            Array.Copy(codeBytes, 0, bytes, offset, codeBytes.Length);
+            return codeBytes.Length;
+        }
+
+        public static int WriteStringPadRightLittle(byte[] bytes, int offset, string data, int len)
+        {
+            data = data.PadRight(len, '\0');
+            byte[] codeBytes = JTNEGlobalConfigs.Instance.Encoding.GetBytes(data);
+            Array.Copy(codeBytes, 0, bytes, offset, codeBytes.Length);
+            return codeBytes.Length;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Extensions/JTNEXorExtensions.cs b/src/JTNE.Protocol/Extensions/JTNEXorExtensions.cs
new file mode 100644
index 0000000..e764aea
--- /dev/null
+++ b/src/JTNE.Protocol/Extensions/JTNEXorExtensions.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace JTNE.Protocol.Extensions
+{
+    public static partial class JTNEBinaryExtensions
+    {
+        /// <summary>
+        /// 异或
+        /// </summary>
+        /// <param name="buf"></param>
+        /// <param name="offset"></param>
+        /// <param name="len"></param>
+        /// <returns></returns>
+        public static byte ToXor(this byte[] buf, int offset, int len)
+        {
+            byte result = buf[offset];
+            for (int i = offset + 1; i < len; i++)
+            {
+                result = (byte)(result ^ buf[i]);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 异或
+        /// </summary>
+        /// <param name="buf"></param>
+        /// <param name="offset"></param>
+        /// <param name="len"></param>
+        /// <returns></returns>
+        public static byte ToXor(this ReadOnlySpan<byte> buf, int offset, int len)
+        {
+            byte result = buf[offset];
+            for (int i = offset + 1; i < len; i++)
+            {
+                result = (byte)(result ^ buf[i]);
+            }
+            return result;
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/Formatters/IJTNEFormatterOfT.cs b/src/JTNE.Protocol/Formatters/IJTNEFormatterOfT.cs
new file mode 100644
index 0000000..c772b5f
--- /dev/null
+++ b/src/JTNE.Protocol/Formatters/IJTNEFormatterOfT.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Buffers;
+
+namespace JTNE.Protocol.Formatters
+{
+    public interface IJTNEFormatter<T> 
+    {
+        T Deserialize(ReadOnlySpan<byte> bytes,  out int readSize);
+
+        int Serialize(ref byte[] bytes, int offset, T value);
+    }
+}
diff --git a/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs b/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs
new file mode 100644
index 0000000..c80e4af
--- /dev/null
+++ b/src/JTNE.Protocol/Formatters/JTNEPackageFormatter.cs
@@ -0,0 +1,43 @@
+using JTNE.Protocol.Enums;
+using JTNE.Protocol.Exceptions;
+using JTNE.Protocol.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol.Formatters
+{
+    public class JTNEPackageFormatter : IJTNEFormatter<JTNEPackage>
+    {
+        public JTNEPackage Deserialize(ReadOnlySpan<byte> bytes, out int readSize)
+        {
+            int offset = 0;
+            // 1.进行固定头校验
+            if (bytes[offset] != JTNEPackage.BeginFlag && bytes[offset+1] == JTNEPackage.BeginFlag)
+                throw new JTNEException(JTNEErrorCode.BeginFlagError, $"{bytes[offset]},{bytes[offset + 1]}");
+            // 2.进行BCC校验码
+            // 校验位 = 报文长度 - 最后一位(校验位)
+            byte bCCCode = bytes[bytes.Length - 1];
+            byte bCCCode2 = bytes.ToXor(2, bytes.Length - 1);
+            if (bCCCode != bCCCode2)
+                throw new JTNEException(JTNEErrorCode.BCCCodeError, $"request:{bCCCode}!=calculate:{bCCCode2}");
+            JTNEPackage jTNEPackage = new JTNEPackage();
+            offset += 2;
+            jTNEPackage.MsgId = JTNEBinaryExtensions.ReadByteLittle(bytes, ref offset);
+            jTNEPackage.AskId = JTNEBinaryExtensions.ReadByteLittle(bytes, ref offset);
+            jTNEPackage.VIN = JTNEBinaryExtensions.ReadStringLittle(bytes, ref offset,17);
+            jTNEPackage.EncryptMethod = JTNEBinaryExtensions.ReadByteLittle(bytes, ref offset);
+            jTNEPackage.DataUnitLength = JTNEBinaryExtensions.ReadUInt16Little(bytes, ref offset);
+            //todo:解码
+            jTNEPackage.Bodies = JTNEBinaryExtensions.ReadBytesLittle(bytes, ref offset, jTNEPackage.DataUnitLength);
+            jTNEPackage.BCCCode = JTNEBinaryExtensions.ReadByteLittle(bytes, ref offset);
+            readSize = offset;
+            return jTNEPackage;
+        }
+
+        public int Serialize(ref byte[] bytes, int offset, JTNEPackage value)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/JTNE.Protocol.csproj b/src/JTNE.Protocol/JTNE.Protocol.csproj
index 6c50f01..f77f861 100644
--- a/src/JTNE.Protocol/JTNE.Protocol.csproj
+++ b/src/JTNE.Protocol/JTNE.Protocol.csproj
@@ -18,7 +18,7 @@
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
-    <DocumentationFile>D:\My Project\JTNewEnergy\src\JTNE.Protocol\JTNE.Protocol.xml</DocumentationFile>
+    <DocumentationFile></DocumentationFile>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
diff --git a/src/JTNE.Protocol/JTNEArrayPool.cs b/src/JTNE.Protocol/JTNEArrayPool.cs
new file mode 100644
index 0000000..57e1965
--- /dev/null
+++ b/src/JTNE.Protocol/JTNEArrayPool.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol
+{
+    internal static class JTNEArrayPool
+    {
+        private readonly static ArrayPool<byte> ArrayPool;
+
+        static JTNEArrayPool()
+        {
+            ArrayPool = ArrayPool<byte>.Create();
+        }
+
+        public static byte[] Rent(int minimumLength)
+        {
+            return ArrayPool.Rent(minimumLength);
+        }
+
+        public static void Return(byte[] array, bool clearArray = false)
+        {
+             ArrayPool.Return(array, clearArray);
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/JTNEBodies.cs b/src/JTNE.Protocol/JTNEBodies.cs
new file mode 100644
index 0000000..50e4958
--- /dev/null
+++ b/src/JTNE.Protocol/JTNEBodies.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JTNE.Protocol
+{
+    /// <summary>
+    /// 数据体
+    /// </summary>
+    public abstract class JTNEBodies
+    {
+    }
+}
diff --git a/src/JTNE.Protocol/JTNEGlobalConfigs.cs b/src/JTNE.Protocol/JTNEGlobalConfigs.cs
new file mode 100644
index 0000000..a0943ab
--- /dev/null
+++ b/src/JTNE.Protocol/JTNEGlobalConfigs.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Text;
+
+namespace JTNE.Protocol
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    public class JTNEGlobalConfigs
+    {
+        private static readonly Lazy<JTNEGlobalConfigs> instance = new Lazy<JTNEGlobalConfigs>(() => new JTNEGlobalConfigs());
+
+        private JTNEGlobalConfigs()
+        {
+            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+            Encoding = Encoding.UTF8;
+        }
+        /// <summary>
+        /// 字符串编码
+        /// </summary>
+        public Encoding Encoding { get; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        public static JTNEGlobalConfigs Instance
+        {
+            get
+            {
+                return instance.Value;
+            }
+        }
+    }
+}
diff --git a/src/JTNE.Protocol/JTNEPackage.cs b/src/JTNE.Protocol/JTNEPackage.cs
index df5ff63..30b475a 100644
--- a/src/JTNE.Protocol/JTNEPackage.cs
+++ b/src/JTNE.Protocol/JTNEPackage.cs
@@ -1,4 +1,6 @@
-using System;
+using JTNE.Protocol.Attributes;
+using JTNE.Protocol.Formatters;
+using System;
 using System.IO;
 
 namespace JTNE.Protocol
@@ -6,23 +8,31 @@ namespace JTNE.Protocol
     /// <summary>
     /// 新能源包
     /// </summary>
+    [JTNEFormatter(typeof(JTNEPackageFormatter))]
     public class JTNEPackage
     {
         /// <summary>
         /// 固定为24个字节长度
         /// </summary>
-        public const int HeaderFixedByteLength = 24;
+        //public const int HeaderFixedByteLength = 24;
+
+        public const byte BeginFlag = 0x23;
+        /// <summary>
+        /// 起始符1
+        /// </summary>
+        public byte BeginFlag1 { get; set; } = 0x23;
         /// <summary>
-        /// 起始符 
-        /// 0x23
+        /// 起始符2 
         /// </summary>
-        public string BeginFlag { get; set; } = "##";
+        public byte BeginFlag2 { get; set; } = 0x23;
         /// <summary>
         /// 命令标识 
+        /// <see cref="JTNE.Protocol.Enums.JTNEMsgId"/>
         /// </summary>
         public byte MsgId { get; set; }
         /// <summary>
         /// 应答标志 
+        /// <see cref="JTNE.Protocol.Enums.JTNEAskId"/>
         /// </summary>
         public byte AskId { get; set; }
         /// <summary>
@@ -32,16 +42,17 @@ namespace JTNE.Protocol
         /// <summary>
         /// 数据加密方式 
         /// 0x01:数据不加密;0x02:数据经过 RSA 算法加密;0x03:数据经过 AES128 位算法加密;“0xFE”表示异常,“0xFF”表示无效
+        /// <see cref="JTNE.Protocol.Enums.JTNEEncryptMethod"/>
         /// </summary>
         public byte EncryptMethod { get; set; }
         /// <summary>
         /// 数据单元长度是数据单元的总字节数,有效值范围:0-65531
         /// </summary>
         public ushort DataUnitLength { get; set; }
-        ///// <summary>
-        ///// 数据体
-        ///// </summary>
-        //public NEBodies Bodies { get; protected set; }
+        /// <summary>
+        /// 数据体
+        /// </summary>
+        public byte[] Bodies { get; set; }
         /// <summary>
         /// 采用BCC(异或检验)法,校验范围从命令单元的第一个字节开始,同后一个字节异或,直到校验码前一个字节为止,
         /// 校验码占用一个字节,当数据单元存在加密时,应先加密后检验,先校验后解密
diff --git a/src/JTNE.Protocol/JTNESerializer.cs b/src/JTNE.Protocol/JTNESerializer.cs
new file mode 100644
index 0000000..b5165e5
--- /dev/null
+++ b/src/JTNE.Protocol/JTNESerializer.cs
@@ -0,0 +1,49 @@
+using JTNE.Protocol.Extensions;
+using System;
+
+namespace JTNE.Protocol
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    public static class JTNESerializer
+    {
+        public static byte[] Serialize(JTNEPackage jTNEPackage, int minBufferSize = 1024)
+        {
+            return Serialize<JTNEPackage>(jTNEPackage, minBufferSize);
+        }
+
+        public static JTNEPackage Deserialize(ReadOnlySpan<byte> bytes)
+        {
+            return Deserialize<JTNEPackage>(bytes);
+        }
+
+        public static byte[] Serialize<T>(T obj, int minBufferSize = 1024)
+        {
+            var formatter = JTNEFormatterExtensions.GetFormatter<T>();
+            byte[] buffer = JTNEArrayPool.Rent(minBufferSize);
+            try
+            {
+                var len = formatter.Serialize(ref buffer, 0, obj);
+                return buffer.AsSpan(0, len).ToArray();
+            }
+            finally
+            {
+                JTNEArrayPool.Return(buffer);
+            }
+        }
+
+        public static T Deserialize<T>(ReadOnlySpan<byte> bytes)
+        {
+            var formatter = JTNEFormatterExtensions.GetFormatter<T>();
+            int readSize;
+            return formatter.Deserialize(bytes,out readSize);
+        }
+
+        public static dynamic Deserialize(ReadOnlySpan<byte> bytes,Type type)
+        {
+            var formatter = JTNEFormatterExtensions.GetFormatter(type);
+            return JTNEFormatterResolverExtensions.JTNEDynamicDeserialize(formatter,bytes,out int readSize);
+        }
+    }
+}
diff --git a/src/JTNewEnergy.sln b/src/JTNewEnergy.sln
index 1d97cf2..a2ab150 100644
--- a/src/JTNewEnergy.sln
+++ b/src/JTNewEnergy.sln
@@ -1,9 +1,15 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28407.52
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.271
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JTNE.Protocol", "JTNE.Protocol\JTNE.Protocol.csproj", "{5B164F58-141D-474E-A82E-672A1C252029}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JTNE.Protocol", "JTNE.Protocol\JTNE.Protocol.csproj", "{5B164F58-141D-474E-A82E-672A1C252029}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GBNewEnergy.Protocol", "GBNewEnergy.Protocol\GBNewEnergy.Protocol.csproj", "{2E21E873-F9EA-4B98-80D6-9719DC924350}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JTNE.Protocol.Test", "JTNE.Protocol.Test\JTNE.Protocol.Test.csproj", "{30BB532E-4E49-4BB4-A1D4-61DC40F320DB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GBNewEnergy.Protocol.Test", "GBNewEnergy.Protocol.Test\GBNewEnergy.Protocol.Test.csproj", "{E8A2DBC3-3384-408F-A9D0-247723EFE383}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +21,18 @@ Global
 		{5B164F58-141D-474E-A82E-672A1C252029}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{5B164F58-141D-474E-A82E-672A1C252029}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{5B164F58-141D-474E-A82E-672A1C252029}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2E21E873-F9EA-4B98-80D6-9719DC924350}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2E21E873-F9EA-4B98-80D6-9719DC924350}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2E21E873-F9EA-4B98-80D6-9719DC924350}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2E21E873-F9EA-4B98-80D6-9719DC924350}.Release|Any CPU.Build.0 = Release|Any CPU
+		{30BB532E-4E49-4BB4-A1D4-61DC40F320DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{30BB532E-4E49-4BB4-A1D4-61DC40F320DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{30BB532E-4E49-4BB4-A1D4-61DC40F320DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{30BB532E-4E49-4BB4-A1D4-61DC40F320DB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E8A2DBC3-3384-408F-A9D0-247723EFE383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E8A2DBC3-3384-408F-A9D0-247723EFE383}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E8A2DBC3-3384-408F-A9D0-247723EFE383}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E8A2DBC3-3384-408F-A9D0-247723EFE383}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE