ソースを参照

重整JT809协议

tags/v1.3.0
SmallChi 6年前
コミット
681e25e6ea
30個のファイルの変更1997行の追加589行の削除
  1. +13
    -2
      README.md
  2. +11
    -4
      src/JT809.Protocol.Test/JT809.Protocol.Test.csproj
  3. +41
    -0
      src/JT809.Protocol.Test/JT809HeaderTest.cs
  4. +37
    -0
      src/JT809.Protocol.Test/JT809MessageBody/JT809_0x1001Test.cs
  5. +81
    -0
      src/JT809.Protocol.Test/JT809Packages/JT809_0x1001PackageTest.cs
  6. +0
    -117
      src/JT809.Protocol.Test/PackageTest.cs
  7. +0
    -12
      src/JT809.Protocol/Enums/ErrorCode.cs
  8. +0
    -25
      src/JT809.Protocol/Exceptions/JT809Exception.cs
  9. +29
    -4
      src/JT809.Protocol/JT809.Protocol.csproj
  10. +14
    -0
      src/JT809.Protocol/JT809Attributes/JT809BodiesTypeAttribute.cs
  11. +25
    -0
      src/JT809.Protocol/JT809Attributes/JT809FormatterAttribute.cs
  12. +10
    -0
      src/JT809.Protocol/JT809Bodies.cs
  13. +166
    -163
      src/JT809.Protocol/JT809Enums/JT809BusinessType.cs
  14. +17
    -0
      src/JT809.Protocol/JT809Enums/JT809ErrorCode.cs
  15. +260
    -260
      src/JT809.Protocol/JT809Enums/JT809SubBusinessType.cs
  16. +32
    -0
      src/JT809.Protocol/JT809Exceptions/JT809Exception.cs
  17. +429
    -0
      src/JT809.Protocol/JT809Extensions/JT809BinaryExtensions.cs
  18. +155
    -0
      src/JT809.Protocol/JT809Extensions/JT809EnumExtensions.cs
  19. +50
    -0
      src/JT809.Protocol/JT809Extensions/JT809FormatterExtensions.cs
  20. +87
    -0
      src/JT809.Protocol/JT809Extensions/JT809FormatterResolverExtensions.cs
  21. +12
    -0
      src/JT809.Protocol/JT809Formatters/IJT809FormatterOfT.cs
  22. +39
    -0
      src/JT809.Protocol/JT809Formatters/JT809HeaderFormatter.cs
  23. +33
    -0
      src/JT809.Protocol/JT809Formatters/JT809MessageBodyFormatters/JT809_0x1001Formatter.cs
  24. +209
    -0
      src/JT809.Protocol/JT809Formatters/JT809PackageFormatter.cs
  25. +52
    -0
      src/JT809.Protocol/JT809Header.cs
  26. +2
    -2
      src/JT809.Protocol/JT809Header_Encrypt.cs
  27. +62
    -0
      src/JT809.Protocol/JT809Header_Version.cs
  28. +34
    -0
      src/JT809.Protocol/JT809MessageBody/JT809_0x1001.cs
  29. +33
    -0
      src/JT809.Protocol/JT809Package.cs
  30. +64
    -0
      src/JT809.Protocol/JT809Serializer.cs

+ 13
- 2
README.md ファイルの表示

@@ -1,2 +1,13 @@
# JT809
JT809
# JT809协议开发

### 瞎逼逼:

  现在有了[JT808](https://github.com/SmallChi/GPSPlatform/blob/master/JT808.md)的基础,对JT809就只剩搬砖了。

> 该JT809协议是参考[MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)一款二进制序列化器,站在巨人的肩膀上搬砖就是爽歪歪。

## JT809终端通讯协议消息对照表

|序号|消息体名称|消息ID|完成情况|
|:------:|:------:|:------:|:------:|
| 1 | 主链路登录请求消息 | 0x1001 | √ |

+ 11
- 4
src/JT809.Protocol.Test/JT809.Protocol.Test.csproj ファイルの表示

@@ -1,15 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<Compile Remove="PackageTest.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>


+ 41
- 0
src/JT809.Protocol.Test/JT809HeaderTest.cs ファイルの表示

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using JT809.Protocol;
using JT809.Protocol.JT809Extensions;

namespace JT809.Protocol.Test
{
public class JT809HeaderTest
{
[Fact]
public void Test1()
{
JT809Header jT809Header = new JT809Header();
jT809Header.MsgLength = 24;
jT809Header.MsgSN = 1024;
jT809Header.MsgID = JT809Enums.JT809BusinessType.DOWN_BASE_MSG;
jT809Header.MsgGNSSCENTERID = 1200;
jT809Header.Version = new JT809Header_Version();
jT809Header.EncryptFlag = JT809Header_Encrypt.None;
jT809Header.EncryptKey = 0;
var hex = JT809Serializer.Serialize(jT809Header).ToHexString();
//"00 00 00 18 00 00 04 00 96 00 00 00 04 B0 01 00 00 00 00 00 00 00"
}

[Fact]
public void Test2()
{
var bytes = "00 00 00 18 00 00 04 00 96 00 00 00 04 B0 01 00 00 00 00 00 00 00".ToHexBytes();
JT809Header jT809Header= JT809Serializer.Deserialize<JT809Header>(bytes);
Assert.Equal((uint)24, jT809Header.MsgLength);
Assert.Equal((uint)1024, jT809Header.MsgSN);
Assert.Equal(JT809Enums.JT809BusinessType.DOWN_BASE_MSG, jT809Header.MsgID);
Assert.Equal((uint)1200, jT809Header.MsgGNSSCENTERID);
Assert.Equal(new JT809Header_Version().ToString(), jT809Header.Version.ToString());
Assert.Equal(JT809Header_Encrypt.None, jT809Header.EncryptFlag);
Assert.Equal((uint)0, jT809Header.EncryptKey);
}
}
}

+ 37
- 0
src/JT809.Protocol.Test/JT809MessageBody/JT809_0x1001Test.cs ファイルの表示

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using JT809.Protocol;
using JT809.Protocol.JT809Extensions;
using JT809.Protocol.JT809MessageBody;
using JT809.Protocol.JT809Exceptions;

namespace JT809.Protocol.Test.JT809MessageBody
{
public class JT809_0x1001Test
{
[Fact]
public void Test1()
{
JT809_0x1001 jT809_0X1001 = new JT809_0x1001();
jT809_0X1001.UserId = 20180920;
jT809_0X1001.Password = "20180920";
jT809_0X1001.DownLinkIP = "127.0.0.1";
jT809_0X1001.DownLinkPort = 809;
var hex = JT809Serializer.Serialize(jT809_0X1001).ToHexString();
//"01 33 EF B8 32 30 31 38 30 39 32 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31 32 37 2E 30 2E 30 2E 31 03 29"
}

[Fact]
public void Test2()
{
var bytes = "01 33 EF B8 32 30 31 38 30 39 32 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31 32 37 2E 30 2E 30 2E 31 03 29".ToHexBytes();
JT809_0x1001 jT809_0X1001 = JT809Serializer.Deserialize<JT809_0x1001>(bytes);
Assert.Equal((uint)20180920, jT809_0X1001.UserId);
Assert.Equal("20180920", jT809_0X1001.Password);
Assert.Equal("127.0.0.1", jT809_0X1001.DownLinkIP);
Assert.Equal((ushort)809,jT809_0X1001.DownLinkPort);
}
}
}

+ 81
- 0
src/JT809.Protocol.Test/JT809Packages/JT809_0x1001PackageTest.cs ファイルの表示

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using JT809.Protocol;
using JT809.Protocol.JT809Extensions;
using JT809.Protocol.JT809MessageBody;

namespace JT809.Protocol.Test.JT809Packages
{
public class JT809_0x1001PackageTest
{
[Fact]
public void Test1()
{
JT809Package jT809Package = new JT809Package();
jT809Package.Header = new JT809Header
{
MsgSN= 133,
EncryptKey=9999,
MsgID= JT809Enums.JT809BusinessType.UP_CONNECT_REQ,
MsgGNSSCENTERID= 20180920,
};
JT809_0x1001 jT809_0X1001 = new JT809_0x1001();
jT809_0X1001.UserId = 20180920;
jT809_0X1001.Password = "20180920";
jT809_0X1001.DownLinkIP = "127.0.0.1";
jT809_0X1001.DownLinkPort = 809;
jT809Package.Bodies = jT809_0X1001;
var hex = JT809Serializer.Serialize(jT809Package).ToHexString();
//"5B
//00 00 00 48
//00 00 00 85
//10 01
//01 33 EF B8
//01 00 00
//00
//00 00 27 0F
//01 33 EF B8
//32 30 31 38 30 39 32 30
//31 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
//03 29
//6A 91
//5D"
}

[Fact]
public void Test2()
{
var bytes = "5B 00 00 00 48 00 00 00 85 10 01 01 33 EF B8 01 00 00 00 00 00 27 0F 01 33 EF B8 32 30 31 38 30 39 32 30 31 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 29 6A 91 5D".ToHexBytes();
JT809Package jT809Package = JT809Serializer.Deserialize(bytes);
Assert.Equal((uint)72, jT809Package.Header.MsgLength);
Assert.Equal((uint)133, jT809Package.Header.MsgSN);
Assert.Equal((uint)9999, jT809Package.Header.EncryptKey);
Assert.Equal((uint)20180920, jT809Package.Header.MsgGNSSCENTERID);
Assert.Equal(JT809Enums.JT809BusinessType.UP_CONNECT_REQ, jT809Package.Header.MsgID);
Assert.Equal(new JT809Header_Version().ToString(), jT809Package.Header.Version.ToString());
JT809_0x1001 jT809_0X1001 = (JT809_0x1001)jT809Package.Bodies;
Assert.Equal((uint)20180920, jT809_0X1001.UserId);
Assert.Equal("20180920", jT809_0X1001.Password);
Assert.Equal("127.0.0.1", jT809_0X1001.DownLinkIP);
Assert.Equal((ushort)809, jT809_0X1001.DownLinkPort);
}

[Fact]
public void Test3()
{
//字符'0':char c = '0'; 它的ASCII码实际上是48。
//字符'\0' : ASCII码为0,表示一个字符串结束的标志。
//"5B 00 00 00 48 00 00 00 85 10 01 01 33 EF B8 01 00 00 00 00 00 27 0F 30 01 33 EF B8 32 30 31 38 30 39 32 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 31 32 37 2E 30 2E 30 2E 31 03 29 7D 38 5D"
var data="32 30 31 38 30 39 32 30".ToHexBytes();
var str = Encoding.GetEncoding("GBK").GetString(data);
var data1 = "31 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00".ToHexBytes();
var str1 = Encoding.GetEncoding("GBK").GetString(data1);
var test1 = Encoding.GetEncoding("GBK").GetBytes("\0\0\0\0\0\0127.0.0.1");
var test2 = Encoding.GetEncoding("GBK").GetBytes("127.0.0.1\0\0\0\0\0\0");
var test3 = Encoding.GetEncoding("GBK").GetBytes("000000127.0.0.1");
var test4 = Encoding.GetEncoding("GBK").GetBytes("127.0.0.1000000");
}
}
}

+ 0
- 117
src/JT809.Protocol.Test/PackageTest.cs ファイルの表示

@@ -1,117 +0,0 @@
using System;
using System.Text;
using JT809.Protocol.Configs;
using JT809.Protocol.ProtocolPacket;
using JT809.Protocol.ProtocolPacket.Bodies.Master;
using Xunit;

namespace JT809.Protocol.Test.ProtocolPacket
{
public class PackageTest
{
readonly static JT809Config JT809Config = new JT809Config
{
};

[Fact]
public void CreatePackageTest()
{
var body_UP_CONNECT_REQ= new Body_UP_CONNECT_REQ(20140813,
Encoding.UTF8.GetBytes("20140813"),
Encoding.UTF8.GetBytes("20140813"),
809);
Package package = Package.GeneratePackage(Enums.BusinessType.UP_CONNECT_REQ,
body_UP_CONNECT_REQ,
JT809Config);
var data = package.Buffer.ToHexString();
Package package1 = new Package(package.Buffer);
package1.Buffer.ToHexString();
}

[Fact]
public void TestMethod1()
{
//5B
//00 00 00 48
//00 00 00 85
//10 01
//01 33 53 D5
//01 00 00
//00
//00 00 27 0F
//01 33 53 0D 32 30 31 34 30 38 31 33 31 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 29 51 83
//5D

//UP-CONNECT-REQ
byte[] login = new byte[]{
91,
00,00,00,48,
00,00,00,85,
10,01,
01,33,53,213,
01,00,00,
00,00,00,
27,15,01,33,
53,13,32,30,
31,34,30,38,
31,33,31,32,
37,46,30,46,
30,46,31,00,
00,00,00,00,
00,00,00,00,
00,00,00,00,
00,00,00,00,
00,00,
00,00,
00,00,03,29,
51,83,
93 };
Package package = new Package(login);
}

[Fact]
public void CrcTest()
{
byte[] login = new byte[] {51,83};

var CRC16 = BitConverter.ToUInt16(login, 0);
byte[] login1 = new byte[] { 83, 51 };
var CRC161 = BitConverter.ToUInt16(login1, 0);
}

[Fact]
public void MSG_GNSSCENTERIDTest()
{//8449
UInt64 result = 0;
//00, 01, D7, 28
//01 ,33 ,53 ,0xD5
//00 01 D7 27
//00 00 27 0F
//5B
byte[] data = new byte[] { 00 ,0x8A ,0xDA ,0xEB };
int length = 4;
//00 << 8*(4-0-1)=>00 << 24
//01 << 8*(4-1-1)=>01 << 16
//0xD7 << 8*(4-2-1)=>0xD7 << 8
//27 << 8*(4-3-1)=>27 << 0
//var a1 = 27 << 0;
//for (int i = 0; i < length; i++)
//{

// UInt64 currentData = (UInt64)data[i] << (8 * (length - i - 1));
// result += currentData;
//}
uint value = 20141013;
var a1 = (byte)(value >> 24);
var a2 = (byte)(value >> 16);
var a3 = (byte)(value >> 8);
var a4 = (byte)(value);
//01 51 83 213
var b = (uint)(data[3] | data[2] << 8 | data[1] << 16 | data[0] << 24);
var a=result.ToString();
}
}
}

+ 0
- 12
src/JT809.Protocol/Enums/ErrorCode.cs ファイルの表示

@@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.Enums
{
public enum ErrorCode
{
CRC16CheckInvalid = 1001,
HeaderLengthNotEqualBodyLength=1002
}
}

+ 0
- 25
src/JT809.Protocol/Exceptions/JT809Exception.cs ファイルの表示

@@ -1,25 +0,0 @@
using JT809.Protocol.Enums;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.Exceptions
{
public class JT809Exception:Exception
{
private readonly ErrorCode errorCode;

public JT809Exception(ErrorCode errorCode) : base(errorCode.ToString())
{
this.errorCode = errorCode;
}

public JT809Exception(ErrorCode errorCode, string message) : base(message)
{
this.errorCode = errorCode;
}


public ErrorCode ErrorCode => errorCode;
}
}

+ 29
- 4
src/JT809.Protocol/JT809.Protocol.csproj ファイルの表示

@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@@ -9,20 +10,44 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="Configs\**" />
<Compile Remove="Encrypt\**" />
<Compile Remove="JT809Enums\**" />
<Compile Remove="Escape\**" />
<Compile Remove="ProtocolPacket\Message\**" />
<Compile Remove="ProtocolPacket\**" />
<EmbeddedResource Remove="Configs\**" />
<EmbeddedResource Remove="Encrypt\**" />
<EmbeddedResource Remove="JT809Enums\**" />
<EmbeddedResource Remove="Escape\**" />
<EmbeddedResource Remove="ProtocolPacket\Message\**" />
<EmbeddedResource Remove="ProtocolPacket\**" />
<None Remove="Configs\**" />
<None Remove="Encrypt\**" />
<None Remove="JT809Enums\**" />
<None Remove="Escape\**" />
<None Remove="ProtocolPacket\Message\**" />
<None Remove="ProtocolPacket\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Constants.cs" />
<Compile Remove="IEncrypt.cs" />
<Compile Remove="IEscape.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="JT809Enums\JT809ErrorCode.cs" />
<Compile Include="JT809Enums\JT809BusinessType.cs" />
<Compile Include="JT809Enums\JT809SubBusinessType.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="System.Dynamic.Runtime" Version="4.3.0" />
<PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="JT809Properties\" />
</ItemGroup>
</Project>

+ 14
- 0
src/JT809.Protocol/JT809Attributes/JT809BodiesTypeAttribute.cs ファイルの表示

@@ -0,0 +1,14 @@
using System;

namespace JT809.Protocol.JT809Attributes
{
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class JT809BodiesTypeAttribute : Attribute
{
public JT809BodiesTypeAttribute(Type jT809BodiesType)
{
JT809BodiesType = jT809BodiesType;
}
public Type JT809BodiesType { get;}
}
}

+ 25
- 0
src/JT809.Protocol/JT809Attributes/JT809FormatterAttribute.cs ファイルの表示

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809Attributes
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public sealed class JT809FormatterAttribute:Attribute
{
public Type FormatterType { get; private set; }

public object[] Arguments { get; private set; }

public JT809FormatterAttribute(Type formatterType)
{
this.FormatterType = formatterType;
}

public JT809FormatterAttribute(Type formatterType, params object[] arguments)
{
this.FormatterType = formatterType;
this.Arguments = arguments;
}
}
}

+ 10
- 0
src/JT809.Protocol/JT809Bodies.cs ファイルの表示

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol
{
public abstract class JT809Bodies
{
}
}

src/JT809.Protocol/Enums/BusinessType.cs → src/JT809.Protocol/JT809Enums/JT809BusinessType.cs ファイルの表示

@@ -1,163 +1,166 @@
using System.ComponentModel;
namespace JT809.Protocol.Enums
{
/// <summary>
/// 业务数据类型标识
/// 数据交换一协议规定的业务数据类型名称和标识常量定义见表 73。业务数据类型标识的命名规则如下:
/// a) 上级平台向下级平台发送的请求消息,一般以“DOWN_”开头,以后缀_REQ 结尾;而下级平台向上级平台发送的请求消息一般以“UP_”开头,以后缀_REQ 结尾;
/// b) 当上下级平台之间有应答消息情况下,应答消息可继续沿用对应的请求消息开头标识符,而通过后缀 RSP 来标识结尾。
/// </summary>
public enum BusinessType : ushort
{
#region 链路管理类
///<summary>
///主链路登录请求消息
///</summary>
[Description("主链路登录请求消息")]
UP_CONNECT_REQ = 0x1001,
///<summary>
///主链路登录应答消息
///</summary>
[Description("主链路登录应答消息")]
UP_CONNECT_RSP = 0x1002,
///<summary>
///主链路注销请求消息
///</summary>
[Description("主链路注销请求消息")]
UP_DISCONNECT_REQ = 0x1003,
///<summary>
///主链路注销应答消息
///</summary>
[Description("主链路注销应答消息")]
UP_DISCONNECT_RSP = 0x1004,
///<summary>
///主链路连接保持请求消息
///</summary>
[Description("主链路连接保持请求消息")]
UP_LINKTEST_REQ = 0x1005,
///<summary>
///主链路连接保持应答消息
///</summary>
[Description("主链路连接保持应答消息")]
UP_LINKTEST_RSP = 0x1006,
///<summary>
///主链路断开通知消息
///</summary>
[Description("主链路断开通知消息")]
UP_DISCONNECT_INFORM = 0x1007,
///<summary>
///下级平台主动关闭链路通知消息
///</summary>
[Description("下级平台主动关闭链路通知消息")]
UP_CLOSELINK_INFORM = 0x1008,
///<summary>
///从链路连接请求消息
///</summary>
[Description("从链路连接请求消息")]
DOWN_CONNECT_REQ = 0x9001,
///<summary>
///从链路连接应答消息
///</summary>
[Description("从链路连接应答消息")]
DOWN_CONNECT_RSP = 0x9002,
///<summary>
///从链路注销请求消息
///</summary>
[Description("从链路注销请求消息")]
DOWN_DISCONNECT_REQ = 0x9003,
///<summary>
///从链路注销应答消息
///</summary>
[Description("从链路注销应答消息")]
DOWN_DISCONNECT_RSP = 0x9004,
///<summary>
///从链路连接保持请求消息
///</summary>
[Description("从链路连接保持请求消息")]
DOWN_LINKTEST_REQ = 0x9005,
///<summary>
///从链路连接保持应答消息
///</summary>
[Description("从链路连接保持应答消息")]
DOWN_LINKTEST_RSP = 0x9006,
///<summary>
///从链路断开通知消息
///</summary>
[Description("从链路断开通知消息")]
DOWN_DISCONNECT_INFORM = 0x9007,
///<summary>
///上级平台主动关闭链路通知消息
///</summary>
[Description("上级平台主动关闭链路通知消息")]
DOWN_CLOSELINK_INFORM = 0x9008,
#endregion
#region 信息统计类
///<summary>
///接收定位信息数量通知消息
///</summary>
[Description("接收定位信息数量通知消息")]
DOWN_TOTAL_RECV_BACK_MSG = 0x9101,
#endregion
#region 车辆动态信息交换
///<summary>
///主链路动态信息交换消息
///</summary>
[Description("主链路动态信息交换消息")]
UP_EXG_MSG = 0x1200,
///<summary>
///从链路动态信息交换消息
///</summary>
[Description("从链路动态信息交换消息")]
DOWN_EXG_MSG = 0x9200,
#endregion
#region 平台间信息交互类
///<summary>
///主链路平台间信息交互消息
///</summary>
[Description("主链路平台间信息交互消息")]
UP_PLATFORM_MSG = 0x1300,
///<summary>
///从链路平台间信息交互消息
///</summary>
[Description("从链路平台间信息交互消息")]
DOWN_PLATFORM_MSG = 0x9300,
#endregion
#region 车辆报警信息交互类
///<summary>
///主链路报警信息交互消息
///</summary>
[Description("主链路报警信息交互消息")]
UP_WARN_MSG = 0x1400,
///<summary>
///从链路报警信息交互消息
///</summary>
[Description("从链路报警信息交互消息")]
DOWN_WARN_MSG = 0x9400,
#endregion
#region 车辆监管类
///<summary>
///主链路车辆监管消息
///</summary>
[Description("主链路车辆监管消息")]
UP_CTRL_MSG = 0x1500,
///<summary>
///从链路车辆监管消息
///</summary>
[Description("从链路车辆监管消息")]
DOWN_CTRL_MSG = 0x9500,
#endregion
#region 车辆静态信息交换类
///<summary>
///主链路静态信息交换消息
///</summary>
[Description("主链路静态信息交换消息")]
UP_BASE_MSG = 0x1600,
///<summary>
///从链路静态信息交换消息
///</summary>
[Description("从链路静态信息交换消息")]
DOWN_BASE_MSG = 0x9600,
#endregion
}
}
using JT809.Protocol.JT809Attributes;
using JT809.Protocol.JT809MessageBody;
using System.ComponentModel;

namespace JT809.Protocol.JT809Enums
{
/// <summary>
/// 业务数据类型标识
/// 数据交换一协议规定的业务数据类型名称和标识常量定义见表 73。业务数据类型标识的命名规则如下:
/// a) 上级平台向下级平台发送的请求消息,一般以“DOWN_”开头,以后缀_REQ 结尾;而下级平台向上级平台发送的请求消息一般以“UP_”开头,以后缀_REQ 结尾;
/// b) 当上下级平台之间有应答消息情况下,应答消息可继续沿用对应的请求消息开头标识符,而通过后缀 RSP 来标识结尾。
/// </summary>
public enum JT809BusinessType : ushort
{
#region 链路管理类
///<summary>
///主链路登录请求消息
///</summary>
[Description("主链路登录请求消息")]
[JT809BodiesType(typeof(JT809_0x1001))]
UP_CONNECT_REQ = 0x1001,
///<summary>
///主链路登录应答消息
///</summary>
[Description("主链路登录应答消息")]
UP_CONNECT_RSP = 0x1002,
///<summary>
///主链路注销请求消息
///</summary>
[Description("主链路注销请求消息")]
UP_DISCONNECT_REQ = 0x1003,
///<summary>
///主链路注销应答消息
///</summary>
[Description("主链路注销应答消息")]
UP_DISCONNECT_RSP = 0x1004,
///<summary>
///主链路连接保持请求消息
///</summary>
[Description("主链路连接保持请求消息")]
UP_LINKTEST_REQ = 0x1005,
///<summary>
///主链路连接保持应答消息
///</summary>
[Description("主链路连接保持应答消息")]
UP_LINKTEST_RSP = 0x1006,
///<summary>
///主链路断开通知消息
///</summary>
[Description("主链路断开通知消息")]
UP_DISCONNECT_INFORM = 0x1007,
///<summary>
///下级平台主动关闭链路通知消息
///</summary>
[Description("下级平台主动关闭链路通知消息")]
UP_CLOSELINK_INFORM = 0x1008,
///<summary>
///从链路连接请求消息
///</summary>
[Description("从链路连接请求消息")]
DOWN_CONNECT_REQ = 0x9001,
///<summary>
///从链路连接应答消息
///</summary>
[Description("从链路连接应答消息")]
DOWN_CONNECT_RSP = 0x9002,
///<summary>
///从链路注销请求消息
///</summary>
[Description("从链路注销请求消息")]
DOWN_DISCONNECT_REQ = 0x9003,
///<summary>
///从链路注销应答消息
///</summary>
[Description("从链路注销应答消息")]
DOWN_DISCONNECT_RSP = 0x9004,
///<summary>
///从链路连接保持请求消息
///</summary>
[Description("从链路连接保持请求消息")]
DOWN_LINKTEST_REQ = 0x9005,
///<summary>
///从链路连接保持应答消息
///</summary>
[Description("从链路连接保持应答消息")]
DOWN_LINKTEST_RSP = 0x9006,
///<summary>
///从链路断开通知消息
///</summary>
[Description("从链路断开通知消息")]
DOWN_DISCONNECT_INFORM = 0x9007,
///<summary>
///上级平台主动关闭链路通知消息
///</summary>
[Description("上级平台主动关闭链路通知消息")]
DOWN_CLOSELINK_INFORM = 0x9008,
#endregion
#region 信息统计类
///<summary>
///接收定位信息数量通知消息
///</summary>
[Description("接收定位信息数量通知消息")]
DOWN_TOTAL_RECV_BACK_MSG = 0x9101,
#endregion
#region 车辆动态信息交换
///<summary>
///主链路动态信息交换消息
///</summary>
[Description("主链路动态信息交换消息")]
UP_EXG_MSG = 0x1200,
///<summary>
///从链路动态信息交换消息
///</summary>
[Description("从链路动态信息交换消息")]
DOWN_EXG_MSG = 0x9200,
#endregion
#region 平台间信息交互类
///<summary>
///主链路平台间信息交互消息
///</summary>
[Description("主链路平台间信息交互消息")]
UP_PLATFORM_MSG = 0x1300,
///<summary>
///从链路平台间信息交互消息
///</summary>
[Description("从链路平台间信息交互消息")]
DOWN_PLATFORM_MSG = 0x9300,
#endregion
#region 车辆报警信息交互类
///<summary>
///主链路报警信息交互消息
///</summary>
[Description("主链路报警信息交互消息")]
UP_WARN_MSG = 0x1400,
///<summary>
///从链路报警信息交互消息
///</summary>
[Description("从链路报警信息交互消息")]
DOWN_WARN_MSG = 0x9400,
#endregion
#region 车辆监管类
///<summary>
///主链路车辆监管消息
///</summary>
[Description("主链路车辆监管消息")]
UP_CTRL_MSG = 0x1500,
///<summary>
///从链路车辆监管消息
///</summary>
[Description("从链路车辆监管消息")]
DOWN_CTRL_MSG = 0x9500,
#endregion
#region 车辆静态信息交换类
///<summary>
///主链路静态信息交换消息
///</summary>
[Description("主链路静态信息交换消息")]
UP_BASE_MSG = 0x1600,
///<summary>
///从链路静态信息交换消息
///</summary>
[Description("从链路静态信息交换消息")]
DOWN_BASE_MSG = 0x9600,
#endregion
}
}

+ 17
- 0
src/JT809.Protocol/JT809Enums/JT809ErrorCode.cs ファイルの表示

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809Enums
{
public enum JT809ErrorCode
{
CRC16CheckInvalid = 1001,
HeaderLengthNotEqualBodyLength=1002,
GetFormatterError=1003,
SerializeError=1004,
DeserializeError=1005,
HeaderParseError=1006,
BodiesParseError=1007
}
}

src/JT809.Protocol/Enums/SubBusinessType.cs → src/JT809.Protocol/JT809Enums/JT809SubBusinessType.cs ファイルの表示

@@ -1,260 +1,260 @@
using System.ComponentModel;
namespace JT809.Protocol.Enums
{
///<summary>
///子业务类型标识
///</summary>
public enum SubBusinessType : ushort
{
#region 主链路动态信息交换消息 UP_EXG_MSG
/// <summary>
/// 上传车辆注册信息
/// </summary>
[Description("上传车辆注册信息")]
UP_EXG_MSG_REGISTER = 0x1201,
///<summary>
///实时上传车辆定位信息
///</summary>
[Description("实时上传车辆定位信息")]
UP_EXG_MSG_REAL_LOCATION = 0x1202,
///<summary>
///车辆定位信息自动补报
///</summary>
[Description("车辆定位信息自动补报")]
UP_EXG_MSG_HISTORY_LOCATION = 0x1203,
///<summary>
///启动车辆定位信息交换应答
///</summary>
[Description("启动车辆定位信息交换应答")]
UP_EXG_MSG_RETURN_STARTUP_ACK = 0x1205,
///<summary>
///结束车辆定位信息交换应答
///</summary>
[Description("结束车辆定位信息交换应答")]
UP_EXG_MSG_RETURN_END_ACK = 0x1206,
///<summary>
///申请交换指定车辆定位信息请求
///</summary>
[Description("申请交换指定车辆定位信息请求")]
UP_EXG_MSG_APPLY_FOR_MONITOR_STARTUP = 0x1207,
///<summary>
///取消交换指定车辆定位信息请求
///</summary>
[Description("取消交换指定车辆定位信息请求")]
UP_EXG_MSG_APPLY_FOR_MONITOR_END = 0x1208,
///<summary>
///补发车辆定位信息请求
///</summary>
[Description("补发车辆定位信息请求")]
UP_EXG_MSG_APPLY_HISGNSSDATA_REQ = 0x1209,
///<summary>
///上报车辆驾驶员身份识别信息应答
///</summary>
[Description("上报车辆驾驶员身份识别信息应答")]
UP_EXG_MSG_REPORT_DRIVER_INFO_ACK = 0x120A,
///<summary>
///上报车辆电子运单应答
///</summary>
[Description("上报车辆电子运单应答")]
UP_EXG_MSG_TAKE_EWAYBILL_ACK = 0x120B,
///<summary>
///主动上报驾驶员身份信息
///</summary>
[Description("主动上报驾驶员身份信息")]
UP_EXG_MSG_REPORT_DRIVER_INFO = 0x120C,
///<summary>
///主动上报车辆电子运单信息
///</summary>
[Description("主动上报车辆电子运单信息")]
UP_EXG_MSG_REPORT_EWAYBILL_INFO = 0x120D,
#endregion
#region 从链路动态信息交换消息 DOWN_EXG_MSG
///<summary>
///交换车辆定位信息
///</summary>
[Description("交换车辆定位信息")]
DOWN_EXG_MSG_CAR_LOCATION = 0x9202,
///<summary>
///车辆定位信息交换补发
///</summary>
[Description("车辆定位信息交换补发")]
DOWN_EXG_MSG_HISTORY_ARCOSSAREA = 0x9203,
///<summary>
///交换车辆静态信息
///</summary>
[Description("交换车辆静态信息")]
DOWN_EXG_MSG_CAR_INFO = 0x9204,
///<summary>
///启动车辆定位信息交换请求
///</summary>
[Description("启动车辆定位信息交换请求")]
DOWN_EXG_MSG_RETURN_STARTUP = 0x9205,
///<summary>
///结束车辆定位信息交换请求
///</summary>
[Description("结束车辆定位信息交换请求")]
DOWN_EXG_MSG_RETURN_END = 0x9206,
///<summary>
///申请交换指定车辆定位信息应答
///</summary>
[Description("申请交换指定车辆定位信息应答")]
DOWN_EXG_MSG_APPLY_FOR_MONITOR_STARTUP_ACK = 0x9207,
///<summary>
///取消交换指定车辆定位信息应答
///</summary>
[Description("取消交换指定车辆定位信息应答")]
DOWN_EXG_MSG_APPLY_FOR_MONITOR_END_ACK = 0x9208,
///<summary>
///补发车辆定位信息应答
///</summary>
[Description("补发车辆定位信息应答")]
DOWN_EXG_MSG_APPLY_HISGNSSDATA_ACK = 0x9209,
///<summary>
///上报车辆驾驶员身份识别信息请求
///</summary>
[Description("上报车辆驾驶员身份识别信息请求")]
DOWN_EXG_MSG_REPORT_DRIVER_INFO = 0x920A,
///<summary>
///上报车辆电子运单请求
///</summary>
[Description("上报车辆电子运单请求")]
DOWN_EXG_MSG_TAKE_EWAYBILL_REQ = 0x920B,
#endregion
#region 主链路平台信息交互消息 UP_PLATFORM_MSG
///<summary>
///平台查岗应答
///</summary>
[Description("平台查岗应答")]
UP_PLATFORM_MSG_POST_QUERY_ACK = 0x1301,
///<summary>
///下发平台间报文应答
///</summary>
[Description("下发平台间报文应答")]
UP_PLATFORM_MSG_INFO_ACK = 0x1302,
#endregion
#region 从链路平台信息交互消息 DOWN_PLATFORM_MSG
///<summary>
///平台查岗请求
///</summary>
[Description("平台查岗请求")]
DOWN_PLATFORM_MSG_POST_QUERY_REQ = 0x9301,
///<summary>
///下发平台间报文请求
///</summary>
[Description("下发平台间报文请求")]
DOWN_PLATFORM_MSG_INFO_REQ = 0x9302,
#endregion
#region 主链路报警信息交互消息 UP_WARN_MSG
///<summary>
///报警督办应答
///</summary>
[Description("报警督办应答")]
UP_WARN_MSG_URGE_TODO_ACK = 0x1401,
///<summary>
///上报报警信息
///</summary>
[Description("上报报警信息")]
UP_WARN_MSG_ADPT_INFO = 0x1402,
///<summary>
///主动上报报警处理结果信息
///</summary>
[Description("主动上报报警处理结果信息")]
UP_WARN_MSG_ADPT_TODO_INFO = 0x1403,
#endregion
#region 从链路报警信息交互消息 DOWN_WARN_MSG
///<summary>
///报警督办请求
///</summary>
[Description("报警督办请求")]
DOWN_WARN_MSG_URGE_TODO_REQ = 0x9401,
///<summary>
///报警预警
///</summary>
[Description("报警预警")]
DOWN_WARN_MSG_INFORM_TIPS = 0x9402,
///<summary>
///实时交换报警信息
///</summary>
[Description("实时交换报警信息")]
DOWN_WARN_MSG_EXG_INFORM = 0x9403,
#endregion
#region 主链路车辆监管消息 UP_CTRL_MSG
///<summary>
///车辆单向监听应答
///</summary>
[Description("车辆单向监听应答")]
UP_CTRL_MSG_MONITOR_VEHICLE_ACK = 0x1501,
///<summary>
///车辆拍照应答
///</summary>
[Description("车辆拍照应答")]
UP_CTRL_MSG_TAKE_PHOTO_ACK = 0x1502,
///<summary>
///下发车辆报文应答
///</summary>
[Description("下发车辆报文应答")]
UP_CTRL_MSG_TEXT_INFO_ACK = 0x1503,
///<summary>
///上报车辆行驶记录应答
///</summary>
[Description("上报车辆行驶记录应答")]
UP_CTRL_MSG_TAKE_TRAVEL_ACK = 0x1504,
///<summary>
///车辆应急接入监管平台应答消息
///</summary>
[Description("车辆应急接入监管平台应答消息")]
UP_CTRL_MSG_EMERGENCY_MONITORING_ACK = 0x1505,
#endregion
#region 从链路车辆监管消息 DOWN_CTRL_MSG
///<summary>
///车辆单向监听请求
///</summary>
[Description("车辆单向监听请求")]
DOWN_CTRL_MSG_MONITOR_VEHICLE_REQ = 0x9501,
///<summary>
///车辆拍照请求
///</summary>
[Description("车辆拍照请求")]
DOWN_CTRL_MSG_TAKE_PHOTO_REQ = 0x9502,
///<summary>
///下发车辆报文请求
///</summary>
[Description("下发车辆报文请求")]
DOWN_CTRL_MSG_TEXT_INFO = 0x9503,
///<summary>
///上报车辆行驶记录请求
///</summary>
[Description("上报车辆行驶记录请求")]
DOWN_CTRL_MSG_TAKE_TRAVEL_REQ = 0x9504,
///<summary>
///车辆应急接入监管平台请求消息
///</summary>
[Description("车辆应急接入监管平台请求消息")]
DOWN_CTRL_MSG_EMERGENCY_MONITORING_REQ = 0x9505,
#endregion
#region 主链路静态信息交换消息 UP_BASE_MSG
///<summary>
///补报车辆静态信息应答
///</summary>
[Description("补报车辆静态信息应答")]
UP_BASE_MSG_VEHICLE_ADDED_ACK = 0x1601,
#endregion
#region 从链路静态信息交换消息 DOWN_BASE_MSG
///<summary>
///补报车辆静态信息请求
///</summary>
[Description("补报车辆静态信息请求")]
DOWN_BASE_MSG_VEHICLE_ADDED = 0x9601,
#endregion
}
}
using System.ComponentModel;
namespace JT809.Protocol.JT809Enums
{
///<summary>
///子业务类型标识
///</summary>
public enum JT809SubBusinessType : ushort
{
#region 主链路动态信息交换消息 UP_EXG_MSG
/// <summary>
/// 上传车辆注册信息
/// </summary>
[Description("上传车辆注册信息")]
UP_EXG_MSG_REGISTER = 0x1201,
///<summary>
///实时上传车辆定位信息
///</summary>
[Description("实时上传车辆定位信息")]
UP_EXG_MSG_REAL_LOCATION = 0x1202,
///<summary>
///车辆定位信息自动补报
///</summary>
[Description("车辆定位信息自动补报")]
UP_EXG_MSG_HISTORY_LOCATION = 0x1203,
///<summary>
///启动车辆定位信息交换应答
///</summary>
[Description("启动车辆定位信息交换应答")]
UP_EXG_MSG_RETURN_STARTUP_ACK = 0x1205,
///<summary>
///结束车辆定位信息交换应答
///</summary>
[Description("结束车辆定位信息交换应答")]
UP_EXG_MSG_RETURN_END_ACK = 0x1206,
///<summary>
///申请交换指定车辆定位信息请求
///</summary>
[Description("申请交换指定车辆定位信息请求")]
UP_EXG_MSG_APPLY_FOR_MONITOR_STARTUP = 0x1207,
///<summary>
///取消交换指定车辆定位信息请求
///</summary>
[Description("取消交换指定车辆定位信息请求")]
UP_EXG_MSG_APPLY_FOR_MONITOR_END = 0x1208,
///<summary>
///补发车辆定位信息请求
///</summary>
[Description("补发车辆定位信息请求")]
UP_EXG_MSG_APPLY_HISGNSSDATA_REQ = 0x1209,
///<summary>
///上报车辆驾驶员身份识别信息应答
///</summary>
[Description("上报车辆驾驶员身份识别信息应答")]
UP_EXG_MSG_REPORT_DRIVER_INFO_ACK = 0x120A,
///<summary>
///上报车辆电子运单应答
///</summary>
[Description("上报车辆电子运单应答")]
UP_EXG_MSG_TAKE_EWAYBILL_ACK = 0x120B,
///<summary>
///主动上报驾驶员身份信息
///</summary>
[Description("主动上报驾驶员身份信息")]
UP_EXG_MSG_REPORT_DRIVER_INFO = 0x120C,
///<summary>
///主动上报车辆电子运单信息
///</summary>
[Description("主动上报车辆电子运单信息")]
UP_EXG_MSG_REPORT_EWAYBILL_INFO = 0x120D,
#endregion
#region 从链路动态信息交换消息 DOWN_EXG_MSG
///<summary>
///交换车辆定位信息
///</summary>
[Description("交换车辆定位信息")]
DOWN_EXG_MSG_CAR_LOCATION = 0x9202,
///<summary>
///车辆定位信息交换补发
///</summary>
[Description("车辆定位信息交换补发")]
DOWN_EXG_MSG_HISTORY_ARCOSSAREA = 0x9203,
///<summary>
///交换车辆静态信息
///</summary>
[Description("交换车辆静态信息")]
DOWN_EXG_MSG_CAR_INFO = 0x9204,
///<summary>
///启动车辆定位信息交换请求
///</summary>
[Description("启动车辆定位信息交换请求")]
DOWN_EXG_MSG_RETURN_STARTUP = 0x9205,
///<summary>
///结束车辆定位信息交换请求
///</summary>
[Description("结束车辆定位信息交换请求")]
DOWN_EXG_MSG_RETURN_END = 0x9206,
///<summary>
///申请交换指定车辆定位信息应答
///</summary>
[Description("申请交换指定车辆定位信息应答")]
DOWN_EXG_MSG_APPLY_FOR_MONITOR_STARTUP_ACK = 0x9207,
///<summary>
///取消交换指定车辆定位信息应答
///</summary>
[Description("取消交换指定车辆定位信息应答")]
DOWN_EXG_MSG_APPLY_FOR_MONITOR_END_ACK = 0x9208,
///<summary>
///补发车辆定位信息应答
///</summary>
[Description("补发车辆定位信息应答")]
DOWN_EXG_MSG_APPLY_HISGNSSDATA_ACK = 0x9209,
///<summary>
///上报车辆驾驶员身份识别信息请求
///</summary>
[Description("上报车辆驾驶员身份识别信息请求")]
DOWN_EXG_MSG_REPORT_DRIVER_INFO = 0x920A,
///<summary>
///上报车辆电子运单请求
///</summary>
[Description("上报车辆电子运单请求")]
DOWN_EXG_MSG_TAKE_EWAYBILL_REQ = 0x920B,
#endregion
#region 主链路平台信息交互消息 UP_PLATFORM_MSG
///<summary>
///平台查岗应答
///</summary>
[Description("平台查岗应答")]
UP_PLATFORM_MSG_POST_QUERY_ACK = 0x1301,
///<summary>
///下发平台间报文应答
///</summary>
[Description("下发平台间报文应答")]
UP_PLATFORM_MSG_INFO_ACK = 0x1302,
#endregion
#region 从链路平台信息交互消息 DOWN_PLATFORM_MSG
///<summary>
///平台查岗请求
///</summary>
[Description("平台查岗请求")]
DOWN_PLATFORM_MSG_POST_QUERY_REQ = 0x9301,
///<summary>
///下发平台间报文请求
///</summary>
[Description("下发平台间报文请求")]
DOWN_PLATFORM_MSG_INFO_REQ = 0x9302,
#endregion
#region 主链路报警信息交互消息 UP_WARN_MSG
///<summary>
///报警督办应答
///</summary>
[Description("报警督办应答")]
UP_WARN_MSG_URGE_TODO_ACK = 0x1401,
///<summary>
///上报报警信息
///</summary>
[Description("上报报警信息")]
UP_WARN_MSG_ADPT_INFO = 0x1402,
///<summary>
///主动上报报警处理结果信息
///</summary>
[Description("主动上报报警处理结果信息")]
UP_WARN_MSG_ADPT_TODO_INFO = 0x1403,
#endregion
#region 从链路报警信息交互消息 DOWN_WARN_MSG
///<summary>
///报警督办请求
///</summary>
[Description("报警督办请求")]
DOWN_WARN_MSG_URGE_TODO_REQ = 0x9401,
///<summary>
///报警预警
///</summary>
[Description("报警预警")]
DOWN_WARN_MSG_INFORM_TIPS = 0x9402,
///<summary>
///实时交换报警信息
///</summary>
[Description("实时交换报警信息")]
DOWN_WARN_MSG_EXG_INFORM = 0x9403,
#endregion
#region 主链路车辆监管消息 UP_CTRL_MSG
///<summary>
///车辆单向监听应答
///</summary>
[Description("车辆单向监听应答")]
UP_CTRL_MSG_MONITOR_VEHICLE_ACK = 0x1501,
///<summary>
///车辆拍照应答
///</summary>
[Description("车辆拍照应答")]
UP_CTRL_MSG_TAKE_PHOTO_ACK = 0x1502,
///<summary>
///下发车辆报文应答
///</summary>
[Description("下发车辆报文应答")]
UP_CTRL_MSG_TEXT_INFO_ACK = 0x1503,
///<summary>
///上报车辆行驶记录应答
///</summary>
[Description("上报车辆行驶记录应答")]
UP_CTRL_MSG_TAKE_TRAVEL_ACK = 0x1504,
///<summary>
///车辆应急接入监管平台应答消息
///</summary>
[Description("车辆应急接入监管平台应答消息")]
UP_CTRL_MSG_EMERGENCY_MONITORING_ACK = 0x1505,
#endregion
#region 从链路车辆监管消息 DOWN_CTRL_MSG
///<summary>
///车辆单向监听请求
///</summary>
[Description("车辆单向监听请求")]
DOWN_CTRL_MSG_MONITOR_VEHICLE_REQ = 0x9501,
///<summary>
///车辆拍照请求
///</summary>
[Description("车辆拍照请求")]
DOWN_CTRL_MSG_TAKE_PHOTO_REQ = 0x9502,
///<summary>
///下发车辆报文请求
///</summary>
[Description("下发车辆报文请求")]
DOWN_CTRL_MSG_TEXT_INFO = 0x9503,
///<summary>
///上报车辆行驶记录请求
///</summary>
[Description("上报车辆行驶记录请求")]
DOWN_CTRL_MSG_TAKE_TRAVEL_REQ = 0x9504,
///<summary>
///车辆应急接入监管平台请求消息
///</summary>
[Description("车辆应急接入监管平台请求消息")]
DOWN_CTRL_MSG_EMERGENCY_MONITORING_REQ = 0x9505,
#endregion
#region 主链路静态信息交换消息 UP_BASE_MSG
///<summary>
///补报车辆静态信息应答
///</summary>
[Description("补报车辆静态信息应答")]
UP_BASE_MSG_VEHICLE_ADDED_ACK = 0x1601,
#endregion
#region 从链路静态信息交换消息 DOWN_BASE_MSG
///<summary>
///补报车辆静态信息请求
///</summary>
[Description("补报车辆静态信息请求")]
DOWN_BASE_MSG_VEHICLE_ADDED = 0x9601,
#endregion
}
}

+ 32
- 0
src/JT809.Protocol/JT809Exceptions/JT809Exception.cs ファイルの表示

@@ -0,0 +1,32 @@
using JT809.Protocol.JT809Enums;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809Exceptions
{
public class JT809Exception:Exception
{
public JT809Exception(JT809ErrorCode errorCode) : base(errorCode.ToString())
{
ErrorCode = errorCode;
}

public JT809Exception(JT809ErrorCode errorCode, string message) : base(message)
{
ErrorCode = errorCode;
}

public JT809Exception(JT809ErrorCode errorCode, Exception ex) : base(ex.Message, ex)
{
ErrorCode = errorCode;
}

public JT809Exception(JT809ErrorCode errorCode, string message, Exception ex) : base(ex.Message, ex)
{
ErrorCode = errorCode;
}

public JT809ErrorCode ErrorCode { get;}
}
}

+ 429
- 0
src/JT809.Protocol/JT809Extensions/JT809BinaryExtensions.cs ファイルの表示

@@ -0,0 +1,429 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Buffers.Binary;
using System.Buffers;

namespace JT809.Protocol.JT809Extensions
{
public static class JT809BinaryExtensions
{
/// <summary>
/// 日期限制于2000年
/// </summary>
private const int DateLimitYear = 2000;

private const ushort cnCRC_CCITT = 0x1021; //CRC校验多项式

private static ulong[] CRC = new ulong[256]; //建立CRC16表

static JT809BinaryExtensions()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
encoding = Encoding.GetEncoding("GBK");
ushort i, j;
ushort nData;
ushort nAccum;
for (i = 0; i < 256; i++)
{
nData = (ushort)(i << 8);
nAccum = 0;
for (j = 0; j < 8; j++)
{
if (((nData ^ nAccum) & 0x8000) > 0)
nAccum = (ushort)((nAccum << 1) ^ cnCRC_CCITT);
else
nAccum <<= 1;
nData <<= 1;
}
CRC[i] = (ulong)nAccum;
}
}

private static Encoding encoding;

public static int ReadBCD32(this byte data, byte dig)
{
int result = Convert.ToInt32(data.ToString("X"));
return result * (int)Math.Pow(100, dig - 1);
}

public static long ReadBCD64(this byte data, byte dig)
{
long result = Convert.ToInt64(data.ToString("X"));
return result * (long)Math.Pow(100, dig - 1);
}

public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset, int len)
{
string value = encoding.GetString(read.Slice(offset, len).ToArray());
offset += value.Length;
return value.Trim('\0');
}

public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset)
{
string value = encoding.GetString(read.Slice(offset).ToArray());
offset += value.Length;
return value.Trim('\0');
}

//public static void WriteLatLng(byte[] write, int offset,double latlng)
//{
// WriteLittle(write, (int)(Math.Pow(10, 6) * latlng), offset, 4);
//}

public static long ReadBCD(ReadOnlySpan<byte> buf,ref int offset, int len)
{
long result = 0;
try
{
for (int i = offset; i < offset + len; i++)
{
result += buf[i].ReadBCD64((byte)(offset + len - i));
}
}
catch
{
}
offset = offset + len;
return result;
}

public static DateTime ReadDateTimeLittle(ReadOnlySpan<byte> buf,ref int offset)
{
DateTime dateTime= new DateTime(
(buf[offset]).ReadBCD32(1) + DateLimitYear,
(buf[offset + 1]).ReadBCD32(1),
(buf[offset + 2]).ReadBCD32(1),
(buf[offset + 3]).ReadBCD32(1),
(buf[offset + 4]).ReadBCD32(1),
(buf[offset + 5]).ReadBCD32(1));
offset = offset + 6;
return dateTime;
}

public static DateTime ReadDateLittle(ReadOnlySpan<byte> buf, ref int offset)
{
DateTime dateTime = new DateTime(
((buf[offset] << 8) | (buf[offset + 1])),
(buf[offset + 2]).ReadBCD32(1),
(buf[offset + 3]).ReadBCD32(1));
offset = offset + 4;
return dateTime;
}

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 int WriteLittle(ref byte[] write, int offset, DateTime date)
{
write[offset] = ((byte)(date.Year - DateLimitYear)).ToBcdByte();
write[offset + 1] = ((byte)(date.Month)).ToBcdByte();
write[offset + 2] = ((byte)(date.Day)).ToBcdByte();
write[offset + 3] = ((byte)(date.Hour)).ToBcdByte();
write[offset + 4] = ((byte)(date.Minute)).ToBcdByte();
write[offset + 5] = ((byte)(date.Second)).ToBcdByte();
return 6;
}

public static int WriteDateTime6Little(IMemoryOwner<byte> memoryOwner, int offset, DateTime date)
{
memoryOwner.Memory.Span[offset] = ((byte)(date.Year - DateLimitYear)).ToBcdByte();
memoryOwner.Memory.Span[offset + 1] = ((byte)(date.Month)).ToBcdByte();
memoryOwner.Memory.Span[offset + 2] = ((byte)(date.Day)).ToBcdByte();
memoryOwner.Memory.Span[offset + 3] = ((byte)(date.Hour)).ToBcdByte();
memoryOwner.Memory.Span[offset + 4] = ((byte)(date.Minute)).ToBcdByte();
memoryOwner.Memory.Span[offset + 5] = ((byte)(date.Second)).ToBcdByte();
return 6;
}

public static int WriteDateLittle(ref byte[] write, int offset, DateTime date)
{
write[offset] = (byte)(date.Year >> 8);
write[offset + 1] = (byte)date.Year;
write[offset + 2] = ((byte)(date.Month)).ToBcdByte();
write[offset + 3] = ((byte)(date.Day)).ToBcdByte();
return 4;
}

public static int WriteDateTime4Little(IMemoryOwner<byte> memoryOwner, int offset, DateTime date)
{
memoryOwner.Memory.Span[offset] = (byte)(date.Year >> 8);
memoryOwner.Memory.Span[offset + 1] = (byte)date.Year;
memoryOwner.Memory.Span[offset + 2] = ((byte)(date.Month)).ToBcdByte();
memoryOwner.Memory.Span[offset + 3] = ((byte)(date.Day)).ToBcdByte();
return 4;
}

public static int WriteLittle(ref 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 WriteInt32Little(IMemoryOwner<byte> memoryOwner, int offset, int data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 24);
memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 16);
memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 3] = (byte)data;
return 4;
}

public static int WriteUInt32Little(IMemoryOwner<byte> memoryOwner, int offset, uint data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 24);
memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 16);
memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 3] = (byte)data;
return 4;
}

public static int WriteUInt16Little(ref byte[] write, int offset, ushort data)
{
write[offset] = (byte)(data >> 8);
write[offset + 1] = (byte)data;
return 2;
}

public static int WriteUInt16Little(IMemoryOwner<byte> memoryOwner, int offset, ushort data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 1] = (byte)data;
return 2;
}

public static int WriteLittle(ref byte[] write, int offset, byte data)
{
write[offset] = data;
return 1;
}

public static int WriteByteLittle(IMemoryOwner<byte> memoryOwner, int offset, byte data)
{
memoryOwner.Memory.Span[offset] = data;
return 1;
}

public static int WriteBytesLittle(IMemoryOwner<byte> memoryOwner, int offset, byte[] data)
{
CopyTo(data, memoryOwner.Memory.Span, offset);
return data.Length;
}

public static int WriteLittle(ref byte[] write, int offset, byte[] data)
{
Buffer.BlockCopy(data, 0, write, offset, data.Length);
return data.Length;
}

public static int WriteLittle(ref byte[] write, int offset, string data)
{
byte[] codeBytes = encoding.GetBytes(data);
Buffer.BlockCopy(codeBytes, 0, write, offset, codeBytes.Length);
return codeBytes.Length;
}

public static int WriteStringLittle(IMemoryOwner<byte> memoryOwner, int offset, string data)
{
byte[] codeBytes = encoding.GetBytes(data);
CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
return codeBytes.Length;
}

public static int WriteBCDLittle(ref byte[] write, int offset, string data, int digit, int len)
{
ReadOnlySpan<char> bcd = data.PadLeft(len, '0').AsSpan();
for (int i = 0; i < digit; i++)
{
write[offset + i] = Convert.ToByte(bcd.Slice(i * 2, 2).ToString(), 16);
}
return digit;
}

public static int WriteBCDLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int digit, int len)
{
ReadOnlySpan<char> bcd = data.PadLeft(len, '0').AsSpan();
for (int i = 0; i < digit; i++)
{
memoryOwner.Memory.Span[offset + i] = Convert.ToByte(bcd.Slice(i * 2, 2).ToString(), 16);
}
return digit;
}

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, 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>
/// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。
/// </summary>
/// <param name="packege"></param>
/// <param name="ucbuf"></param>
/// <param name="offset"></param>
/// <param name="iLen"></param>
/// <returns></returns>
public static ushort ToCRC16_CCITT(this Span<byte> ucbuf, int offset, int iLen)
{
ushort checkCode = 0xFFFF;
for (int j = offset; j < iLen; ++j)
{
checkCode = (ushort)((checkCode << 8) ^ (ushort)CRC[(checkCode >> 8) ^ ucbuf[j]]);
}
return checkCode;
}

/// <summary>
/// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。
/// </summary>
/// <param name="packege"></param>
/// <param name="ucbuf"></param>
/// <param name="offset"></param>
/// <param name="iLen"></param>
/// <returns></returns>
public static ushort ToCRC16_CCITT(this ReadOnlySpan<byte> ucbuf, int offset, int iLen)
{
ushort checkCode = 0xFFFF;
for (int j = offset; j < iLen; ++j)
{
checkCode = (ushort)((checkCode << 8) ^ (ushort)CRC[(checkCode >> 8) ^ ucbuf[j]]);
}
return checkCode;
}

public static byte ToBcdByte(this byte buf)
{
return (byte)Convert.ToInt32(buf.ToString(), 16);
}

/// <summary>
/// 经纬度
/// </summary>
/// <param name="latlng"></param>
/// <returns></returns>
public static double ToLatLng(this int latlng)
{
return Math.Round(latlng / Math.Pow(10, 6), 6);
}

public static void CopyTo(Span<byte> source, Span<byte> destination, int offset)
{
for (int i = 0; i < source.Length; i++)
{
destination[offset + i] = source[i];
}
}

/// <summary>
/// 字节数组转16进制字符串
/// </summary>
/// <param name="bytes"></param>
/// <param name="separator">默认 " "</param>
/// <returns></returns>
public static string ToHexString(this byte[] bytes, string separator = " ")
{
return string.Join(separator, bytes.Select(s => s.ToString("X2")));
}

/// <summary>
/// 16进制字符串转16进制数组
/// </summary>
/// <param name="hexString"></param>
/// <param name="separator"></param>
/// <returns></returns>
public static byte[] ToHexBytes(this string hexString, string separator = " ")
{
return hexString.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToByte(s, 16)).ToArray();
}

/// <summary>
/// 16进制字符串转16进制数组
/// </summary>
/// <param name="hexString"></param>
/// <returns></returns>
public static byte[] ToStr2HexBytes(this string hexString)
{
//byte[] buf = new byte[hexString.Length / 2];
//for (int i = 0; i < hexString.Length; i++)
//{
// if (i % 2 == 0)
// {
// buf[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16) ;
// }

//}
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;
//List<byte> bytes = new List<byte>();
//while (hexString.Length>0)
//{
// bytes.Add(Convert.ToByte(hexString.AsSpan(0, 2).ToString(), 16));
// hexString = hexString.Remove(0,2);
//}
//return Regex.Replace(hexString, @"(\w{2})", "$1 ").Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToByte(s, 16)).ToArray();
}
}
}

+ 155
- 0
src/JT809.Protocol/JT809Extensions/JT809EnumExtensions.cs ファイルの表示

@@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace JT809.Protocol.JT809Extensions
{
/// <summary>
/// 枚举扩展
/// </summary>
public static class JT809EnumExtensions
{
/// <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>
/// 转为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;
}
}
}
}

+ 50
- 0
src/JT809.Protocol/JT809Extensions/JT809FormatterExtensions.cs ファイルの表示

@@ -0,0 +1,50 @@
using JT809.Protocol.JT809Attributes;
using JT809.Protocol.JT809Enums;
using JT809.Protocol.JT809Exceptions;
using JT809.Protocol.JT809Formatters;
using System;
using System.Reflection;

namespace JT809.Protocol.JT809Extensions
{
public static class JT809FormatterExtensions
{
public static IJT809Formatter<T> GetFormatter<T>()
{
IJT809Formatter<T> formatter;
var attr = typeof(T).GetTypeInfo().GetCustomAttribute<JT809FormatterAttribute>();
if (attr == null)
{
throw new JT809Exception(JT809ErrorCode.GetFormatterError, $"该类{typeof(T).FullName}没有标记JT809FormatterAttribute");
}
if (attr.Arguments == null)
{
formatter = (IJT809Formatter<T>)Activator.CreateInstance(attr.FormatterType);
}
else
{
formatter = (IJT809Formatter<T>)Activator.CreateInstance(attr.FormatterType, attr.Arguments);
}
return formatter;
}

public static object GetFormatter(Type formatterType)
{
object formatter;
var attr = formatterType.GetTypeInfo().GetCustomAttribute<JT809FormatterAttribute>();
if (attr == null)
{
throw new JT809Exception(JT809ErrorCode.GetFormatterError,$"该类{formatterType.FullName}没有标记JT809FormatterAttribute");
}
if (attr.Arguments == null)
{
formatter = Activator.CreateInstance(attr.FormatterType);
}
else
{
formatter = Activator.CreateInstance(attr.FormatterType, attr.Arguments);
}
return formatter;
}
}
}

+ 87
- 0
src/JT809.Protocol/JT809Extensions/JT809FormatterResolverExtensions.cs ファイルの表示

@@ -0,0 +1,87 @@
using JT809.Protocol.JT809Formatters;
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace JT809.Protocol.JT809Extensions
{
/// <summary>
///
/// <para>ref http://adamsitnik.com/Span/#span-must-not-be-a-generic-type-argument </para>
/// <para>ref http://adamsitnik.com/Span/ </para>
/// <para>ref MessagePack.Formatters.DynamicObjectTypeFallbackFormatter </para>
/// </summary>
public static class JT809FormatterResolverExtensions
{
delegate int JT809SerializeMethod(object dynamicFormatter, IMemoryOwner<byte> memoryOwner, int offset, object value);

delegate dynamic JT809DeserializeMethod(object dynamicFormatter, ReadOnlySpan<byte> bytes, out int readSize);

static readonly ConcurrentDictionary<Type, (object Value, JT809SerializeMethod SerializeMethod)> jT809Serializers = new ConcurrentDictionary<Type, (object Value, JT809SerializeMethod SerializeMethod)>();

static readonly ConcurrentDictionary<Type, (object Value, JT809DeserializeMethod DeserializeMethod)> jT809Deserializes = new ConcurrentDictionary<Type, (object Value, JT809DeserializeMethod DeserializeMethod)>();

//T Deserialize(ReadOnlySpan<byte> bytes, out int readSize);
//int Serialize(IMemoryOwner<byte> memoryOwner, int offset, T value);

public static int JT809DynamicSerialize(object objFormatter, IMemoryOwner<byte> memoryOwner, int offset, dynamic value)
{
Type type = value.GetType();
var ti = type.GetTypeInfo();
(object Value, JT809SerializeMethod SerializeMethod) formatterAndDelegate;
if (!jT809Serializers.TryGetValue(type, out formatterAndDelegate))
{
var t = type;
{
var formatterType = typeof(IJT809Formatter<>).MakeGenericType(t);
var param0 = Expression.Parameter(typeof(object), "formatter");
var param1 = Expression.Parameter(typeof(IMemoryOwner<byte>), "memoryOwner");
var param2 = Expression.Parameter(typeof(int), "offset");
var param3 = Expression.Parameter(typeof(object), "value");
var serializeMethodInfo = formatterType.GetRuntimeMethod("Serialize", new[] { typeof(IMemoryOwner<byte>), 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<JT809SerializeMethod>(body, param0, param1, param2, param3).Compile();
formatterAndDelegate = (objFormatter, lambda);
}
jT809Serializers.TryAdd(t, formatterAndDelegate);
}
return formatterAndDelegate.SerializeMethod(formatterAndDelegate.Value, memoryOwner, offset, value);
}

public static dynamic JT809DynamicDeserialize(object objFormatter,ReadOnlySpan<byte> bytes, out int readSize)
{
var type = objFormatter.GetType();
(object Value, JT809DeserializeMethod DeserializeMethod) formatterAndDelegate;
if (!jT809Deserializes.TryGetValue(type, out formatterAndDelegate))
{
var t = type;
{
var formatterType = typeof(IJT809Formatter<>).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<JT809DeserializeMethod>(body, param0, param1, param2).Compile();
formatterAndDelegate = (objFormatter, lambda);
}
jT809Deserializes.TryAdd(t, formatterAndDelegate);
}
return formatterAndDelegate.DeserializeMethod(formatterAndDelegate.Value, bytes, out readSize);
}
}
}

+ 12
- 0
src/JT809.Protocol/JT809Formatters/IJT809FormatterOfT.cs ファイルの表示

@@ -0,0 +1,12 @@
using System;
using System.Buffers;

namespace JT809.Protocol.JT809Formatters
{
public interface IJT809Formatter<T>
{
T Deserialize(ReadOnlySpan<byte> bytes, out int readSize);

int Serialize(IMemoryOwner<byte> memoryOwner, int offset, T value);
}
}

+ 39
- 0
src/JT809.Protocol/JT809Formatters/JT809HeaderFormatter.cs ファイルの表示

@@ -0,0 +1,39 @@
using JT809.Protocol.JT809Enums;
using JT809.Protocol.JT809Extensions;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809Formatters
{
public class JT809HeaderFormatter : IJT809Formatter<JT809Header>
{
public JT809Header Deserialize(ReadOnlySpan<byte> bytes, out int readSize)
{
int offset = 0;
JT809Header jT809Header = new JT809Header();
jT809Header.MsgLength = JT809BinaryExtensions.ReadUInt32Little(bytes, ref offset);
jT809Header.MsgSN= JT809BinaryExtensions.ReadUInt32Little(bytes, ref offset);
jT809Header.MsgID = (JT809BusinessType)JT809BinaryExtensions.ReadUInt16Little(bytes, ref offset);
jT809Header.MsgGNSSCENTERID = JT809BinaryExtensions.ReadUInt32Little(bytes, ref offset);
jT809Header.Version = new JT809Header_Version(JT809BinaryExtensions.ReadBytesLittle(bytes, ref offset, JT809Header_Version.FixedByteLength));
jT809Header.EncryptFlag= (JT809Header_Encrypt)JT809BinaryExtensions.ReadByteLittle(bytes, ref offset);
jT809Header.EncryptKey= JT809BinaryExtensions.ReadUInt32Little(bytes, ref offset);
readSize = offset;
return jT809Header;
}

public int Serialize(IMemoryOwner<byte> memoryOwner, int offset, JT809Header value)
{
offset += JT809BinaryExtensions.WriteUInt32Little(memoryOwner, offset, value.MsgLength);
offset += JT809BinaryExtensions.WriteUInt32Little(memoryOwner, offset, value.MsgSN);
offset += JT809BinaryExtensions.WriteUInt16Little(memoryOwner, offset, (ushort)value.MsgID);
offset += JT809BinaryExtensions.WriteUInt32Little(memoryOwner, offset, value.MsgGNSSCENTERID);
offset += JT809BinaryExtensions.WriteBytesLittle(memoryOwner, offset, value.Version.Buffer);
offset += JT809BinaryExtensions.WriteByteLittle(memoryOwner, offset, (byte)value.EncryptFlag);
offset += JT809BinaryExtensions.WriteUInt32Little(memoryOwner, offset, value.EncryptKey);
return offset;
}
}
}

+ 33
- 0
src/JT809.Protocol/JT809Formatters/JT809MessageBodyFormatters/JT809_0x1001Formatter.cs ファイルの表示

@@ -0,0 +1,33 @@
using JT809.Protocol.JT809Extensions;
using JT809.Protocol.JT809MessageBody;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809Formatters.JT809MessageBodyFormatters
{
public class JT809_0x1001Formatter : IJT809Formatter<JT809_0x1001>
{
public JT809_0x1001 Deserialize(ReadOnlySpan<byte> bytes, out int readSize)
{
int offset = 0;
JT809_0x1001 jT809_0X1001 = new JT809_0x1001();
jT809_0X1001.UserId = JT809BinaryExtensions.ReadUInt32Little(bytes, ref offset);
jT809_0X1001.Password = JT809BinaryExtensions.ReadStringLittle(bytes, ref offset, 8);
jT809_0X1001.DownLinkIP = JT809BinaryExtensions.ReadStringLittle(bytes, ref offset, 32);
jT809_0X1001.DownLinkPort = JT809BinaryExtensions.ReadUInt16Little(bytes, ref offset);
readSize = offset;
return jT809_0X1001;
}

public int Serialize(IMemoryOwner<byte> memoryOwner, int offset, JT809_0x1001 value)
{
offset += JT809BinaryExtensions.WriteUInt32Little(memoryOwner, offset, value.UserId);
offset += JT809BinaryExtensions.WriteStringLittle(memoryOwner, offset, value.Password.PadRight(8,'\0'));
offset += JT809BinaryExtensions.WriteStringLittle(memoryOwner, offset, value.DownLinkIP.PadRight(32, '\0'));
offset += JT809BinaryExtensions.WriteUInt16Little(memoryOwner, offset, value.DownLinkPort);
return offset;
}
}
}

+ 209
- 0
src/JT809.Protocol/JT809Formatters/JT809PackageFormatter.cs ファイルの表示

@@ -0,0 +1,209 @@
using JT809.Protocol.JT809Attributes;
using JT809.Protocol.JT809Enums;
using JT809.Protocol.JT809Exceptions;
using JT809.Protocol.JT809Extensions;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809Formatters
{
public class JT809PackageFormatter : IJT809Formatter<JT809Package>
{
public JT809Package Deserialize(ReadOnlySpan<byte> bytes, out int readSize)
{
int offset = 0;
JT809Package jT809Package = new JT809Package();
// 转义还原——>验证校验码——>解析消息
// 1. 解码(转义还原)
ReadOnlySpan<byte> buffer = JT809DeEscape(bytes);
// 2. 验证校验码
// 2.1. 获取校验位索引
int checkIndex = buffer.Length - 3;
// 2.2. 获取校验码
int crcCodeOffset = 0;
jT809Package.CRCCode = JT809BinaryExtensions.ReadUInt16Little(buffer.Slice(checkIndex,2),ref crcCodeOffset);
// 2.3. 从消息头到校验码前一个字节
ushort checkCode = buffer.ToCRC16_CCITT(1, checkIndex);
// 2.4. 验证校验码
if (jT809Package.CRCCode != checkCode)
{
throw new JT809Exception(JT809ErrorCode.CRC16CheckInvalid,$"{jT809Package.CRCCode.ToString()}!={checkCode.ToString()}");
}
jT809Package.BeginFlag = JT809BinaryExtensions.ReadByteLittle(buffer, ref offset);
// 3.初始化消息头
try
{
jT809Package.Header = JT809FormatterExtensions.GetFormatter<JT809Header>().Deserialize(buffer.Slice(offset, JT809Header.FixedByteLength), out readSize);
}
catch (Exception ex)
{
throw new JT809Exception(JT809ErrorCode.HeaderParseError, $"offset>{offset.ToString()}", ex);
}
offset += readSize;
// 4.是否加密
switch (jT809Package.Header.EncryptFlag)
{
case JT809Header_Encrypt.None:
break;
case JT809Header_Encrypt.Common:
#warning 加密尚未实现
break;
}
// 5.数据体处理
// 5.1 判断是否有数据体(总长度-固定长度)> 0
if ((jT809Package.Header.MsgLength - JT809Package.FixedByteLength) > 0)
{
//JT809.Protocol.JT809Enums.JT809BusinessType 映射对应消息特性
JT809BodiesTypeAttribute jT809BodiesTypeAttribute = jT809Package.Header.MsgID.GetAttribute<JT809BodiesTypeAttribute>();
if (jT809BodiesTypeAttribute != null)
{
try
{
var a = buffer.Slice(offset);
var b = buffer.Slice(offset,checkIndex - offset);
//5.2 处理消息体
jT809Package.Bodies = JT809FormatterResolverExtensions.JT809DynamicDeserialize(JT809FormatterExtensions.GetFormatter(jT809BodiesTypeAttribute.JT809BodiesType), buffer.Slice(offset, checkIndex - offset), out readSize);
}
catch (Exception ex)
{
throw new JT809Exception(JT809ErrorCode.BodiesParseError,$"offset>{offset.ToString()}", ex);
}
}
}
jT809Package.EndFlag = buffer[buffer.Length - 1];
readSize = buffer.Length;
return jT809Package;
}

public int Serialize(IMemoryOwner<byte> memoryOwner, int offset, JT809Package value)
{
// 1. 先序列化数据体,根据数据体的长度赋值给头部,在序列化头部。
int messageBodyOffset = 0;
JT809BodiesTypeAttribute jT809BodiesTypeAttribute = value.Header.MsgID.GetAttribute<JT809BodiesTypeAttribute>();
if (jT809BodiesTypeAttribute != null)
{
if (value.Bodies != null)
{
// 1.1 处理数据体
messageBodyOffset = JT809FormatterResolverExtensions.JT809DynamicSerialize(JT809FormatterExtensions.GetFormatter(jT809BodiesTypeAttribute.JT809BodiesType), memoryOwner, messageBodyOffset, value.Bodies);
}
}
byte[] messageBodyData=null;
if (messageBodyOffset != 0)
{
// 1.2 数据加密
switch (value.Header.EncryptFlag)
{
case JT809Header_Encrypt.None:
break;
case JT809Header_Encrypt.Common:
#warning 加密尚未实现
break;
}
// 1.3 数据内容进行转义
messageBodyData = JT809Escape(memoryOwner.Memory.Slice(0, messageBodyOffset).Span);
}
// ------------------------------------开始组包
// 1.起始符
offset += JT809BinaryExtensions.WriteByteLittle(memoryOwner, offset, value.BeginFlag);
// 2.赋值头数据长度
if (messageBodyOffset != 0)
{
value.Header.MsgLength = (uint)(JT809Package.FixedByteLength + messageBodyData.Length);
}
else
{
value.Header.MsgLength = JT809Package.FixedByteLength;
}
// 2.1写入头部数据
offset = JT809FormatterExtensions.GetFormatter<JT809Header>().Serialize(memoryOwner, offset, value.Header);
if (messageBodyOffset != 0)
{
// 3. 写入数据体
JT809BinaryExtensions.CopyTo(messageBodyData, memoryOwner.Memory.Span, offset);
offset += messageBodyData.Length;
messageBodyData = null;
}
// 4.校验码
offset += JT809BinaryExtensions.WriteUInt16Little(memoryOwner, offset, memoryOwner.Memory.Span.ToCRC16_CCITT(1, offset));
// 5.终止符
offset += JT809BinaryExtensions.WriteByteLittle(memoryOwner, offset, value.EndFlag);
return offset;
}

private static ReadOnlySpan<byte> JT809DeEscape(ReadOnlySpan<byte> buffer)
{
List<byte> dataList = new List<byte>();
dataList.Add(buffer[0]);
for (int i = 1; i < buffer.Length - 1; i++)
{
byte first = buffer[i];
byte second = buffer[i + 1];
if (first == 0x5a && second == 0x01)
{
dataList.Add(0x5b);
i++;
}
else if (first == 0x5a && second == 0x02)
{
dataList.Add(0x5a);
i++;
}
else if (first == 0x5e && second == 0x01)
{
dataList.Add(0x5d);
i++;
}
else if (first == 0x5e && second == 0x02)
{
dataList.Add(0x5e);
i++;
}
else
{
dataList.Add(first);
}
}
dataList.Add(buffer[buffer.Length - 1]);
return dataList.ToArray();
}

private static byte[] JT809Escape(Span<byte> buf)
{
List<byte> dataList = new List<byte>();
dataList.Add(buf[0]);
for (int i = 1; i < buf.Length - 1; i++)
{
var item = buf[i];
switch (item)
{
case 0x5b:
dataList.Add(0x5a);
dataList.Add(0x01);
break;
case 0x5a:
dataList.Add(0x5a);
dataList.Add(0x02);
break;
case 0x5d:
dataList.Add(0x5e);
dataList.Add(0x01);
break;
case 0x5e:
dataList.Add(0x5e);
dataList.Add(0x02);
break;
default:
dataList.Add(item);
break;
}
}
dataList.Add(buf[buf.Length - 1]);
return dataList.ToArray();
}
}
}

+ 52
- 0
src/JT809.Protocol/JT809Header.cs ファイルの表示

@@ -0,0 +1,52 @@
using JT809.Protocol.JT809Attributes;
using JT809.Protocol.JT809Enums;
using JT809.Protocol.JT809Formatters;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol
{
[JT809Formatter(typeof(JT809HeaderFormatter))]
public class JT809Header
{
/// <summary>
/// 固定为22个字节长度
/// <para>MSG LENGTH + MSG_SN + MSG_ID + MSG_GNSSCENTERID + VERSION_FLAG + ENCRYPT_FLAG + ENCRYPT_KEY</para>
/// <para>4 + 4 + 2 + 4 + 3 + 1 + 4 = 22</para>
/// </summary>
public const int FixedByteLength = 22;
/// <summary>
/// 数据长度(包括头标识、数据头、数据体和尾标识)
/// <para>头标识 + 数据头 + 数据体 + 尾标识</para>
/// <para>1 + 22 + n + 1</para>
/// </summary>
public uint MsgLength { get; set; }
/// <summary>
/// 报文序列号 a
/// </summary>
public uint MsgSN { get; set; }
/// <summary>
/// 业务数据类型
/// </summary>
public JT809BusinessType MsgID { get; set; }
/// <summary>
/// 下级平台接入码,上级平台给下级平台分配唯一标识码。
/// </summary>
public uint MsgGNSSCENTERID { get; set; }
/// <summary>
/// 协议版本好标识,上下级平台之间采用的标准协议版
/// 编号;长度为 3 个字节来表示,0x01 0x02 0x0F 标识
/// 的版本号是 v1.2.15,以此类推。
/// </summary>
public JT809Header_Version Version { get; set; } = new JT809Header_Version();
/// <summary>
/// 报文加密标识位 b: 0 表示报文不加密,1 表示报文加密。
/// </summary>
public JT809Header_Encrypt EncryptFlag { get; set; } = JT809Header_Encrypt.None;
/// <summary>
/// 数据加密的密匙,长度为 4 个字节
/// </summary>
public uint EncryptKey { get; set; }
}
}

src/JT809.Protocol/Enums/EncryptOpitions.cs → src/JT809.Protocol/JT809Header_Encrypt.cs ファイルの表示

@@ -1,9 +1,9 @@
namespace JT809.Protocol.Enums
namespace JT809.Protocol
{
/// <summary>
/// 报文加密标识位 b: 0 表示报文不加密,1 表示报文加密。
/// </summary>
public enum EncryptOpitions : byte
public enum JT809Header_Encrypt:byte
{
None = 0X00,
Common = 0X01,

+ 62
- 0
src/JT809.Protocol/JT809Header_Version.cs ファイルの表示

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol
{
public class JT809Header_Version
{
public byte[] Buffer { get; } = new byte[3];
private const int MajorIndex = 0;
private const int MinorIndex = 1;
private const int BuildIndex = 2;
public const int FixedByteLength = 3;

public byte Major
{
get { return Buffer[MajorIndex]; }
private set { Buffer[MajorIndex] = value; }
}

public byte Minor
{
get { return Buffer[MinorIndex]; }
private set { Buffer[MinorIndex] = value; }
}

public byte Build
{
get { return Buffer[BuildIndex]; }
private set { Buffer[BuildIndex] = value; }
}

/// <summary>
/// 默认1.0.0版本
/// </summary>
public JT809Header_Version()
{
Major = 1;
Minor = 0;
Build = 0;
}

public JT809Header_Version(byte major, byte minor, byte buid)
{
Major = major;
Minor = minor;
Build = buid;
}

public JT809Header_Version(byte[] bytes)
{
Major = bytes[0];
Minor = bytes[1];
Build = bytes[2];
}

public override string ToString()
{
return $"{Major}.{Minor}.{Build}";
}
}
}

+ 34
- 0
src/JT809.Protocol/JT809MessageBody/JT809_0x1001.cs ファイルの表示

@@ -0,0 +1,34 @@
using JT809.Protocol.JT809Attributes;
using JT809.Protocol.JT809Formatters.JT809MessageBodyFormatters;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol.JT809MessageBody
{
/// <summary>
/// 主链路登录请求消息
/// </summary>
[JT809Formatter(typeof(JT809_0x1001Formatter))]
public class JT809_0x1001: JT809Bodies
{
/// <summary>
/// 用户名
/// </summary>
public uint UserId { get; set; }
/// <summary>
/// 密码
/// 8位
/// </summary>
public string Password { get; set; }
/// <summary>
/// 下级平台提供对应的从链路服务端 IP 地址
/// 32位
/// </summary>
public string DownLinkIP { get; set; }
/// <summary>
/// 下级平台提供对应的从链路服务器端口号
/// </summary>
public ushort DownLinkPort { get; set; }
}
}

+ 33
- 0
src/JT809.Protocol/JT809Package.cs ファイルの表示

@@ -0,0 +1,33 @@
using JT809.Protocol.JT809Attributes;
using JT809.Protocol.JT809Formatters;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol
{
[JT809Formatter(typeof(JT809PackageFormatter))]
public class JT809Package
{
public const byte BEGINFLAG = 0X5B;

public const byte ENDFLAG = 0X5D;

/// <summary>
/// 固定为26个字节长度
/// <para>Head flag + Message Header + CRC Code + End Flag</para>
/// <para>1 + 22 + 2 + 1 = 26</para>
/// </summary>
public const int FixedByteLength = 26;

public byte BeginFlag { get; set; } = BEGINFLAG;

public JT809Header Header { get; set; }

public JT809Bodies Bodies { get; set; }

public ushort CRCCode { get; set; }

public byte EndFlag { get; set; } = ENDFLAG;
}
}

+ 64
- 0
src/JT809.Protocol/JT809Serializer.cs ファイルの表示

@@ -0,0 +1,64 @@
using JT809.Protocol.JT809Enums;
using JT809.Protocol.JT809Exceptions;
using JT809.Protocol.JT809Extensions;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;

namespace JT809.Protocol
{
public static class JT809Serializer
{
public static byte[] Serialize(JT809Package jT809Package)
{
var formatter = JT809FormatterExtensions.GetFormatter<JT809Package>();
var pool = MemoryPool<byte>.Shared;
IMemoryOwner<byte> buffer = pool.Rent(4096);
try
{
var len = formatter.Serialize(buffer, 0, jT809Package);
return buffer.Memory.Slice(0, len).ToArray();
}
finally
{
// 源码:System.Memory.MemoryPool
// private static readonly MemoryPool<T> s_shared = new ArrayMemoryPool<T>();
// 单例内存池 不需要手动释放资源
buffer.Dispose();
}
}

public static JT809Package Deserialize(ReadOnlySpan<byte> bytes)
{
var formatter = JT809FormatterExtensions.GetFormatter<JT809Package>();
return formatter.Deserialize(bytes, out int readSize);
}

public static byte[] Serialize<T>(T obj)
{
var formatter = JT809FormatterExtensions.GetFormatter<T>();
var pool = MemoryPool<byte>.Shared;
IMemoryOwner<byte> buffer = pool.Rent(10240);
try
{
var len = formatter.Serialize(buffer, 0, obj);
return buffer.Memory.Slice(0, len).ToArray();
}
finally
{
// 源码:System.Memory.MemoryPool
// private static readonly MemoryPool<T> s_shared = new ArrayMemoryPool<T>();
// 单例内存池 不需要手动释放资源
buffer.Dispose();
}
}

public static T Deserialize<T>(ReadOnlySpan<byte> bytes)
{
var formatter = JT809FormatterExtensions.GetFormatter<T>();
int readSize;
return formatter.Deserialize(bytes, out readSize);
}
}
}

読み込み中…
キャンセル
保存