@@ -23,15 +23,15 @@ | |||
### 数据头[JT808Header] | |||
| 消息ID | 消息体属性 | 终端手机号 | 消息流水号 | 消息总包数(依赖是否分包) | 包序号(依赖是否分包) | | |||
| :----: | :----------------------------: | :-------------: | :--------: |:---------: | :-------:| | |||
| MsgId | JT808HeaderMessageBodyProperty | TerminalPhoneNo | MsgNum |PackgeCount | PackageIndex | | |||
| 消息ID | 消息体属性 | 协议版本号(2019版本)|终端手机号 | 消息流水号 | 消息总包数(依赖是否分包) | 包序号(依赖是否分包) | | |||
| :----: | :----------------------------: | :-------------: |:-------------: | :--------: |:---------: | :-------:| | |||
| MsgId | JT808HeaderMessageBodyProperty | ProtocolVersion|TerminalPhoneNo | MsgNum |PackgeCount | PackageIndex | | |||
#### 数据头-消息体属性[JT808HeaderMessageBodyProperty] | |||
| 是否分包 | 加密标识 | 消息体长度 | | |||
| :------: | :------: | :--------: | | |||
| IsPackge | Encrypt | DataLength | | |||
|版本标识(2019版本)| 是否分包 | 加密标识 | 消息体长度 | | |||
|:------:| :------: | :------: | :--------: | | |||
|VersionFlag| IsPackge | Encrypt | DataLength | | |||
#### 消息体属性[JT808Bodies] | |||
@@ -306,17 +306,17 @@ Platform=AnyCpu Server=False Toolchain=.NET Core 3.0 | |||
## JT808终端通讯协议消息对照表 | |||
| 序号 | 消息ID | 完成情况 | 测试情况 | 消息体名称 | | |||
| :---: | :-----------: | :------: | :------: | :----------------------------: | | |||
| 序号 | 消息ID | 完成情况 | 测试情况 | 消息体名称 |2019版本| | |||
| :---: | :-----------: | :------: | :------: | :----------------------------: |:----------------------------:| | |||
| 1 | 0x0001 | √ | √ | 终端通用应答 | | |||
| 2 | 0x8001 | √ | √ | 平台通用应答 | | |||
| 3 | 0x0002 | √ | √ | 终端心跳 | | |||
| 4 | 0x8003 | √ | √ | 补传分包请求 | | |||
| 5 | 0x0100 | √ | √ | 终端注册 | | |||
| 5 | 0x0100 | √ | √ | 终端注册 |修改| | |||
| 6 | 0x8100 | √ | √ | 终端注册应答 | | |||
| 7 | 0x0003 | √ | √ | 终端注销 | | |||
| 8 | 0x0102 | √ | √ | 终端鉴权 | | |||
| 9 | 0x8103 | √ | √ | 设置终端参数 | | |||
| 8 | 0x0102 | √ | √ | 终端鉴权 |修改| | |||
| 9 | 0x8103 | √ | x | 设置终端参数 |修改且增加| | |||
| 10 | 0x8104 | √ | √ | 查询终端参数 | | |||
| 11 | 0x0104 | √ | √ | 查询终端参数应答 | | |||
| 12 | 0x8105 | √ | √ | 终端控制 | | |||
@@ -350,9 +350,9 @@ Platform=AnyCpu Server=False Toolchain=.NET Core 3.0 | |||
| 40 | 0x8605 | √ | √ | 删除多边形区域 | | |||
| 41 | 0x8606 | √ | √ | 设置路线 | | |||
| 42 | 0x8607 | √ | √ | 删除路线 | | |||
| 43 | 0x8700 | x | 下个版本 | 行驶记录仪数据采集命令 | | |||
| 44 | 0x0700 | x | 下个版本 | 行驶记录仪数据上传 | | |||
| 45 | 0x8701 | x | 下个版本 | 行驶记录仪参数下传命令 | | |||
| 43 | 0x8700 | x | 不开发 | 行驶记录仪数据采集命令 | | |||
| 44 | 0x0700 | x | 不开发 | 行驶记录仪数据上传 | | |||
| 45 | 0x8701 | x | 不开发 | 行驶记录仪参数下传命令 | | |||
| 46 | 0x0701 | √ | √ | 电子运单上报 | | |||
| 47 | 0x0702 | √ | √ | 驾驶员身份信息采集上报 | | |||
| 48 | 0x8702 | √ | 消息体为空| 上报驾驶员身份信息请求 | | |||
@@ -375,3 +375,6 @@ Platform=AnyCpu Server=False Toolchain=.NET Core 3.0 | |||
| 65 | 0x0A00 | √ | √ | 终端 RSA 公钥 | | |||
| 66 | 0x8F00~0x8FFF | 保留 | 保留 | 平台下行消息保留 | | |||
| 67 | 0x0F00~0x0FFF | 保留 | 保留 | 终端上行消息保留 | | |||
| 68 | 0x0004 | √ | √ | 查询服务器时间请求 |新增| | |||
| 69 | 0x8004 | √ | √ | 查询服务器时间应答 |新增| | |||
| 70 | 0x0005 | √ | √ | 终端补传分包请求 |新增| |
@@ -56,6 +56,8 @@ | |||
<Compile Include="MessageBody\JT808_0x0901Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x0A00Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x8001Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x0005Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x8004Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x8003Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x8100Test.cs" /> | |||
<Compile Include="MessageBody\JT808_0x8103CustomIdExtensions\JT808_0x8103_0x0075.cs" /> | |||
@@ -94,6 +96,10 @@ | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
</PackageReference> | |||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" /> | |||
<PackageReference Include="NETStandard.Library" Version="2.0.3" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> | |||
@@ -27,5 +27,49 @@ namespace JT808.Protocol.Test | |||
Assert.True(jT808HeaderMessageBodyProperty.IsPackage); | |||
Assert.Equal(JT808EncryptMethod.RSA, jT808HeaderMessageBodyProperty.Encrypt); | |||
} | |||
[Fact] | |||
public void Test2019_1() | |||
{ | |||
//01 1 001 0011111111 | |||
JT808HeaderMessageBodyProperty jT808HeaderMessageBodyProperty = new JT808HeaderMessageBodyProperty(); | |||
jT808HeaderMessageBodyProperty.DataLength = 255; | |||
jT808HeaderMessageBodyProperty.IsPackage = true; | |||
jT808HeaderMessageBodyProperty.Encrypt = JT808EncryptMethod.RSA; | |||
jT808HeaderMessageBodyProperty.VersionFlag = true; | |||
var result = jT808HeaderMessageBodyProperty.Wrap(); | |||
Assert.Equal(25855, result); | |||
} | |||
[Fact] | |||
public void Test2019_2() | |||
{ | |||
JT808HeaderMessageBodyProperty jT808HeaderMessageBodyProperty = new JT808HeaderMessageBodyProperty(25855); | |||
Assert.Equal(255, jT808HeaderMessageBodyProperty.DataLength); | |||
Assert.True(jT808HeaderMessageBodyProperty.IsPackage); | |||
Assert.True(jT808HeaderMessageBodyProperty.VersionFlag); | |||
Assert.Equal(JT808EncryptMethod.RSA, jT808HeaderMessageBodyProperty.Encrypt); | |||
} | |||
[Fact] | |||
public void Test2019_3() | |||
{ | |||
JT808HeaderMessageBodyProperty jT808HeaderMessageBodyProperty = new JT808HeaderMessageBodyProperty(); | |||
jT808HeaderMessageBodyProperty.DataLength = 255; | |||
jT808HeaderMessageBodyProperty.IsPackage = false; | |||
jT808HeaderMessageBodyProperty.Encrypt = JT808EncryptMethod.RSA; | |||
jT808HeaderMessageBodyProperty.VersionFlag = true; | |||
ushort result = jT808HeaderMessageBodyProperty.Wrap(); | |||
Assert.Equal(17663, result); | |||
} | |||
[Fact] | |||
public void Test2019_4() | |||
{ | |||
JT808HeaderMessageBodyProperty jT808HeaderMessageBodyProperty = new JT808HeaderMessageBodyProperty(17663); | |||
Assert.Equal(255, jT808HeaderMessageBodyProperty.DataLength); | |||
Assert.False(jT808HeaderMessageBodyProperty.IsPackage); | |||
Assert.True(jT808HeaderMessageBodyProperty.VersionFlag); | |||
Assert.Equal(JT808EncryptMethod.RSA, jT808HeaderMessageBodyProperty.Encrypt); | |||
} | |||
} | |||
} |
@@ -8,6 +8,7 @@ namespace JT808.Protocol.Test | |||
public class JT808HeaderTest | |||
{ | |||
JT808Serializer JT808Serializer = new JT808Serializer(); | |||
[Fact] | |||
public void Test3() | |||
{ | |||
@@ -34,7 +35,7 @@ namespace JT808.Protocol.Test | |||
jT808HeaderProperty.MsgId = JT808MsgId.终端鉴权.ToUInt16Value(); | |||
var hex = JT808Serializer.Serialize(jT808HeaderProperty).ToHexString(); | |||
Assert.Equal("01 02 00 05 01 38 12 34 56 78 00 87".Replace(" ",""), hex); | |||
Assert.Equal("01 02 00 05 01 38 12 34 56 78 00 87".Replace(" ", ""), hex); | |||
} | |||
[Fact] | |||
@@ -75,5 +76,39 @@ namespace JT808.Protocol.Test | |||
Assert.Equal(JT808MsgId.终端鉴权.ToValue(), jT808Header.MsgId); | |||
Assert.Equal(5, jT808Header.MessageBodyProperty.DataLength); | |||
} | |||
[Fact] | |||
public void JT808Header_2019Test1() | |||
{ | |||
JT808Header jT808HeaderProperty = new JT808Header | |||
{ | |||
TerminalPhoneNo = "13812345678" | |||
}; | |||
JT808HeaderMessageBodyProperty jT808HeaderMessageBodyProperty = new JT808HeaderMessageBodyProperty(); | |||
jT808HeaderMessageBodyProperty.DataLength = 255; | |||
jT808HeaderMessageBodyProperty.IsPackage = true; | |||
jT808HeaderMessageBodyProperty.Encrypt = JT808EncryptMethod.RSA; | |||
jT808HeaderMessageBodyProperty.VersionFlag = true; | |||
jT808HeaderProperty.MessageBodyProperty = jT808HeaderMessageBodyProperty; | |||
jT808HeaderProperty.MsgNum = 135; | |||
jT808HeaderProperty.MsgId = JT808MsgId.终端鉴权.ToUInt16Value(); | |||
jT808HeaderProperty.ProtocolVersion = 2; | |||
var hex = JT808Serializer.Serialize(jT808HeaderProperty).ToHexString(); | |||
Assert.Equal("010264FF0200000000013812345678008700000000", hex); | |||
} | |||
[Fact] | |||
public void JT808Header_2019Test2() | |||
{ | |||
byte[] headerBytes = "010264FF0200000000013812345678008700000000".ToHexBytes(); | |||
JT808Header jT808Header = JT808Serializer.Deserialize<JT808Header>(headerBytes); | |||
Assert.Equal(135, jT808Header.MsgNum); | |||
Assert.Equal(2, jT808Header.ProtocolVersion); | |||
Assert.Equal("13812345678", jT808Header.TerminalPhoneNo); | |||
Assert.True(jT808Header.MessageBodyProperty.IsPackage); | |||
Assert.True(jT808Header.MessageBodyProperty.VersionFlag); | |||
Assert.Equal(JT808MsgId.终端鉴权.ToValue(), jT808Header.MsgId); | |||
Assert.Equal(255, jT808Header.MessageBodyProperty.DataLength); | |||
} | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
using System.Text; | |||
using Xunit; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.MessageBody; | |||
namespace JT808.Protocol.Test.MessageBody | |||
{ | |||
public class JT808_0x0005Test | |||
{ | |||
JT808Serializer JT808Serializer = new JT808Serializer(); | |||
[Fact] | |||
public void Test1() | |||
{ | |||
JT808_0x0005 jT808_0X8005 = new JT808_0x0005 | |||
{ | |||
OriginalMsgNum = 1234, | |||
AgainPackageData = new byte[] { 0x01, 0x02, 0x02, 0x03 } | |||
}; | |||
var hex = JT808Serializer.Serialize(jT808_0X8005).ToHexString(); | |||
Assert.Equal("04D20201020203", hex); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
var bytes = "04D20201020203".ToHexBytes(); | |||
JT808_0x0005 jT808_0X8005 = JT808Serializer.Deserialize<JT808_0x0005>(bytes); | |||
Assert.Equal(1234, jT808_0X8005.OriginalMsgNum); | |||
Assert.Equal(new byte[] { 0x01, 0x02, 0x02, 0x03 }, jT808_0X8005.AgainPackageData); | |||
Assert.Equal(2, jT808_0X8005.AgainPackageCount); | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using Xunit; | |||
using JT808.Protocol.MessageBody; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.Enums; | |||
namespace JT808.Protocol.Test.MessageBody | |||
{ | |||
@@ -52,5 +53,56 @@ namespace JT808.Protocol.Test.MessageBody | |||
Assert.Equal("CHI1230", JT808Bodies.TerminalId); | |||
Assert.Equal("smallchi123000000000", JT808Bodies.TerminalModel); | |||
} | |||
[Fact] | |||
public void Test2019_1() | |||
{ | |||
JT808Package jT808_0X0100 = new JT808Package | |||
{ | |||
Header = new JT808Header | |||
{ | |||
MsgId = Enums.JT808MsgId.终端注册.ToUInt16Value(), | |||
MsgNum = 10, | |||
TerminalPhoneNo = "123456789", | |||
ProtocolVersion=1, | |||
}, | |||
Bodies = new JT808_0x0100 | |||
{ | |||
AreaID = 40, | |||
CityOrCountyId = 50, | |||
MakerId = "1234", | |||
PlateColor = 1, | |||
PlateNo = "粤A12345", | |||
TerminalId = "CHI123", | |||
TerminalModel = "smallchi123" | |||
} | |||
}; | |||
JT808HeaderMessageBodyProperty jT808HeaderMessageBodyProperty = new JT808HeaderMessageBodyProperty(true); | |||
jT808_0X0100.Header.MessageBodyProperty = jT808HeaderMessageBodyProperty; | |||
var hex = JT808Serializer.Serialize(jT808_0X0100).ToHexString(); | |||
Assert.Equal("7E010040540100000000000123456789000A00280032303030303030303132333430303030303030303030303030303030303030736D616C6C63686931323330303030303030303030303030303030303030303030303043484931323301D4C1413132333435B27E", hex); | |||
} | |||
[Fact] | |||
public void Test2019_2() | |||
{ | |||
byte[] bytes = "7E010040540100000000000123456789000A00280032303030303030303132333430303030303030303030303030303030303030736D616C6C63686931323330303030303030303030303030303030303030303030303043484931323301D4C1413132333435B27E".ToHexBytes(); | |||
JT808Package jT808_0X0100 = JT808Serializer.Deserialize<JT808Package>(bytes); | |||
Assert.Equal(JT808MsgId.终端注册.ToUInt16Value(), jT808_0X0100.Header.MsgId); | |||
Assert.Equal(1, jT808_0X0100.Header.ProtocolVersion); | |||
Assert.Equal(JT808Version.JTT2019, jT808_0X0100.Version); | |||
Assert.True(jT808_0X0100.Header.MessageBodyProperty.VersionFlag); | |||
Assert.Equal(10, jT808_0X0100.Header.MsgNum); | |||
Assert.Equal("123456789", jT808_0X0100.Header.TerminalPhoneNo); | |||
JT808_0x0100 JT808Bodies = (JT808_0x0100)jT808_0X0100.Bodies; | |||
Assert.Equal(40, JT808Bodies.AreaID); | |||
Assert.Equal(50, JT808Bodies.CityOrCountyId); | |||
Assert.Equal("1234".PadLeft(11,'0'), JT808Bodies.MakerId); | |||
Assert.Equal(1, JT808Bodies.PlateColor); | |||
Assert.Equal("粤A12345", JT808Bodies.PlateNo); | |||
Assert.Equal("CHI123".PadLeft(30, '0'), JT808Bodies.TerminalId); | |||
Assert.Equal("smallchi123".PadLeft(30, '0'), JT808Bodies.TerminalModel); | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using Xunit; | |||
using JT808.Protocol.MessageBody; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.Enums; | |||
namespace JT808.Protocol.Test.MessageBody | |||
{ | |||
@@ -26,6 +27,30 @@ namespace JT808.Protocol.Test.MessageBody | |||
Assert.Equal("45612", jT808LoginRequest.Code); | |||
} | |||
[Fact] | |||
public void Test2019_1() | |||
{ | |||
JT808_0x0102 jT808LoginRequestProperty = new JT808_0x0102 | |||
{ | |||
Code = "45612", | |||
IMEI="1234567890abcde", | |||
SoftwareVersion="v2.0.0" | |||
}; | |||
string hex = JT808Serializer.Serialize(jT808LoginRequestProperty,JT808Version.JTT2019).ToHexString(); | |||
Assert.Equal("05343536313231323334353637383930616263646576322E302E303030303030303030303030303030", hex); | |||
} | |||
[Fact] | |||
public void Test2019_2() | |||
{ | |||
byte[] bodys = "05343536313231323334353637383930616263646576322E302E303030303030303030303030303030".ToHexBytes(); | |||
JT808_0x0102 jT808LoginRequest = JT808Serializer.Deserialize<JT808_0x0102>(bodys, JT808Version.JTT2019); | |||
Assert.Equal("45612", jT808LoginRequest.Code); | |||
Assert.Equal(5, jT808LoginRequest.CodeLength); | |||
Assert.Equal("1234567890abcde", jT808LoginRequest.IMEI); | |||
Assert.Equal("v2.0.0".PadRight(20,'0'), jT808LoginRequest.SoftwareVersion); | |||
} | |||
[Fact] | |||
public void Test3() | |||
{ | |||
@@ -0,0 +1,31 @@ | |||
using System.Text; | |||
using Xunit; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.MessageBody; | |||
using System; | |||
namespace JT808.Protocol.Test.MessageBody | |||
{ | |||
public class JT808_0x8004Test | |||
{ | |||
JT808Serializer JT808Serializer = new JT808Serializer(); | |||
[Fact] | |||
public void Test1() | |||
{ | |||
JT808_0x8004 jT808_0X8004 = new JT808_0x8004 | |||
{ | |||
Time = DateTime.Parse("2019-11-26 15:58:50") | |||
}; | |||
var hex = JT808Serializer.Serialize(jT808_0X8004).ToHexString(); | |||
Assert.Equal("191126155850", hex); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
var bytes = "191126155850".ToHexBytes(); | |||
JT808_0x8004 jT808_0X8004 = JT808Serializer.Deserialize<JT808_0x8004>(bytes); | |||
Assert.Equal(DateTime.Parse("2019-11-26 15:58:50"), jT808_0X8004.Time); | |||
} | |||
} | |||
} |
@@ -8,6 +8,7 @@ using System.Buffers; | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.Interfaces; | |||
using JT808.Protocol.Internal; | |||
using JT808.Protocol.Enums; | |||
namespace JT808.Protocol.Test.MessagePack | |||
{ | |||
@@ -228,5 +229,15 @@ namespace JT808.Protocol.Test.MessagePack | |||
} | |||
} | |||
} | |||
[Fact] | |||
public void VersionTest1() | |||
{ | |||
byte[] array = new byte[4096]; | |||
var reader = new JT808MessagePackReader(array); | |||
Assert.Equal(JT808Version.JTT2013, reader.Version); | |||
reader.Version = JT808Version.JTT2019; | |||
Assert.Equal(JT808Version.JTT2019, reader.Version); | |||
} | |||
} | |||
} |
@@ -5,6 +5,7 @@ using System.Collections.Generic; | |||
using System.Text; | |||
using Xunit; | |||
using System.Buffers; | |||
using JT808.Protocol.Enums; | |||
namespace JT808.Protocol.Test.MessagePack | |||
{ | |||
@@ -457,5 +458,15 @@ namespace JT808.Protocol.Test.MessagePack | |||
var realBytes = msgpackWriter.FlushAndGetRealArray().ToHexString(); | |||
Assert.Equal("7E 01 7E 00 7D 01 23 45 67 89 00 00 00 00 00 7E 7E 01 7D 02 00 7D 01 01 23 45 67 89 00 00 00 00 00 7E".Replace(" ", ""), realBytes); | |||
} | |||
[Fact] | |||
public void VersionTest1() | |||
{ | |||
byte[] array = new byte[4096]; | |||
var msgpackWriter = new JT808MessagePackWriter(array); | |||
Assert.Equal(JT808Version.JTT2013, msgpackWriter.Version); | |||
msgpackWriter.Version = JT808Version.JTT2019; | |||
Assert.Equal(JT808Version.JTT2019, msgpackWriter.Version); | |||
} | |||
} | |||
} |
@@ -1,17 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.Protocol.Attributes | |||
{ | |||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)] | |||
public sealed class JT808FormatterAttribute : Attribute | |||
{ | |||
public Type FormatterType { get; private set; } | |||
public JT808FormatterAttribute(Type formatterType) | |||
{ | |||
this.FormatterType = formatterType; | |||
} | |||
} | |||
} |
@@ -7,11 +7,6 @@ | |||
/// </summary> | |||
CheckCodeNotEqual = 1001, | |||
/// <summary> | |||
/// 没有标记 | |||
/// <see cref="JT808.Protocol.Attributes.JT808FormatterAttribute"/> | |||
/// </summary> | |||
GetFormatterAttributeError = 1002, | |||
/// <summary> | |||
/// 消息头解析错误 | |||
/// </summary> | |||
HeaderParseError = 1003, | |||
@@ -10,6 +10,7 @@ namespace JT808.Protocol | |||
{ | |||
public interface IJT808Config | |||
{ | |||
[Obsolete("目前没用")] | |||
JT808Version Version { get;} | |||
string ConfigId { get; } | |||
/// <summary> | |||
@@ -14,7 +14,7 @@ | |||
<licenseUrl>https://github.com/SmallChi/JT808/blob/master/LICENSE</licenseUrl> | |||
<license>https://github.com/SmallChi/JT808/blob/master/LICENSE</license> | |||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | |||
<Version>2.2.0-preview1</Version> | |||
<Version>2.2.0-preview3</Version> | |||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
@@ -65,6 +65,10 @@ | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
</PackageReference> | |||
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" /> | |||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.6.0" /> | |||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.0.0" /> | |||
@@ -213,12 +213,6 @@ | |||
校验和不相等 | |||
</summary> | |||
</member> | |||
<member name="F:JT808.Protocol.Enums.JT808ErrorCode.GetFormatterAttributeError"> | |||
<summary> | |||
没有标记 | |||
<see cref="T:JT808.Protocol.Attributes.JT808FormatterAttribute"/> | |||
</summary> | |||
</member> | |||
<member name="F:JT808.Protocol.Enums.JT808ErrorCode.HeaderParseError"> | |||
<summary> | |||
消息头解析错误 | |||
@@ -2197,10 +2191,21 @@ | |||
<see cref="T:JT808.Protocol.Enums.JT808MsgId"/> | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Header.MessageBodyProperty"> | |||
<summary> | |||
消息体属性 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Header.ProtocolVersion"> | |||
<summary> | |||
协议版本号(2019版本) | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Header.TerminalPhoneNo"> | |||
<summary> | |||
终端手机号 | |||
根据安装后终端自身的手机号转换。手机号不足 12 位,则在前补充数字,大陆手机号补充数字 0,港澳台则根据其区号进行位数补充 | |||
(2019版本)手机号不足 20 位,则在前补充数字 0 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Header.MsgNum"> | |||
@@ -2221,6 +2226,11 @@ | |||
报序号 从1开始 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808HeaderMessageBodyProperty.VersionFlag"> | |||
<summary> | |||
版本标识(默认为1=true) | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808HeaderMessageBodyProperty.IsPackage"> | |||
<summary> | |||
是否分包 | |||
@@ -2292,9 +2302,14 @@ | |||
起始符 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Package.End"> | |||
<member name="P:JT808.Protocol.JT808Package.Header"> | |||
<summary> | |||
终止符 | |||
头数据 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Package.Bodies"> | |||
<summary> | |||
数据体 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Package.CheckCode"> | |||
@@ -2303,17 +2318,17 @@ | |||
从消息头开始,同后一字节异或,直到校验码前一个字节,占用一个字节。 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Package.Header"> | |||
<member name="P:JT808.Protocol.JT808Package.End"> | |||
<summary> | |||
头数据 | |||
终止符 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.JT808Package.Bodies"> | |||
<member name="P:JT808.Protocol.JT808Package.Version"> | |||
<summary> | |||
数据体 | |||
808版本号 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.Protocol.JT808Serializer.HeaderDeserialize(System.ReadOnlySpan{System.Byte},System.Int32)"> | |||
<member name="M:JT808.Protocol.JT808Serializer.HeaderDeserialize(System.ReadOnlySpan{System.Byte},JT808.Protocol.Enums.JT808Version,System.Int32)"> | |||
<summary> | |||
用于负载或者分布式的时候,在网关只需要解到头部。 | |||
根据头部的消息Id进行分发处理,可以防止小部分性能损耗。 | |||
@@ -2365,6 +2380,42 @@ | |||
跳过数据体序列化 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.Protocol.MessageBody.JT808_0x0004"> | |||
<summary> | |||
查询服务器时间请求 | |||
2019版本 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0004.SkipSerialization"> | |||
<summary> | |||
跳过数据体序列化 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.Protocol.MessageBody.JT808_0x0005"> | |||
<summary> | |||
终端补传分包请求 | |||
2019版本 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0005.OriginalMsgNum"> | |||
<summary> | |||
原始消息流水号 | |||
对应要求补传的原始消息第一包的消息流水号 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0005.AgainPackageCount"> | |||
<summary> | |||
重传包总数 | |||
n | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0005.AgainPackageData"> | |||
<summary> | |||
重传包 ID 列表 | |||
BYTE[2*n] | |||
重传包序号顺序排列,如“包 ID1 包 ID2......包 IDn”。 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.Protocol.MessageBody.JT808_0x0100"> | |||
<summary> | |||
终端注册 | |||
@@ -2389,21 +2440,22 @@ | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0100.MakerId"> | |||
<summary> | |||
制造商 ID | |||
5 个字节,终端制造商编码 | |||
2013版本 5 个字节,终端制造商编码 | |||
2019版本 11 个字节,终端制造商编码 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0100.TerminalModel"> | |||
<summary> | |||
终端型号 | |||
20 个字节,此终端型号由制造商自行定义,位数不 | |||
足时,后补“0X00”。 | |||
2013版本 20 个字节,此终端型号由制造商自行定义,位数不足时,后补“0X00”。 | |||
2019版本 30 个字节,此终端型号由制造商自行定义,位数不足时,后补“0X00”。 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0100.TerminalId"> | |||
<summary> | |||
终端 ID | |||
7 个字节,由大写字母和数字组成,此终端 ID 由制 | |||
造商自行定义,位数不足时,后补“0X00”。 | |||
2013版本 7个字节,由大写字母和数字组成,此终端 ID 由制造商自行定义,位数不足时,后补“0X00”。 | |||
2019版本 30个字节,由大写字母和数字组成,此终端 ID 由制造商自行定义,位数不足时,后补“0X00”。 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0100.PlateColor"> | |||
@@ -2428,6 +2480,22 @@ | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0102.Code"> | |||
<summary> | |||
鉴权码 | |||
鉴权码内容 2019版本 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0102.CodeLength"> | |||
<summary> | |||
鉴权码长度 2019版本 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0102.IMEI"> | |||
<summary> | |||
终端IMEI 长度15 2019版本 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.Protocol.MessageBody.JT808_0x0102.SoftwareVersion"> | |||
<summary> | |||
软件版本号 长度20 后补 "0x00" 2019版本 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.Protocol.MessageBody.JT808_0x0104"> | |||
@@ -3216,6 +3284,12 @@ | |||
重传包序号顺序排列,如“包 ID1 包 ID2......包 IDn”。 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.Protocol.MessageBody.JT808_0x8004"> | |||
<summary> | |||
查询服务器时间应答 | |||
2019版本 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.Protocol.MessageBody.JT808_0x8100"> | |||
<summary> | |||
终端注册应答 | |||
@@ -5420,7 +5494,7 @@ | |||
主要用来一次性读取所有数据体内容操作 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.Protocol.MessagePack.JT808MessagePackReader.#ctor(System.ReadOnlySpan{System.Byte})"> | |||
<member name="M:JT808.Protocol.MessagePack.JT808MessagePackReader.#ctor(System.ReadOnlySpan{System.Byte},JT808.Protocol.Enums.JT808Version)"> | |||
<summary> | |||
解码(转义还原),计算校验和 | |||
</summary> | |||
@@ -13,10 +13,18 @@ namespace JT808.Protocol | |||
/// <see cref="JT808.Protocol.Enums.JT808MsgId"/> | |||
/// </summary> | |||
public ushort MsgId { get; set; } | |||
/// <summary> | |||
/// 消息体属性 | |||
/// </summary> | |||
public JT808HeaderMessageBodyProperty MessageBodyProperty { get; set; } | |||
/// <summary> | |||
/// 协议版本号(2019版本) | |||
/// </summary> | |||
public byte ProtocolVersion { get; set; } = 1; | |||
/// <summary> | |||
/// 终端手机号 | |||
/// 根据安装后终端自身的手机号转换。手机号不足 12 位,则在前补充数字,大陆手机号补充数字 0,港澳台则根据其区号进行位数补充 | |||
/// (2019版本)手机号不足 20 位,则在前补充数字 0 | |||
/// </summary> | |||
public string TerminalPhoneNo { get; set; } | |||
/// <summary> | |||
@@ -42,8 +50,20 @@ namespace JT808.Protocol | |||
jT808Header.MsgId = reader.ReadUInt16(); | |||
// 2.消息体属性 | |||
jT808Header.MessageBodyProperty = new JT808HeaderMessageBodyProperty(reader.ReadUInt16()); | |||
// 3.终端手机号 | |||
jT808Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim); | |||
if (jT808Header.MessageBodyProperty.VersionFlag) | |||
{ | |||
// 2019 版本 | |||
// 3.协议版本号 | |||
jT808Header.ProtocolVersion = reader.ReadByte(); | |||
// 4.终端手机号 | |||
jT808Header.TerminalPhoneNo = reader.ReadBCD(20, config.Trim); | |||
} | |||
else | |||
{ | |||
// 2013 版本 | |||
// 3.终端手机号 | |||
jT808Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim); | |||
} | |||
jT808Header.MsgNum = reader.ReadUInt16(); | |||
// 4.判断有无分包 | |||
if (jT808Header.MessageBodyProperty.IsPackage) | |||
@@ -62,8 +82,20 @@ namespace JT808.Protocol | |||
writer.WriteUInt16(value.MsgId); | |||
// 2.消息体属性 | |||
writer.WriteUInt16(value.MessageBodyProperty.Wrap()); | |||
// 3.终端手机号 | |||
writer.WriteBCD(value.TerminalPhoneNo, config.TerminalPhoneNoLength); | |||
if (value.MessageBodyProperty.VersionFlag) | |||
{ | |||
// 2019 版本 | |||
// 3.协议版本号 | |||
writer.WriteByte(value.ProtocolVersion); | |||
// 4.终端手机号 | |||
writer.WriteBCD(value.TerminalPhoneNo, 20); | |||
} | |||
else | |||
{ | |||
// 2013 版本 | |||
// 3.终端手机号 | |||
writer.WriteBCD(value.TerminalPhoneNo, config.TerminalPhoneNoLength); | |||
} | |||
// 4.消息流水号 | |||
writer.WriteUInt16(value.MsgNum); | |||
// 5.判断是否分包 | |||
@@ -7,15 +7,34 @@ namespace JT808.Protocol | |||
{ | |||
public struct JT808HeaderMessageBodyProperty | |||
{ | |||
public JT808HeaderMessageBodyProperty(int dataLength,bool isPackage, JT808EncryptMethod jT808EncryptMethod= JT808EncryptMethod.None) | |||
public JT808HeaderMessageBodyProperty(int dataLength,bool isPackage, bool versionFlag= false, JT808EncryptMethod jT808EncryptMethod= JT808EncryptMethod.None) | |||
{ | |||
IsPackage = isPackage; | |||
Encrypt = jT808EncryptMethod; | |||
DataLength = dataLength; | |||
VersionFlag = versionFlag; | |||
} | |||
public JT808HeaderMessageBodyProperty(bool isPackage, bool versionFlag, JT808EncryptMethod jT808EncryptMethod = JT808EncryptMethod.None) | |||
{ | |||
IsPackage = isPackage; | |||
Encrypt = jT808EncryptMethod; | |||
DataLength = 0; | |||
VersionFlag = versionFlag; | |||
} | |||
public JT808HeaderMessageBodyProperty(bool versionFlag, JT808EncryptMethod jT808EncryptMethod = JT808EncryptMethod.None) | |||
{ | |||
IsPackage = false; | |||
Encrypt = jT808EncryptMethod; | |||
DataLength = 0; | |||
VersionFlag = versionFlag; | |||
} | |||
public JT808HeaderMessageBodyProperty(ushort value) | |||
{ | |||
IsPackage = (value >> 13) == 1; | |||
VersionFlag = (value >> 14 & 0x01) == 1; | |||
IsPackage = ((value >> 13) & 0x001) == 1; | |||
switch ((value & 0x400) >> 10) | |||
{ | |||
case 0: | |||
@@ -31,6 +50,10 @@ namespace JT808.Protocol | |||
DataLength = value & 0x3FF; | |||
} | |||
/// <summary> | |||
/// 版本标识(默认为1=true) | |||
/// </summary> | |||
public bool VersionFlag { get; set; } | |||
/// <summary> | |||
/// 是否分包 | |||
/// true-1 表示消息体为长消息,进行分包发送处理 | |||
/// false-0 消息头中无消息包封装项字段。 | |||
@@ -49,6 +72,7 @@ namespace JT808.Protocol | |||
public int DataLength { get; set; } | |||
public ushort Wrap() | |||
{ | |||
// 1.是否分包 | |||
int tmpIsPacke = 0; | |||
if (IsPackage) | |||
@@ -75,8 +99,53 @@ namespace JT808.Protocol | |||
{ | |||
// 判断有无数据体长度 | |||
DataLength = 0; | |||
} | |||
return (ushort)(tmpIsPacke | tmpEncrypt | DataLength); | |||
} | |||
// 3.是否分包 | |||
int versionFlag = 0; | |||
if (VersionFlag) | |||
{ | |||
versionFlag = 1 << 14; | |||
} | |||
return (ushort)(versionFlag|tmpIsPacke | tmpEncrypt | DataLength); | |||
} | |||
public ushort Wrap(int dataLength) | |||
{ | |||
// 1.是否分包 | |||
int tmpIsPacke = 0; | |||
if (IsPackage) | |||
{ | |||
tmpIsPacke = 1 << 13; | |||
} | |||
// 2.是否加密 | |||
int tmpEncrypt; | |||
// 2.3.数据加密方式 | |||
switch (Encrypt) | |||
{ | |||
case JT808EncryptMethod.None: | |||
tmpEncrypt = 0; | |||
break; | |||
case JT808EncryptMethod.RSA: | |||
tmpEncrypt = 1 << 10; | |||
break; | |||
default: | |||
tmpEncrypt = 0; | |||
break; | |||
} | |||
// 2.4.数据长度 | |||
DataLength = dataLength; | |||
if (dataLength <= 0) | |||
{ | |||
// 判断有无数据体长度 | |||
dataLength = 0; | |||
} | |||
// 3.是否分包 | |||
int versionFlag = 0; | |||
if (VersionFlag) | |||
{ | |||
versionFlag = 1 << 14; | |||
} | |||
return (ushort)(versionFlag | tmpIsPacke | tmpEncrypt | dataLength); | |||
} | |||
} | |||
} |
@@ -34,6 +34,34 @@ namespace JT808.Protocol | |||
/// </summary> | |||
public byte End { get; set; } | |||
public JT808Version Version | |||
{ | |||
get { | |||
if (Header != null) | |||
{ | |||
try | |||
{ | |||
if (Header.MessageBodyProperty.VersionFlag) | |||
{ | |||
return JT808Version.JTT2019; | |||
} | |||
else | |||
{ | |||
return JT808Version.JTT2013; | |||
} | |||
} | |||
catch | |||
{ | |||
return JT808Version.JTT2013; | |||
} | |||
} | |||
else | |||
{ | |||
return JT808Version.JTT2013; | |||
} | |||
} | |||
} | |||
public JT808HeaderPackage Deserialize(ref JT808MessagePackReader reader, IJT808Config config) | |||
{ | |||
// 1. 验证校验和 | |||
@@ -56,8 +84,21 @@ namespace JT808.Protocol | |||
ushort messageBodyPropertyValue = reader.ReadUInt16(); | |||
// 3.2.1.解包消息体属性 | |||
jT808Package.Header.MessageBodyProperty = new JT808HeaderMessageBodyProperty(messageBodyPropertyValue); | |||
// 3.3.读取终端手机号 | |||
jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim); | |||
if (jT808Package.Header.MessageBodyProperty.VersionFlag) | |||
{ | |||
//2019版本 | |||
// 3.3.读取协议版本号 | |||
jT808Package.Header.ProtocolVersion = reader.ReadByte(); | |||
// 3.4.读取终端手机号 | |||
jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(20, config.Trim); | |||
reader.Version = JT808Version.JTT2019; | |||
} | |||
else | |||
{ | |||
//2013版本 | |||
// 3.3.读取终端手机号 | |||
jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim); | |||
} | |||
// 3.4.读取消息流水号 | |||
jT808Package.Header.MsgNum = reader.ReadUInt16(); | |||
// 3.5.判断有无分包 | |||
@@ -25,27 +25,54 @@ namespace JT808.Protocol | |||
/// 起始符 | |||
/// </summary> | |||
public byte Begin { get; set; } = BeginFlag; | |||
/// <summary> | |||
/// 终止符 | |||
/// 头数据 | |||
/// </summary> | |||
public byte End { get; set; } = EndFlag; | |||
public JT808Header Header { get; set; } | |||
/// <summary> | |||
/// 数据体 | |||
/// </summary> | |||
public JT808Bodies Bodies { get; set; } | |||
/// <summary> | |||
/// 校验码 | |||
/// 从消息头开始,同后一字节异或,直到校验码前一个字节,占用一个字节。 | |||
/// </summary> | |||
public byte CheckCode { get; set; } | |||
/// <summary> | |||
/// 头数据 | |||
/// 终止符 | |||
/// </summary> | |||
public JT808Header Header { get; set; } | |||
public byte End { get; set; } = EndFlag; | |||
/// <summary> | |||
/// 数据体 | |||
/// 808版本号 | |||
/// </summary> | |||
public JT808Bodies Bodies { get; set; } | |||
public JT808Version Version | |||
{ | |||
get | |||
{ | |||
if (Header != null) | |||
{ | |||
try | |||
{ | |||
if (Header.MessageBodyProperty.VersionFlag) | |||
{ | |||
return JT808Version.JTT2019; | |||
} | |||
else | |||
{ | |||
return JT808Version.JTT2013; | |||
} | |||
} | |||
catch | |||
{ | |||
return JT808Version.JTT2013; | |||
} | |||
} | |||
else | |||
{ | |||
return JT808Version.JTT2013; | |||
} | |||
} | |||
} | |||
public JT808Package Deserialize(ref JT808MessagePackReader reader, IJT808Config config) | |||
{ | |||
@@ -67,11 +94,23 @@ namespace JT808.Protocol | |||
jT808Package.Header.MsgId = reader.ReadUInt16(); | |||
// 3.2.读取消息体属性 | |||
jT808Package.Header.MessageBodyProperty = new JT808HeaderMessageBodyProperty(reader.ReadUInt16()); | |||
// 3.3.读取终端手机号 | |||
jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim); | |||
// 3.4.读取消息流水号 | |||
if (jT808Package.Header.MessageBodyProperty.VersionFlag) | |||
{ | |||
//2019版本 | |||
jT808Package.Header.ProtocolVersion = reader.ReadByte(); | |||
// 3.4.读取终端手机号 | |||
jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(20, config.Trim); | |||
reader.Version = JT808Version.JTT2019; | |||
} | |||
else | |||
{ | |||
//2013版本 | |||
// 3.3.读取终端手机号 | |||
jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim); | |||
} | |||
// 3.4.读取消息流水号 | |||
jT808Package.Header.MsgNum = reader.ReadUInt16(); | |||
// 3.5.判断有无分包 | |||
// 3.5.判断有无分包 | |||
if (jT808Package.Header.MessageBodyProperty.IsPackage) | |||
{ | |||
//3.5.1.读取消息包总数 | |||
@@ -131,9 +170,7 @@ namespace JT808.Protocol | |||
} | |||
} | |||
} | |||
// 5.读取校验码 | |||
jT808Package.CheckCode = reader.ReadByte(); | |||
// 6.读取终止位置 | |||
@@ -152,8 +189,21 @@ namespace JT808.Protocol | |||
writer.WriteUInt16(value.Header.MsgId); | |||
// 2.2.消息体属性(包含消息体长度所以先跳过) | |||
writer.Skip(2, out int msgBodiesPropertyPosition); | |||
// 2.3.终端手机号 (写死大陆手机号码) | |||
writer.WriteBCD(value.Header.TerminalPhoneNo, config.TerminalPhoneNoLength); | |||
if (value.Header.MessageBodyProperty.VersionFlag) | |||
{ | |||
//2019版本 | |||
// 2.3.协议版本号 | |||
writer.WriteByte(value.Header.ProtocolVersion); | |||
// 2.4.终端手机号 | |||
writer.WriteBCD(value.Header.TerminalPhoneNo, 20); | |||
writer.Version = JT808Version.JTT2019; | |||
} | |||
else | |||
{ | |||
//2013版本 | |||
// 2.3.终端手机号 (写死大陆手机号码) | |||
writer.WriteBCD(value.Header.TerminalPhoneNo, config.TerminalPhoneNoLength); | |||
} | |||
value.Header.MsgNum = value.Header.MsgNum > 0 ? value.Header.MsgNum : config.MsgSNDistributed.Increment(); | |||
// 2.4.消息流水号 | |||
writer.WriteUInt16(value.Header.MsgNum); | |||
@@ -177,9 +227,8 @@ namespace JT808.Protocol | |||
} | |||
} | |||
// 3.1.处理数据体长度 | |||
value.Header.MessageBodyProperty = new JT808HeaderMessageBodyProperty((ushort)(writer.GetCurrentPosition() - headerLength)); | |||
// 2.2.回写消息体属性 | |||
writer.WriteUInt16Return(value.Header.MessageBodyProperty.Wrap(), msgBodiesPropertyPosition); | |||
writer.WriteUInt16Return(value.Header.MessageBodyProperty.Wrap((writer.GetCurrentPosition() - headerLength)), msgBodiesPropertyPosition); | |||
// 4.校验码 | |||
writer.WriteXor(); | |||
// 5.终止符 | |||
@@ -1,4 +1,5 @@ | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.Enums; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.Interfaces; | |||
using JT808.Protocol.Internal; | |||
@@ -27,13 +28,13 @@ namespace JT808.Protocol | |||
private readonly IJT808Config jT808Config; | |||
public byte[] Serialize(JT808Package jT808Package, int minBufferSize = 4096) | |||
public byte[] Serialize(JT808Package package, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer); | |||
jT808Package.Serialize(ref jT808MessagePackWriter, jT808Package, jT808Config); | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer, version); | |||
jT808Package.Serialize(ref jT808MessagePackWriter, package, jT808Config); | |||
return jT808MessagePackWriter.FlushAndGetEncodingArray(); | |||
} | |||
finally | |||
@@ -42,13 +43,13 @@ namespace JT808.Protocol | |||
} | |||
} | |||
public ReadOnlySpan<byte> SerializeReadOnlySpan(JT808Package jT808Package, int minBufferSize = 4096) | |||
public ReadOnlySpan<byte> SerializeReadOnlySpan(JT808Package package, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer); | |||
jT808Package.Serialize(ref jT808MessagePackWriter, jT808Package, jT808Config); | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer, version); | |||
jT808Package.Serialize(ref jT808MessagePackWriter, package, jT808Config); | |||
return jT808MessagePackWriter.FlushAndGetEncodingReadOnlySpan(); | |||
} | |||
finally | |||
@@ -57,12 +58,12 @@ namespace JT808.Protocol | |||
} | |||
} | |||
public JT808Package Deserialize(ReadOnlySpan<byte> bytes, int minBufferSize = 4096) | |||
public JT808Package Deserialize(ReadOnlySpan<byte> bytes, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes); | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes, version); | |||
jT808MessagePackReader.Decode(buffer); | |||
return jT808Package.Deserialize(ref jT808MessagePackReader, jT808Config); | |||
} | |||
@@ -72,13 +73,13 @@ namespace JT808.Protocol | |||
} | |||
} | |||
public byte [] Serialize<T>(T obj, int minBufferSize = 4096) | |||
public byte [] Serialize<T>(T obj, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
var formatter = jT808Config.GetMessagePackFormatter<T>(); | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer); | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer, version); | |||
formatter.Serialize(ref jT808MessagePackWriter, obj, jT808Config); | |||
return jT808MessagePackWriter.FlushAndGetEncodingArray(); | |||
} | |||
@@ -88,13 +89,13 @@ namespace JT808.Protocol | |||
} | |||
} | |||
public ReadOnlySpan<byte> SerializeReadOnlySpan<T>(T obj, int minBufferSize = 4096) | |||
public ReadOnlySpan<byte> SerializeReadOnlySpan<T>(T obj, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
var formatter = jT808Config.GetMessagePackFormatter<T>(); | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer); | |||
JT808MessagePackWriter jT808MessagePackWriter = new JT808MessagePackWriter(buffer, version); | |||
formatter.Serialize(ref jT808MessagePackWriter, obj, jT808Config); | |||
return jT808MessagePackWriter.FlushAndGetEncodingReadOnlySpan(); | |||
} | |||
@@ -104,12 +105,12 @@ namespace JT808.Protocol | |||
} | |||
} | |||
public T Deserialize<T>(ReadOnlySpan<byte> bytes, int minBufferSize = 4096) | |||
public T Deserialize<T>(ReadOnlySpan<byte> bytes, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes); | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes, version); | |||
if(CheckPackageType(typeof(T))) | |||
jT808MessagePackReader.Decode(buffer); | |||
var formatter = jT808Config.GetMessagePackFormatter<T>(); | |||
@@ -132,12 +133,12 @@ namespace JT808.Protocol | |||
/// </summary> | |||
/// <param name="bytes"></param> | |||
/// <returns></returns> | |||
public JT808HeaderPackage HeaderDeserialize(ReadOnlySpan<byte> bytes, int minBufferSize = 4096) | |||
public JT808HeaderPackage HeaderDeserialize(ReadOnlySpan<byte> bytes, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes); | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes, version); | |||
jT808MessagePackReader.Decode(buffer); | |||
return jT808HeaderPackage.Deserialize(ref jT808MessagePackReader,jT808Config); | |||
} | |||
@@ -146,13 +147,13 @@ namespace JT808.Protocol | |||
JT808ArrayPool.Return(buffer); | |||
} | |||
} | |||
public dynamic Deserialize(ReadOnlySpan<byte> bytes, Type type, int minBufferSize = 4096) | |||
public dynamic Deserialize(ReadOnlySpan<byte> bytes, Type type, JT808Version version = JT808Version.JTT2013, int minBufferSize = 4096) | |||
{ | |||
byte[] buffer = JT808ArrayPool.Rent(minBufferSize); | |||
try | |||
{ | |||
var formatter = jT808Config.GetMessagePackFormatterByType(type); | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes); | |||
JT808MessagePackReader jT808MessagePackReader = new JT808MessagePackReader(bytes, version); | |||
if (CheckPackageType(type)) | |||
jT808MessagePackReader.Decode(buffer); | |||
return JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(formatter,ref jT808MessagePackReader, jT808Config); | |||
@@ -0,0 +1,16 @@ | |||
namespace JT808.Protocol.MessageBody | |||
{ | |||
/// <summary> | |||
/// 查询服务器时间请求 | |||
/// 2019版本 | |||
/// </summary> | |||
public class JT808_0x0004 : JT808Bodies | |||
{ | |||
/// <summary> | |||
/// 跳过数据体序列化 | |||
/// </summary> | |||
public override bool SkipSerialization { get; set; } = true; | |||
public override ushort MsgId { get; } = 0x0004; | |||
} | |||
} |
@@ -0,0 +1,44 @@ | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.MessagePack; | |||
namespace JT808.Protocol.MessageBody | |||
{ | |||
/// <summary> | |||
/// 终端补传分包请求 | |||
/// 2019版本 | |||
/// </summary> | |||
public class JT808_0x0005 : JT808Bodies, IJT808MessagePackFormatter<JT808_0x0005> | |||
{ | |||
public override ushort MsgId { get; } = 0x0005; | |||
/// <summary> | |||
/// 原始消息流水号 | |||
/// 对应要求补传的原始消息第一包的消息流水号 | |||
/// </summary> | |||
public ushort OriginalMsgNum { get; set; } | |||
/// <summary> | |||
/// 重传包总数 | |||
/// n | |||
/// </summary> | |||
public byte AgainPackageCount { get; set; } | |||
/// <summary> | |||
/// 重传包 ID 列表 | |||
/// BYTE[2*n] | |||
/// 重传包序号顺序排列,如“包 ID1 包 ID2......包 IDn”。 | |||
/// </summary> | |||
public byte[] AgainPackageData { get; set; } | |||
public JT808_0x0005 Deserialize(ref JT808MessagePackReader reader, IJT808Config config) | |||
{ | |||
JT808_0x0005 value = new JT808_0x0005(); | |||
value.OriginalMsgNum = reader.ReadUInt16(); | |||
value.AgainPackageCount = reader.ReadByte(); | |||
value.AgainPackageData = reader.ReadArray(value.AgainPackageCount * 2).ToArray(); | |||
return value; | |||
} | |||
public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0005 value, IJT808Config config) | |||
{ | |||
writer.WriteUInt16(value.OriginalMsgNum); | |||
writer.WriteByte((byte)(value.AgainPackageData.Length / 2)); | |||
writer.WriteArray(value.AgainPackageData); | |||
} | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.Enums; | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.MessagePack; | |||
namespace JT808.Protocol.MessageBody | |||
@@ -27,21 +28,22 @@ namespace JT808.Protocol.MessageBody | |||
/// <summary> | |||
/// 制造商 ID | |||
/// 5 个字节,终端制造商编码 | |||
/// 2013版本 5 个字节,终端制造商编码 | |||
/// 2019版本 11 个字节,终端制造商编码 | |||
/// </summary> | |||
public string MakerId { get; set; } | |||
/// <summary> | |||
/// 终端型号 | |||
/// 20 个字节,此终端型号由制造商自行定义,位数不 | |||
/// 足时,后补“0X00”。 | |||
/// 2013版本 20 个字节,此终端型号由制造商自行定义,位数不足时,后补“0X00”。 | |||
/// 2019版本 30 个字节,此终端型号由制造商自行定义,位数不足时,后补“0X00”。 | |||
/// </summary> | |||
public string TerminalModel { get; set; } | |||
/// <summary> | |||
/// 终端 ID | |||
/// 7 个字节,由大写字母和数字组成,此终端 ID 由制 | |||
/// 造商自行定义,位数不足时,后补“0X00”。 | |||
/// 2013版本 7个字节,由大写字母和数字组成,此终端 ID 由制造商自行定义,位数不足时,后补“0X00”。 | |||
/// 2019版本 30个字节,由大写字母和数字组成,此终端 ID 由制造商自行定义,位数不足时,后补“0X00”。 | |||
/// </summary> | |||
public string TerminalId { get; set; } | |||
@@ -64,9 +66,18 @@ namespace JT808.Protocol.MessageBody | |||
JT808_0x0100 jT808_0X0100 = new JT808_0x0100(); | |||
jT808_0X0100.AreaID = reader.ReadUInt16(); | |||
jT808_0X0100.CityOrCountyId = reader.ReadUInt16(); | |||
jT808_0X0100.MakerId = reader.ReadString(5); | |||
jT808_0X0100.TerminalModel = reader.ReadString(20); | |||
jT808_0X0100.TerminalId = reader.ReadString(7); | |||
if(reader.Version== JT808Version.JTT2019) | |||
{ | |||
jT808_0X0100.MakerId = reader.ReadString(11); | |||
jT808_0X0100.TerminalModel = reader.ReadString(30); | |||
jT808_0X0100.TerminalId = reader.ReadString(30); | |||
} | |||
else | |||
{ | |||
jT808_0X0100.MakerId = reader.ReadString(5); | |||
jT808_0X0100.TerminalModel = reader.ReadString(20); | |||
jT808_0X0100.TerminalId = reader.ReadString(7); | |||
} | |||
jT808_0X0100.PlateColor = reader.ReadByte(); | |||
jT808_0X0100.PlateNo = reader.ReadRemainStringContent(); | |||
return jT808_0X0100; | |||
@@ -76,9 +87,18 @@ namespace JT808.Protocol.MessageBody | |||
{ | |||
writer.WriteUInt16(value.AreaID); | |||
writer.WriteUInt16(value.CityOrCountyId); | |||
writer.WriteString(value.MakerId.PadRight(5, '0')); | |||
writer.WriteString(value.TerminalModel.PadRight(20, '0')); | |||
writer.WriteString(value.TerminalId.PadRight(7, '0')); | |||
if (writer.Version == JT808Version.JTT2019) | |||
{ | |||
writer.WriteString(value.MakerId.PadLeft(11, '0')); | |||
writer.WriteString(value.TerminalModel.PadLeft(30, '0')); | |||
writer.WriteString(value.TerminalId.PadLeft(30, '0')); | |||
} | |||
else | |||
{ | |||
writer.WriteString(value.MakerId.PadRight(5, '0')); | |||
writer.WriteString(value.TerminalModel.PadRight(20, '0')); | |||
writer.WriteString(value.TerminalId.PadRight(7, '0')); | |||
} | |||
writer.WriteByte(value.PlateColor); | |||
writer.WriteString(value.PlateNo); | |||
} | |||
@@ -1,4 +1,5 @@ | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.Enums; | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.MessagePack; | |||
namespace JT808.Protocol.MessageBody | |||
@@ -11,19 +12,54 @@ namespace JT808.Protocol.MessageBody | |||
public override ushort MsgId { get; } = 0x0102; | |||
/// <summary> | |||
/// 鉴权码 | |||
/// 鉴权码内容 2019版本 | |||
/// </summary> | |||
public string Code { get; set; } | |||
/// <summary> | |||
/// 鉴权码长度 2019版本 | |||
/// </summary> | |||
public byte CodeLength { get; set; } | |||
/// <summary> | |||
/// 终端IMEI 长度15 2019版本 | |||
/// </summary> | |||
public string IMEI { get; set; } | |||
/// <summary> | |||
/// 软件版本号 长度20 后补 "0x00" 2019版本 | |||
/// </summary> | |||
public string SoftwareVersion { get; set; } | |||
public JT808_0x0102 Deserialize(ref JT808MessagePackReader reader, IJT808Config config) | |||
{ | |||
JT808_0x0102 jT808_0X0102 = new JT808_0x0102(); | |||
jT808_0X0102.Code = reader.ReadRemainStringContent(); | |||
if(reader.Version== JT808Version.JTT2019) | |||
{ | |||
jT808_0X0102.CodeLength = reader.ReadByte(); | |||
jT808_0X0102.Code = reader.ReadString(jT808_0X0102.CodeLength); | |||
jT808_0X0102.IMEI = reader.ReadString(15); | |||
jT808_0X0102.SoftwareVersion = reader.ReadString(20); | |||
} | |||
else | |||
{ | |||
jT808_0X0102.Code = reader.ReadRemainStringContent(); | |||
} | |||
return jT808_0X0102; | |||
} | |||
public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0102 value, IJT808Config config) | |||
{ | |||
writer.WriteString(value.Code); | |||
if (writer.Version == JT808Version.JTT2019) | |||
{ | |||
writer.Skip(1, out int CodeLengthPosition); | |||
writer.WriteString(value.Code); | |||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - CodeLengthPosition - 1), CodeLengthPosition); | |||
writer.WriteString(value.IMEI); | |||
writer.WriteString(value.SoftwareVersion.PadRight(20,'0')); | |||
} | |||
else | |||
{ | |||
writer.WriteString(value.Code); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
using JT808.Protocol.Formatters; | |||
using JT808.Protocol.MessagePack; | |||
using System; | |||
namespace JT808.Protocol.MessageBody | |||
{ | |||
/// <summary> | |||
/// 查询服务器时间应答 | |||
/// 2019版本 | |||
/// </summary> | |||
public class JT808_0x8004 : JT808Bodies, IJT808MessagePackFormatter<JT808_0x8004> | |||
{ | |||
public override ushort MsgId { get; } = 0x8004; | |||
public DateTime Time { get; set; } = DateTime.Now; | |||
public JT808_0x8004 Deserialize(ref JT808MessagePackReader reader, IJT808Config config) | |||
{ | |||
JT808_0x8004 value = new JT808_0x8004(); | |||
value.Time = reader.ReadDateTime6(); | |||
return value; | |||
} | |||
public void Serialize(ref JT808MessagePackWriter writer, JT808_0x8004 value, IJT808Config config) | |||
{ | |||
writer.WriteDateTime6(value.Time); | |||
} | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
using JT808.Protocol.Buffers; | |||
using JT808.Protocol.Enums; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.Interfaces; | |||
using System; | |||
using System.Buffers; | |||
using System.Buffers.Binary; | |||
@@ -15,6 +17,7 @@ namespace JT808.Protocol.MessagePack | |||
public ReadOnlySpan<byte> Reader { get; private set; } | |||
public ReadOnlySpan<byte> SrcBuffer { get; } | |||
public int ReaderCount { get; private set; } | |||
public JT808Version Version { get; set; } | |||
private byte _calculateCheckXorCode; | |||
private byte _realCheckXorCode; | |||
private bool _checkXorCodeVali; | |||
@@ -31,7 +34,7 @@ namespace JT808.Protocol.MessagePack | |||
/// 解码(转义还原),计算校验和 | |||
/// </summary> | |||
/// <param name="buffer"></param> | |||
public JT808MessagePackReader(ReadOnlySpan<byte> srcBuffer) | |||
public JT808MessagePackReader(ReadOnlySpan<byte> srcBuffer, JT808Version version = JT808Version.JTT2013) | |||
{ | |||
SrcBuffer = srcBuffer; | |||
ReaderCount = 0; | |||
@@ -39,6 +42,7 @@ namespace JT808.Protocol.MessagePack | |||
_calculateCheckXorCode = 0x00; | |||
_checkXorCodeVali = false; | |||
_decoded = false; | |||
Version = version; | |||
Reader = srcBuffer; | |||
} | |||
/// <summary> | |||
@@ -1,4 +1,5 @@ | |||
using JT808.Protocol.Buffers; | |||
using JT808.Protocol.Enums; | |||
using System; | |||
using System.Buffers; | |||
using System.Buffers.Binary; | |||
@@ -9,9 +10,11 @@ namespace JT808.Protocol.MessagePack | |||
public ref struct JT808MessagePackWriter | |||
{ | |||
private JT808BufferWriter writer; | |||
public JT808MessagePackWriter(Span<byte> buffer) | |||
public JT808Version Version { get; set; } | |||
public JT808MessagePackWriter(Span<byte> buffer, JT808Version version= JT808Version.JTT2013) | |||
{ | |||
this.writer = new JT808BufferWriter(buffer); | |||
Version = version; | |||
} | |||
public byte[] FlushAndGetEncodingArray() | |||
{ | |||