@@ -1,35 +1,47 @@ | |||
# JT809协议开发 | |||
### 瞎逼逼: | |||
## 瞎逼逼: | |||
  现在有了[JT808](https://github.com/SmallChi/GPSPlatform/blob/master/JT808.md)的基础,对JT809就只剩搬砖了。 | |||
> 该JT809协议是参考[MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp)一款二进制序列化器,站在巨人的肩膀上搬砖就是爽歪歪。 | |||
> 这GB的文档不得不说,太坑了。。。 | |||
## JT809协议消息对照表 | |||
### 链路管理类 | |||
|序号|消息ID|完成情况|消息体名称| | |||
|:------:|:------:|:------:|:------:| | |||
| 1 | 0x1001 | √ | 主链路登录请求消息 | | |||
| 2 | 0x1002 | √ | 主链路登录应答消息 | | |||
| 3 | 0x1003 | √ | 主链路注销请求消息 | | |||
| 4 | 0x1004 | √ | 主链路注销应答消息 | | |||
| 5 | 0x1005 | √ | 主链路连接保持请求消息 | | |||
| 6 | 0x1006 | √ | 主链路连接保持应答消息 | | |||
| 7 | 0x1007 | √ | 主链路断开通知消息 | | |||
| 8 | 0x1008 | √ | 下级平台主动关闭链路通知消息 | | |||
| 9 | 0x9001 | √ | 从链路连接请求消息 | | |||
| 10 | 0x9002 | √ | 从链路连接应答消息 | | |||
| 11 | 0x9003 | √ | 从链路注销请求消息 | | |||
| 12 | 0x9004 | √ | 从链路注销应答消息 | | |||
| 13 | 0x9005 | √ | 从链路连接保持请求消息 | | |||
| 14 | 0x9006 | √ | 从链路连接保持应答消息 | | |||
| 15 | 0x9007 | √ | 从链路断开通知消息 | | |||
| 16 | 0x9008 | √ | 上级平台主动关闭链路通知消息 | | |||
| 17 | 0x9101 | √ | 接收定位信息数量通知消息 | | |||
| 1 | 0x1001 | √ | 主链路登录请求消息 | | |||
| 2 | 0x1002 | √ | 主链路登录应答消息 | | |||
| 3 | 0x1003 | √ | 主链路注销请求消息 | | |||
| 4 | 0x1004 | √ | 主链路注销应答消息 | | |||
| 5 | 0x1005 | √ | 主链路连接保持请求消息 | | |||
| 6 | 0x1006 | √ | 主链路连接保持应答消息 | | |||
| 7 | 0x1007 | √ | 主链路断开通知消息 | | |||
| 8 | 0x1008 | √ | 下级平台主动关闭链路通知消息 | | |||
| 9 | 0x9001 | √ | 从链路连接请求消息 | | |||
| 10 | 0x9002 | √ | 从链路连接应答消息 | | |||
| 11 | 0x9003 | √ | 从链路注销请求消息 | | |||
| 12 | 0x9004 | √ | 从链路注销应答消息 | | |||
| 13 | 0x9005 | √ | 从链路连接保持请求消息 | | |||
| 14 | 0x9006 | √ | 从链路连接保持应答消息 | | |||
| 15 | 0x9007 | √ | 从链路断开通知消息 | | |||
| 16 | 0x9008 | √ | 上级平台主动关闭链路通知消息 | | |||
### 信息统计类 | |||
|序号|消息ID|完成情况|消息体名称| | |||
|:------:|:------:|:------:|:------:| | |||
| 1 | 0x9101 | √ |接收定位信息数量通知消息 | | |||
### 车辆动态信息交换 | |||
#### 主链路动态信息交换消息 | |||
|序号|消息ID|完成情况|消息体名称| | |||
|:------:|:------:|:------:|:------:| | |||
| 1 | 0x1200 | √ | 主链路动态信息交换消息 | | |||
| 2 | 0x1201 | √ | 上传车辆注册信息 | |
@@ -0,0 +1,54 @@ | |||
using JT809.Protocol; | |||
using JT809.Protocol.JT809Extensions; | |||
using JT809.Protocol.JT809MessageBody; | |||
using JT809.Protocol.JT809SubMessageBody; | |||
using JT809.Protocol.JT809Exceptions; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Xunit; | |||
namespace JT809.Protocol.Test.JT809MessageBody | |||
{ | |||
public class JT809_0x1200Test | |||
{ | |||
[Fact] | |||
public void Test1() | |||
{ | |||
JT809_0x1200 jT809_0X1200 = new JT809_0x1200(); | |||
jT809_0X1200.VehicleNo= "粤A12345"; | |||
jT809_0X1200.VehicleColor = JT809Enums.JT809VehicleColorType.蓝色; | |||
jT809_0X1200.SubBusinessType = JT809Enums.JT809SubBusinessType.UP_EXG_MSG_REGISTER; | |||
jT809_0X1200.DataLength = 61; | |||
JT809_0x1200_0x1201 jT809_0X1200_0X1201 = new JT809_0x1200_0x1201 | |||
{ | |||
PlateformId = "1111111111", | |||
ProducerId = "1111111111", | |||
TerminalId = "11111AA", | |||
TerminalModelType = "11111111", | |||
TerminalSimCode = "222222222222" | |||
}; | |||
jT809_0X1200.JT809SubBodies = jT809_0X1200_0X1201; | |||
var hex = JT809Serializer.Serialize(jT809_0X1200).ToHexString(); | |||
//"D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 01 12 01 00 00 00 3D 00 00 00 00 00 00 00 42 3A 35 C7 00 00 00 00 00 00 00 42 3A 35 C7 31 31 31 31 31 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 31 31 31 31 31 41 41 32 32 32 32 32 32 32 32 32 32 32 32" | |||
//"D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 01 12 01 00 00 00 3D 00 00 00 00 00 00 00 42 3A 35 C7 00 00 00 00 00 00 00 42 3A 35 C7 31 31 31 31 31 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 31 31 31 31 31 61 61 32 32 32 32 32 32 32 32 32 32 32 32" | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
var bytes = "D4 C1 41 31 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 00 01 12 01 00 00 00 3D 00 00 00 00 00 00 00 42 3A 35 C7 00 00 00 00 00 00 00 42 3A 35 C7 31 31 31 31 31 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 31 31 31 31 31 41 41 32 32 32 32 32 32 32 32 32 32 32 32".ToHexBytes(); | |||
JT809_0x1200 jT809_0X9001 = JT809Serializer.Deserialize<JT809_0x1200>(bytes); | |||
Assert.Equal("粤A12345", jT809_0X9001.VehicleNo); | |||
Assert.Equal(JT809Enums.JT809VehicleColorType.蓝色, jT809_0X9001.VehicleColor); | |||
Assert.Equal(JT809Enums.JT809SubBusinessType.UP_EXG_MSG_REGISTER, jT809_0X9001.SubBusinessType); | |||
Assert.Equal((ushort)61, jT809_0X9001.DataLength); | |||
JT809_0x1200_0x1201 jT809_0X1200_0X1201 = jT809_0X9001.JT809SubBodies as JT809_0x1200_0x1201; | |||
Assert.Equal("1111111111", jT809_0X1200_0X1201.PlateformId); | |||
Assert.Equal("1111111111", jT809_0X1200_0X1201.ProducerId); | |||
Assert.Equal("11111AA", jT809_0X1200_0X1201.TerminalId); | |||
Assert.Equal("11111111", jT809_0X1200_0X1201.TerminalModelType); | |||
Assert.Equal("222222222222", jT809_0X1200_0X1201.TerminalSimCode); | |||
} | |||
} | |||
} |
@@ -0,0 +1,42 @@ | |||
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; | |||
using JT809.Protocol.JT809SubMessageBody; | |||
namespace JT809.Protocol.Test.JT809SubMessageBody | |||
{ | |||
public class JT809_0x1200_0x1201Test | |||
{ | |||
[Fact] | |||
public void Test1() | |||
{ | |||
JT809_0x1200_0x1201 jT809_0X1200_0X1201 = new JT809_0x1200_0x1201 | |||
{ | |||
PlateformId= "1111111111", | |||
ProducerId= "1111111111", | |||
TerminalId= "11111AA", | |||
TerminalModelType= "11111111", | |||
TerminalSimCode= "222222222222" | |||
}; | |||
var hex = JT809Serializer.Serialize(jT809_0X1200_0X1201).ToHexString(); | |||
//"00 00 00 00 00 00 00 42 3A 35 C7 00 00 00 00 00 00 00 42 3A 35 C7 31 31 31 31 31 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 31 31 31 31 31 41 41 32 32 32 32 32 32 32 32 32 32 32 32" | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
var bytes = "00 00 00 00 00 00 00 42 3A 35 C7 00 00 00 00 00 00 00 42 3A 35 C7 31 31 31 31 31 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 31 31 31 31 31 41 41 32 32 32 32 32 32 32 32 32 32 32 32".ToHexBytes(); | |||
JT809_0x1200_0x1201 jT809_0X1200_0X1201 = JT809Serializer.Deserialize<JT809_0x1200_0x1201>(bytes); | |||
Assert.Equal("1111111111", jT809_0X1200_0X1201.PlateformId); | |||
Assert.Equal("1111111111", jT809_0X1200_0X1201.ProducerId); | |||
Assert.Equal("11111AA", jT809_0X1200_0X1201.TerminalId); | |||
Assert.Equal("11111111", jT809_0X1200_0X1201.TerminalModelType); | |||
Assert.Equal("222222222222", jT809_0X1200_0X1201.TerminalSimCode); | |||
} | |||
} | |||
} |
@@ -37,6 +37,7 @@ | |||
<Compile Include="JT809Enums\JT809ErrorCode.cs" /> | |||
<Compile Include="JT809Enums\JT809BusinessType.cs" /> | |||
<Compile Include="JT809Enums\JT809SubBusinessType.cs" /> | |||
<Compile Include="JT809Enums\JT809VehicleColorType.cs" /> | |||
<Compile Include="JT809Enums\JT809_0x1002_Result.cs" /> | |||
<Compile Include="JT809Enums\JT809_0x1007_ErrorCode.cs" /> | |||
<Compile Include="JT809Enums\JT809_0x9007_ReasonCode.cs" /> | |||
@@ -1,40 +0,0 @@ | |||
using JT809.Protocol.ProtocolPacket; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.Configs | |||
{ | |||
public class JT809Config | |||
{ | |||
public JT809Config() { } | |||
public JT809Config(uint sessionId, JT809Version jt809Version) | |||
{ | |||
SessionId = sessionId; | |||
JT809Version = jt809Version; | |||
} | |||
public JT809Config(uint sessionId, JT809Version jt809Version, JT809EncryptConfig encryptConfig) | |||
{ | |||
SessionId = sessionId; | |||
JT809Version = jt809Version; | |||
JT809EncryptConfig = encryptConfig; | |||
} | |||
/// <summary> | |||
/// 下级平台接入码,上级平台给下级平台分配唯一标识码。 | |||
/// </summary> | |||
public uint SessionId { get; set; } | |||
/// <summary> | |||
/// 加密配置 | |||
/// </summary> | |||
public JT809EncryptConfig JT809EncryptConfig { get; set; } | |||
/// <summary> | |||
/// 版本号 | |||
/// </summary> | |||
public JT809Version JT809Version { get; set; } = new JT809Version(); | |||
} | |||
} |
@@ -123,6 +123,7 @@ namespace JT809.Protocol.JT809Enums | |||
///主链路动态信息交换消息 | |||
///</summary> | |||
[Description("主链路动态信息交换消息")] | |||
[JT809BodiesType(typeof(JT809_0x1200))] | |||
UP_EXG_MSG = 0x1200, | |||
///<summary> | |||
///从链路动态信息交换消息 | |||
@@ -12,6 +12,8 @@ namespace JT809.Protocol.JT809Enums | |||
SerializeError=1004, | |||
DeserializeError=1005, | |||
HeaderParseError=1006, | |||
BodiesParseError=1007 | |||
BodiesParseError=1007, | |||
SubBodiesParseError = 1008, | |||
GetAttributeError=1009 | |||
} | |||
} |
@@ -1,4 +1,6 @@ | |||
using System.ComponentModel; | |||
using JT809.Protocol.JT809Attributes; | |||
using JT809.Protocol.JT809SubMessageBody; | |||
using System.ComponentModel; | |||
namespace JT809.Protocol.JT809Enums | |||
{ | |||
@@ -12,6 +14,7 @@ namespace JT809.Protocol.JT809Enums | |||
/// 上传车辆注册信息 | |||
/// </summary> | |||
[Description("上传车辆注册信息")] | |||
[JT809BodiesType(typeof(JT809_0x1200_0x1201))] | |||
UP_EXG_MSG_REGISTER = 0x1201, | |||
///<summary> | |||
///实时上传车辆定位信息 | |||
@@ -0,0 +1,18 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.JT809Enums | |||
{ | |||
/// <summary> | |||
/// 车辆颜色,按照 JT/T415-2006 中5.4.12 的规定 | |||
/// </summary> | |||
public enum JT809VehicleColorType:byte | |||
{ | |||
蓝色=0x01, | |||
黄色=0x02, | |||
黑色 = 0x03, | |||
白色 = 0x04, | |||
其他 =0x09, | |||
} | |||
} |
@@ -58,7 +58,7 @@ namespace JT809.Protocol.JT809Extensions | |||
public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset, int len) | |||
{ | |||
string value = encoding.GetString(read.Slice(offset, len).ToArray()); | |||
offset += value.Length; | |||
offset += len; | |||
return value.Trim('\0'); | |||
} | |||
@@ -69,11 +69,6 @@ namespace JT809.Protocol.JT809Extensions | |||
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; | |||
@@ -164,15 +159,42 @@ namespace JT809.Protocol.JT809Extensions | |||
return temp.ToArray(); | |||
} | |||
public static int WriteLittle(ref byte[] write, int offset, DateTime date) | |||
/// <summary> | |||
/// 数字编码 大端模式、高位在前 | |||
/// </summary> | |||
/// <param name="read"></param> | |||
/// <param name="offset"></param> | |||
/// <param name="len"></param> | |||
/// <returns></returns> | |||
public static string ReadBigNumberLittle(ReadOnlySpan<byte> read, ref int offset, int len) | |||
{ | |||
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; | |||
ulong result = 0; | |||
for (int i = 0; i < len; i++) | |||
{ | |||
ulong currentData = (ulong)read[offset+i] << (8 * (len - i - 1)); | |||
result += currentData; | |||
} | |||
offset += len; | |||
return result.ToString(); | |||
} | |||
/// <summary> | |||
/// 数字编码 小端模式、低位在前 | |||
/// </summary> | |||
/// <param name="read"></param> | |||
/// <param name="offset"></param> | |||
/// <param name="len"></param> | |||
/// <returns></returns> | |||
public static string ReadLowNumberLittle(ReadOnlySpan<byte> read, ref int offset, int len) | |||
{ | |||
ulong result = 0; | |||
for (int i = 0; i < len; i++) | |||
{ | |||
ulong currentData = (ulong)read[offset+i] << (8 * i); | |||
result += currentData; | |||
} | |||
offset += len; | |||
return result.ToString(); | |||
} | |||
public static int WriteDateTime6Little(IMemoryOwner<byte> memoryOwner, int offset, DateTime date) | |||
@@ -186,15 +208,6 @@ namespace JT809.Protocol.JT809Extensions | |||
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); | |||
@@ -204,15 +217,6 @@ namespace JT809.Protocol.JT809Extensions | |||
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); | |||
@@ -244,13 +248,6 @@ namespace JT809.Protocol.JT809Extensions | |||
return 8; | |||
} | |||
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); | |||
@@ -258,12 +255,6 @@ namespace JT809.Protocol.JT809Extensions | |||
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; | |||
@@ -276,24 +267,32 @@ namespace JT809.Protocol.JT809Extensions | |||
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) | |||
public static int WriteStringLittle(IMemoryOwner<byte> memoryOwner, int offset, string data) | |||
{ | |||
byte[] codeBytes = encoding.GetBytes(data); | |||
Buffer.BlockCopy(codeBytes, 0, write, offset, codeBytes.Length); | |||
CopyTo(codeBytes, memoryOwner.Memory.Span, offset); | |||
return codeBytes.Length; | |||
} | |||
public static int WriteStringLittle(IMemoryOwner<byte> memoryOwner, int offset, string data) | |||
public static int WriteStringLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len) | |||
{ | |||
byte[] codeBytes = encoding.GetBytes(data); | |||
CopyTo(codeBytes, memoryOwner.Memory.Span, offset); | |||
return codeBytes.Length; | |||
byte[] bytes = null; | |||
if (string.IsNullOrEmpty(data)) | |||
{ | |||
bytes = new byte[0]; | |||
} | |||
else | |||
{ | |||
bytes = encoding.GetBytes(data); | |||
} | |||
byte[] rBytes = new byte[len]; | |||
for (int i = 0; i < bytes.Length; i++) | |||
{ | |||
if (i >= len) break; | |||
rBytes[i] = bytes[i]; | |||
} | |||
CopyTo(rBytes, memoryOwner.Memory.Span, offset); | |||
return rBytes.Length; | |||
} | |||
public static int WriteStringPadLeftLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len) | |||
@@ -332,6 +331,44 @@ namespace JT809.Protocol.JT809Extensions | |||
return digit; | |||
} | |||
/// <summary> | |||
/// 数字编码 大端模式、高位在前 | |||
/// </summary> | |||
/// <param name="memoryOwner"></param> | |||
/// <param name="offset"></param> | |||
/// <param name="data"></param> | |||
/// <param name="len"></param> | |||
/// <returns></returns> | |||
public static int WriteBigNumberLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len) | |||
{ | |||
ulong number = string.IsNullOrEmpty(data) ? 0 : (ulong)double.Parse(data); | |||
for (int i = len - 1; i >= 0; i--) | |||
{ | |||
memoryOwner.Memory.Span[offset+i] = (byte)(number & 0xFF); //取低8位 | |||
number = number >> 8; | |||
} | |||
return len; | |||
} | |||
/// <summary> | |||
/// 数字编码 小端模式、低位在前 | |||
/// </summary> | |||
/// <param name="memoryOwner"></param> | |||
/// <param name="offset"></param> | |||
/// <param name="data"></param> | |||
/// <param name="len"></param> | |||
/// <returns></returns> | |||
public static int WriteLowNumberLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len) | |||
{ | |||
ulong number = string.IsNullOrEmpty(data) ? 0 : (ulong)double.Parse(data); | |||
for (int i = 0; i < len; i++) | |||
{ | |||
memoryOwner.Memory.Span[offset + i] = (byte)(number & 0xFF); //取低8位 | |||
number = number >> 8; | |||
} | |||
return len; | |||
} | |||
public static IEnumerable<byte> ToBytes(this string data, Encoding coding) | |||
{ | |||
return coding.GetBytes(data); | |||
@@ -0,0 +1,64 @@ | |||
using JT809.Protocol.JT809Attributes; | |||
using JT809.Protocol.JT809Enums; | |||
using JT809.Protocol.JT809Exceptions; | |||
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_0x1200Formatter : IJT809Formatter<JT809_0x1200> | |||
{ | |||
public JT809_0x1200 Deserialize(ReadOnlySpan<byte> bytes, out int readSize) | |||
{ | |||
int offset = 0; | |||
JT809_0x1200 jT809_0X1200 = new JT809_0x1200(); | |||
jT809_0X1200.VehicleNo =JT809BinaryExtensions.ReadStringLittle(bytes, ref offset,21); | |||
jT809_0X1200.VehicleColor = (JT809VehicleColorType)JT809BinaryExtensions.ReadByteLittle(bytes, ref offset); | |||
jT809_0X1200.SubBusinessType = (JT809SubBusinessType)JT809BinaryExtensions.ReadUInt16Little(bytes, ref offset); | |||
jT809_0X1200.DataLength = JT809BinaryExtensions.ReadUInt32Little(bytes, ref offset); | |||
//JT809.Protocol.JT809Enums.JT809BusinessType 映射对应消息特性 | |||
JT809BodiesTypeAttribute jT809SubBodiesTypeAttribute = jT809_0X1200.SubBusinessType.GetAttribute<JT809BodiesTypeAttribute>(); | |||
if (jT809SubBodiesTypeAttribute == null) | |||
{ | |||
throw new JT809Exception(JT809ErrorCode.GetAttributeError, $"JT809BodiesTypeAttribute Not Found>{jT809_0X1200.SubBusinessType.ToString()}"); | |||
} | |||
try | |||
{ | |||
jT809_0X1200.JT809SubBodies = JT809FormatterResolverExtensions.JT809DynamicDeserialize(JT809FormatterExtensions.GetFormatter(jT809SubBodiesTypeAttribute.JT809BodiesType), bytes.Slice(offset, (int)jT809_0X1200.DataLength), out readSize); | |||
} | |||
catch | |||
{ | |||
throw new JT809Exception(JT809ErrorCode.SubBodiesParseError, $"SubBusinessType>{jT809_0X1200.SubBusinessType.ToString()}"); | |||
} | |||
readSize = offset; | |||
return jT809_0X1200; | |||
} | |||
public int Serialize(IMemoryOwner<byte> memoryOwner, int offset, JT809_0x1200 value) | |||
{ | |||
offset += JT809BinaryExtensions.WriteStringLittle(memoryOwner, offset, value.VehicleNo, 21); | |||
offset += JT809BinaryExtensions.WriteByteLittle(memoryOwner, offset, (byte)value.VehicleColor); | |||
offset += JT809BinaryExtensions.WriteUInt16Little(memoryOwner, offset, (ushort)value.SubBusinessType); | |||
offset += JT809BinaryExtensions.WriteUInt32Little(memoryOwner, offset, value.DataLength); | |||
//JT809.Protocol.JT809Enums.JT809BusinessType 映射对应消息特性 | |||
JT809BodiesTypeAttribute jT809SubBodiesTypeAttribute = value.SubBusinessType.GetAttribute<JT809BodiesTypeAttribute>(); | |||
if (jT809SubBodiesTypeAttribute == null) | |||
{ | |||
throw new JT809Exception(JT809ErrorCode.GetAttributeError, $"JT809BodiesTypeAttribute Not Found>{value.SubBusinessType.ToString()}"); | |||
} | |||
try | |||
{ | |||
offset = JT809FormatterResolverExtensions.JT809DynamicSerialize(JT809FormatterExtensions.GetFormatter(jT809SubBodiesTypeAttribute.JT809BodiesType), memoryOwner, offset, value.JT809SubBodies); | |||
} | |||
catch | |||
{ | |||
throw new JT809Exception(JT809ErrorCode.SubBodiesParseError, $"SubBusinessType>{value.SubBusinessType.ToString()}"); | |||
} | |||
return offset; | |||
} | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
using JT809.Protocol.JT809Extensions; | |||
using JT809.Protocol.JT809SubMessageBody; | |||
using JT809.Protocol.JT809Enums; | |||
using System; | |||
using System.Buffers; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.JT809Formatters.JT809SubMessageBodyFormatters | |||
{ | |||
public class JT809_0x1200_0x1201Formatter : IJT809Formatter<JT809_0x1200_0x1201> | |||
{ | |||
public JT809_0x1200_0x1201 Deserialize(ReadOnlySpan<byte> bytes, out int readSize) | |||
{ | |||
int offset = 0; | |||
JT809_0x1200_0x1201 jT809_0X1200_0X1201 = new JT809_0x1200_0x1201(); | |||
jT809_0X1200_0X1201.PlateformId= JT809BinaryExtensions.ReadBigNumberLittle(bytes, ref offset, 11); | |||
jT809_0X1200_0X1201.ProducerId = JT809BinaryExtensions.ReadBigNumberLittle(bytes, ref offset, 11); | |||
jT809_0X1200_0X1201.TerminalModelType = JT809BinaryExtensions.ReadStringLittle(bytes, ref offset, 20); | |||
jT809_0X1200_0X1201.TerminalId = JT809BinaryExtensions.ReadStringLittle(bytes, ref offset, 7); | |||
jT809_0X1200_0X1201.TerminalId = jT809_0X1200_0X1201.TerminalId.ToUpper(); | |||
jT809_0X1200_0X1201.TerminalSimCode = JT809BinaryExtensions.ReadStringLittle(bytes, ref offset, 12); | |||
readSize = offset; | |||
return jT809_0X1200_0X1201; | |||
} | |||
public int Serialize(IMemoryOwner<byte> memoryOwner, int offset, JT809_0x1200_0x1201 value) | |||
{ | |||
offset += JT809BinaryExtensions.WriteBigNumberLittle(memoryOwner, offset, value.PlateformId,11); | |||
offset += JT809BinaryExtensions.WriteBigNumberLittle(memoryOwner, offset, value.ProducerId, 11); | |||
offset += JT809BinaryExtensions.WriteStringPadRightLittle(memoryOwner, offset, value.TerminalModelType, 20); | |||
offset += JT809BinaryExtensions.WriteStringPadRightLittle(memoryOwner, offset, value.TerminalId.ToUpper(), 7); | |||
offset += JT809BinaryExtensions.WriteStringPadRightLittle(memoryOwner, offset, value.TerminalSimCode, 12); | |||
return offset; | |||
} | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
using JT809.Protocol.JT809Attributes; | |||
using JT809.Protocol.JT809Enums; | |||
using JT809.Protocol.JT809Formatters.JT809MessageBodyFormatters; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.JT809MessageBody | |||
{ | |||
/// <summary> | |||
/// 主链路车辆动态信息交换业务 | |||
/// <para>链路类型:主链路</para> | |||
/// <para>消息方向:下级平台往上级平台</para> | |||
/// <para>业务数据类型标识:UP_EXG_MSG</para> | |||
/// <para>描述:下级平台向上级平台发送车辆动态信息交换业务数据包</para> | |||
/// </summary> | |||
[JT809Formatter(typeof(JT809_0x1200Formatter))] | |||
public class JT809_0x1200:JT809Bodies | |||
{ | |||
/// <summary> | |||
/// 车牌号 | |||
/// </summary> | |||
public string VehicleNo { get; set; } | |||
/// <summary> | |||
/// 车辆颜色 | |||
/// </summary> | |||
public JT809VehicleColorType VehicleColor { get; set; } | |||
/// <summary> | |||
/// 子业务类型标识 | |||
/// </summary> | |||
public JT809SubBusinessType SubBusinessType { get; set; } | |||
/// <summary> | |||
/// 后续数据长度 | |||
/// </summary> | |||
public uint DataLength { get; set; } | |||
/// <summary> | |||
/// 数据部分 | |||
/// </summary> | |||
public byte[] Data { get; set; } | |||
/// <summary> | |||
/// 子业务数据体 | |||
/// </summary> | |||
public JT809SubBodies JT809SubBodies { get; set; } | |||
} | |||
} |
@@ -39,7 +39,7 @@ namespace JT809.Protocol | |||
{ | |||
var formatter = JT809FormatterExtensions.GetFormatter<T>(); | |||
var pool = MemoryPool<byte>.Shared; | |||
IMemoryOwner<byte> buffer = pool.Rent(10240); | |||
IMemoryOwner<byte> buffer = pool.Rent(4096); | |||
try | |||
{ | |||
var len = formatter.Serialize(buffer, 0, obj); | |||
@@ -0,0 +1,15 @@ | |||
using JT809.Protocol.JT809Enums; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol | |||
{ | |||
/// <summary> | |||
/// 子业务数据体 | |||
/// </summary> | |||
public abstract class JT809SubBodies | |||
{ | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
using JT809.Protocol.JT809Attributes; | |||
using JT809.Protocol.JT809Enums; | |||
using JT809.Protocol.JT809Formatters.JT809SubMessageBodyFormatters; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.JT809SubMessageBody | |||
{ | |||
/// <summary> | |||
/// 上传车辆注册信息消息 | |||
/// <para>子业务类型标识:UP_ EXG_ MSG_ REGISTER</para> | |||
/// <para>描述:监控平台收到车载终端鉴权信息后,启动本命令向上级监管平台上传该车辆注册信息.各级监管平台再逐级向上级平台上传该信息</para> | |||
/// <para>本条消息服务端无需应答</para> | |||
/// </summary> | |||
[JT809Formatter(typeof(JT809_0x1200_0x1201Formatter))] | |||
public class JT809_0x1200_0x1201:JT809SubBodies | |||
{ | |||
/// <summary> | |||
/// 平台唯一编码 | |||
/// </summary> | |||
public string PlateformId { get; set; } | |||
/// <summary> | |||
/// 车载终端厂商唯一编码 | |||
/// </summary> | |||
public string ProducerId { get; set; } | |||
/// <summary> | |||
/// 车载终端型号,不是 8 位时以“\0”终结 | |||
/// </summary> | |||
public string TerminalModelType { get; set; } | |||
/// <summary> | |||
/// 车载终端编号,大写字母和数字组成 | |||
/// </summary> | |||
public string TerminalId { get; set; } | |||
/// <summary> | |||
/// 车载终端 SIM 卡电话号码。号码不是12 位,则在前补充数字 0. | |||
/// </summary> | |||
public string TerminalSimCode { get; set; } | |||
} | |||
} |
@@ -1,47 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Text; | |||
namespace JT809.Protocol.ProtocolPacket.Bodies.Master | |||
{ | |||
public sealed class Body_UP_CONNECT_REQ : MessageBody | |||
{ | |||
public uint UserId { get; private set; } | |||
public byte[] Password { get; private set; } | |||
public byte[] DownLinkIp { get; private set; } | |||
public ushort DownLinkPort { get; private set; } | |||
public Body_UP_CONNECT_REQ(byte[] buffer) : base(buffer) { } | |||
public Body_UP_CONNECT_REQ(uint userId, byte[] password, byte[] downLinkIp, ushort downLinkPort) | |||
: base(userId, password, downLinkIp, downLinkPort) { } | |||
protected override void InitializeProperties(object[] properties, int startIndex) | |||
{ | |||
UserId = (uint)properties[startIndex++]; | |||
Password = SetMatchBytes((byte[])properties[startIndex++], 8); | |||
DownLinkIp = SetMatchBytes((byte[])properties[startIndex++], 32); | |||
DownLinkPort = (ushort)properties[startIndex++]; | |||
} | |||
protected override void OnInitializePropertiesFromReadBuffer(BinaryReader reader) | |||
{ | |||
UserId = reader.ReadUInt32Little(); | |||
Password = reader.ReadBytes(8); | |||
DownLinkIp = reader.ReadBytes(32); | |||
DownLinkPort = reader.ReadUInt16Little(); | |||
} | |||
protected override void OnWriteToBuffer(BinaryWriter writer) | |||
{ | |||
writer.WriteLittle(UserId); | |||
writer.WriteLittle(Password); | |||
writer.WriteLittle(DownLinkIp); | |||
writer.WriteLittle(DownLinkPort); | |||
} | |||
} | |||
} |
@@ -1,65 +0,0 @@ | |||
using System; | |||
using System.IO; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
public abstract class BufferedEntityBase : IBuffered, IBuffer | |||
{ | |||
public byte[] Buffer { get; protected set; } | |||
public virtual byte[] ToBuffer() | |||
{ | |||
using (var stream = new MemoryStream()) | |||
{ | |||
var writer = new BinaryWriter(stream); | |||
OnWriteToBuffer(writer); | |||
var reader = new BinaryReader(stream); | |||
stream.Seek(0, SeekOrigin.Begin); | |||
Buffer = reader.ReadBytes((int)stream.Length);//stream.GetBuffer(); | |||
stream.Close(); | |||
} | |||
return Buffer; | |||
} | |||
protected BufferedEntityBase(params object[] properties) | |||
{ | |||
InitializeProperties(properties, 0); | |||
ToBuffer(); | |||
} | |||
protected BufferedEntityBase(byte[] buffer) | |||
{ | |||
Buffer = buffer; | |||
InitializePropertiesFromBuffer(); | |||
} | |||
public static byte[] SetMatchBytes(byte[] bufferIn, int lengthMatch, byte mask = 0X00) | |||
{ | |||
if (bufferIn.Length != lengthMatch) | |||
{ | |||
var tempBuffer = new byte[lengthMatch]; | |||
Array.ForEach(tempBuffer, b => b = mask);//TODO : Maybe mask error | |||
var copyLength = bufferIn.Length > lengthMatch ? lengthMatch : bufferIn.Length; | |||
Array.Copy(bufferIn, 0, tempBuffer, 0, copyLength); | |||
return tempBuffer; | |||
} | |||
return bufferIn; | |||
} | |||
protected abstract void InitializeProperties(object[] properties, int startIndex); | |||
protected abstract void OnInitializePropertiesFromReadBuffer(BinaryReader reader); | |||
protected virtual void InitializePropertiesFromBuffer() | |||
{ | |||
using (var stream = new MemoryStream(Buffer)) | |||
{ | |||
var reader = new BinaryReader(stream); | |||
OnInitializePropertiesFromReadBuffer(reader); | |||
stream.Close(); | |||
} | |||
} | |||
protected abstract void OnWriteToBuffer(BinaryWriter writer); | |||
} | |||
} |
@@ -1,99 +0,0 @@ | |||
using System; | |||
using System.IO; | |||
using System.Linq; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
public static class BinaryExtensions | |||
{ | |||
public static void WriteLittle(this BinaryWriter writer, ulong value) | |||
{ | |||
writer.Write((byte)(value >> 56)); | |||
writer.Write((byte)(value >> 48)); | |||
writer.Write((byte)(value >> 40)); | |||
writer.Write((byte)(value >> 32)); | |||
writer.Write((byte)(value >> 24)); | |||
writer.Write((byte)(value >> 16)); | |||
writer.Write((byte)(value >> 8)); | |||
writer.Write((byte)(value)); | |||
} | |||
public static void WriteLittle(this BinaryWriter writer, uint value) | |||
{ | |||
writer.Write((byte)(value >> 24)); | |||
writer.Write((byte)(value >> 16)); | |||
writer.Write((byte)(value >> 8)); | |||
writer.Write((byte)(value)); | |||
} | |||
public static void WriteLittle(this BinaryWriter writer, int value) | |||
{ | |||
writer.Write((byte)(value >> 24)); | |||
writer.Write((byte)(value >> 16)); | |||
writer.Write((byte)(value >> 8)); | |||
writer.Write((byte)(value)); | |||
} | |||
public static void WriteLittle(this BinaryWriter writer, short value) | |||
{ | |||
writer.Write((byte)(value >> 8)); | |||
writer.Write((byte)(value)); | |||
} | |||
public static void WriteLittle(this BinaryWriter writer, ushort value) | |||
{ | |||
writer.Write((byte)(value >> 8)); | |||
writer.Write((byte)(value)); | |||
} | |||
public static void WriteLittle(this BinaryWriter writer, byte value) | |||
{ | |||
writer.Write(value); | |||
} | |||
public static void WriteLittle(this BinaryWriter writer, byte[] value) | |||
{ | |||
writer.Write(value); | |||
} | |||
public static ulong ReadUInt64Little(this BinaryReader read) | |||
{ | |||
var buffer = read.ReadBytes(8); | |||
return (ulong)(buffer[7] | buffer[6] << 8 | buffer[5] << 16 | buffer[4] << 24| buffer[3] << 32 | buffer[2] << 40 | buffer[1] << 48 | buffer[0] << 56); | |||
} | |||
public static uint ReadUInt32Little(this BinaryReader read) | |||
{ | |||
var buffer = read.ReadBytes(4); | |||
return (uint)(buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24); | |||
} | |||
public static ushort ReadUInt16Little(this BinaryReader read) | |||
{ | |||
var buffer = read.ReadBytes(2); | |||
return (ushort)(buffer[1] | buffer[0] << 8); | |||
} | |||
/// <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(); | |||
} | |||
} | |||
} |
@@ -1,141 +0,0 @@ | |||
using JT809.Protocol.Configs; | |||
using System.Collections.Generic; | |||
namespace JT809.Protocol.ProtocolPacket.Extensions | |||
{ | |||
/// <summary> | |||
/// 包扩展方法 | |||
/// </summary> | |||
public static class PackageExtensions | |||
{ | |||
const ushort cnCRC_CCITT = 0x1021; //CRC校验多项式 | |||
static ulong[] CRC = new ulong[256]; //建立CRC16表 | |||
static PackageExtensions() | |||
{ | |||
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; | |||
} | |||
} | |||
internal static byte[] Escape(this Package packege, byte[] bytes) | |||
{ | |||
List<byte> dataList = new List<byte>(); | |||
dataList.Add(bytes[0]); | |||
for (int i = 1; i < bytes.Length - 1; i++) | |||
{ | |||
var item = bytes[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(bytes[bytes.Length - 1]); | |||
var tempBuffe = dataList.ToArray(); | |||
return tempBuffe; | |||
} | |||
internal static byte[] UnEscape(this Package packege, byte[] bytes) | |||
{ | |||
List<byte> dataList = new List<byte>(); | |||
dataList.Add(bytes[0]); | |||
for (int i = 1; i < bytes.Length - 1; i++) | |||
{ | |||
byte first = bytes[i]; | |||
byte second = bytes[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(bytes[bytes.Length - 1]); | |||
var tempBuffe = dataList.ToArray(); | |||
return tempBuffe; | |||
} | |||
/// <summary> | |||
/// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。 | |||
/// </summary> | |||
/// <param name="packege"></param> | |||
/// <param name="ucbuf"></param> | |||
/// <param name="offset"></param> | |||
/// <param name="iLen"></param> | |||
/// <returns></returns> | |||
internal static ushort CRC16_CCITT(this Package packege, 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; | |||
} | |||
internal static byte[] Encrypt(this Package packege, byte[] buffer, int size, JT809EncryptConfig Config) | |||
{ | |||
if (0 == Config.Key) | |||
{ | |||
Config.Key = 1; | |||
} | |||
uint mkey = Config.M1; | |||
if (0 == mkey) | |||
{ | |||
mkey = 1; | |||
} | |||
for (int idx = 0; idx < size; idx++) | |||
{ | |||
Config.Key = Config.IA1 * (Config.Key % mkey) + Config.IC1; | |||
buffer[idx] ^= (byte)((Config.Key >> 20) & 0xFF); | |||
} | |||
return buffer; | |||
} | |||
} | |||
} |
@@ -1,101 +0,0 @@ | |||
using JT809.Protocol.Configs; | |||
using JT809.Protocol.Enums; | |||
using System; | |||
using System.IO; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
/// <summary> | |||
/// Message Header 数据头 | |||
/// </summary> | |||
public class Header: BufferedEntityBase | |||
{ | |||
/// <summary> | |||
/// 固定为22个字节长度 | |||
/// </summary> | |||
public const int HeaderFixedByteLength = 22; | |||
/// <summary> | |||
/// 发送计数器 | |||
/// 占用四个字节,为发送信息的序列号,用于接收方检测是否有信息的丢失,上级平台和下级平台接自己发送数据包的个数计数,互不影响。 | |||
/// 程序开始运行时等于零,发送第一帧数据时开始计数,到最大数后自动归零 | |||
/// </summary> | |||
public static uint CounterOnSendGenerater { get; private set; } | |||
/// <summary> | |||
/// 接收计数器 | |||
/// 占用四个字节,为发送信息的序列号,用于接收方检测是否有信息的丢失,上级平台和下级平台接自己发送数据包的个数计数,互不影响。 | |||
/// 程序开始运行时等于零,发送第一帧数据时开始计数,到最大数后自动归零 | |||
/// </summary> | |||
public static uint CounterOnRecieveGenerater { get; private set; } | |||
/// <summary> | |||
/// 数据长度(包括头标识、数据头、数据体和尾标识) | |||
/// </summary> | |||
public uint Length { get; private set; } | |||
/// <summary> | |||
/// 报文序列号 | |||
/// </summary> | |||
public uint SN { get; private set; } | |||
/// <summary> | |||
/// 业务数据类型 | |||
/// </summary> | |||
public BusinessType BusinessID { get; private set; } | |||
/// <summary> | |||
/// 下级平台接入码,上级平台给下级平台分配唯一标识码。 | |||
/// </summary> | |||
public uint SessionId { get; set; } | |||
public JT809Version JT809Version { get; private set; } | |||
public EncryptOpitions EncryptOpition { get; private set; } | |||
/// <summary> | |||
/// 数据加密的密匙,长度为 4 个字节。 | |||
/// </summary> | |||
public uint EncryptKey { get; private set; } = 0X00; | |||
public Header(byte[] buffer) : base(buffer) { CounterOnRecieveGenerater++; } | |||
internal Header(uint length, uint number, BusinessType businessID, JT809Config jt809Config) : base(length, number, businessID, jt809Config) | |||
{ CounterOnSendGenerater++; } | |||
public Header(uint length, BusinessType businessID, JT809Config jt809Config) : this(length, CounterOnSendGenerater, businessID, jt809Config) { } | |||
protected override void InitializeProperties(object[] properties, int startIndex) | |||
{ | |||
Length = (uint)properties[0] + Package.NotDataLength; | |||
SN = (uint)properties[1]; | |||
BusinessID = (BusinessType)properties[2]; | |||
JT809Config jt809Config=(JT809Config)properties[3]; | |||
SessionId = jt809Config.SessionId; | |||
JT809Version = jt809Config.JT809Version; | |||
EncryptOpition = jt809Config.JT809EncryptConfig==null? EncryptOpitions.None: EncryptOpitions.Common; | |||
if(jt809Config.JT809EncryptConfig == null) | |||
{ | |||
EncryptOpition = EncryptOpitions.None; | |||
} | |||
else | |||
{ | |||
EncryptOpition = EncryptOpitions.Common; | |||
EncryptKey = jt809Config.JT809EncryptConfig.Key; | |||
} | |||
} | |||
protected override void OnInitializePropertiesFromReadBuffer(BinaryReader reader) | |||
{ | |||
Length = reader.ReadUInt32Little(); | |||
SN = reader.ReadUInt32Little(); | |||
BusinessID = (BusinessType)reader.ReadUInt16Little(); | |||
SessionId = reader.ReadUInt32Little(); | |||
JT809Version = new JT809Version(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); | |||
EncryptOpition = (EncryptOpitions)reader.ReadByte(); | |||
EncryptKey = reader.ReadUInt32Little(); | |||
} | |||
protected override void OnWriteToBuffer(BinaryWriter writer) | |||
{ | |||
writer.WriteLittle(Length); | |||
writer.WriteLittle(SN); | |||
writer.WriteLittle((ushort)BusinessID); | |||
writer.WriteLittle(SessionId); | |||
writer.WriteLittle(JT809Version.Buffer); | |||
writer.WriteLittle((byte)EncryptOpition); | |||
writer.WriteLittle(EncryptKey); | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
public interface IBuffer | |||
{ | |||
byte[] Buffer { get; } | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
public interface IBuffered | |||
{ | |||
byte[] ToBuffer(); | |||
} | |||
} |
@@ -1,46 +0,0 @@ | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
/// <summary> | |||
/// 协议版本好标识,上下级平台之间采用的标准协议版编号; | |||
/// 长度为 3 个字节来表示, | |||
/// 0x01 0x02 0x0F 标识的版本号是 v1.2.15,以此类推。 | |||
/// </summary> | |||
public class JT809Version | |||
{ | |||
public byte[] Buffer { get; } = new byte[3]; | |||
private const int MajorIndex = 0; | |||
private const int MinorIndex = 1; | |||
private const int BuildIndex = 2; | |||
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; } | |||
} | |||
public JT809Version() | |||
{ | |||
Major = 1; | |||
Minor = 0; | |||
Build = 0; | |||
} | |||
public JT809Version(byte major, byte minor, byte buid) | |||
{ | |||
Major = major; | |||
Minor = minor; | |||
Build = buid; | |||
} | |||
public override string ToString() | |||
{ | |||
return $"{Major}.{Minor}.{Build}"; | |||
} | |||
} | |||
} |
@@ -1,14 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.ProtocolPacket.Message.MainLink | |||
{ | |||
/// <summary> | |||
/// 主链路登录请求消息 | |||
/// </summary> | |||
public sealed class MainLink_Login: MessageBody | |||
{ | |||
} | |||
} |
@@ -1,15 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
/// <summary> | |||
/// 抽象消息体 | |||
/// </summary> | |||
public abstract class MessageBody: BufferedEntityBase | |||
{ | |||
protected MessageBody(params object[] properties) : base(properties){} | |||
protected MessageBody(byte[] buffer):base(buffer){} | |||
} | |||
} |
@@ -1,116 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Text; | |||
using JT809.Protocol.Configs; | |||
using JT809.Protocol.Enums; | |||
using JT809.Protocol.Exceptions; | |||
using JT809.Protocol.ProtocolPacket.Extensions; | |||
namespace JT809.Protocol.ProtocolPacket | |||
{ | |||
/// <summary> | |||
/// 数据包 | |||
/// </summary> | |||
public class Package: BufferedEntityBase | |||
{ | |||
public const int NotDataLength = 26; | |||
public const int Crc16ByteLength = 2; | |||
public const byte BeginFlag = 0X5B; | |||
public const byte EndFlag = 0X5D; | |||
public const int BeginFixedByteLength = 1; | |||
public const int EndFixedByteLength = 1; | |||
public JT809Config JT809Config; | |||
public Header Header { get; private set; } | |||
public MessageBody Body { get; private set; } | |||
private ushort CRC16 { get; set; } | |||
public Package(byte[] buffer) : base(buffer){} | |||
public Package(Header header, MessageBody body, JT809Config jt809Config) : base(header, body) | |||
{ | |||
JT809Config = jt809Config; | |||
} | |||
protected override void InitializeProperties(object[] properties, int startIndex) | |||
{ | |||
Header = properties[0] as Header; | |||
Body = properties[1] as MessageBody; | |||
if (Header == null) throw new NullReferenceException($"{new StackFrame().GetMethod().Name }:Header can't be null."); | |||
if (Body == null) throw new NullReferenceException($"{new StackFrame().GetMethod().Name }:Body can't be null."); | |||
} | |||
protected override void OnInitializePropertiesFromReadBuffer(BinaryReader reader) | |||
{ | |||
var content00 = new byte[Buffer.Length- BeginFixedByteLength-EndFixedByteLength]; | |||
Array.Copy(Buffer, BeginFixedByteLength, content00, 0, Buffer.Length- BeginFixedByteLength-EndFixedByteLength); | |||
var content01 = this.UnEscape(content00); | |||
var crc16 = this.CRC16_CCITT(content01, 0, content01.Length - Crc16ByteLength); | |||
CRC16 = BitConverter.ToUInt16(new[] { content01[content01.Length - 1], content01[content01.Length - 2] }, 0); | |||
if (CRC16 != crc16) throw new JT809Exception(ErrorCode.CRC16CheckInvalid,$"{CRC16}-{crc16},{content01.ToHexString()}"); | |||
Header = new Header(content01); | |||
var bodyBuffer00 = new byte[content01.Length - Header.HeaderFixedByteLength - Crc16ByteLength]; | |||
Array.Copy(content01, Header.HeaderFixedByteLength, bodyBuffer00, 0, bodyBuffer00.Length); | |||
//Default | |||
byte[] bodyBuffer01 = bodyBuffer00; | |||
switch (Header.EncryptOpition) | |||
{ | |||
case EncryptOpitions.None: | |||
break; | |||
case EncryptOpitions.Common: | |||
bodyBuffer01 = this.Encrypt(bodyBuffer01, bodyBuffer01.Length, JT809Config.JT809EncryptConfig); | |||
break; | |||
} | |||
if (Header.Length != (bodyBuffer01.Length + NotDataLength)) throw new JT809Exception(ErrorCode.HeaderLengthNotEqualBodyLength); | |||
Body = GenerateBody(Header.BusinessID, bodyBuffer01); | |||
} | |||
protected override void OnWriteToBuffer(BinaryWriter writer) | |||
{ | |||
writer.WriteLittle(BeginFlag); | |||
//Dealling Code On Header | |||
var headerBuffer00 = Header.Buffer; | |||
//Dealling Code On Body | |||
byte[] bodyBuffer00 = Body.Buffer; | |||
switch (Header.EncryptOpition) | |||
{ | |||
case EncryptOpitions.None: | |||
bodyBuffer00 = Body.Buffer; | |||
break; | |||
case EncryptOpitions.Common: | |||
bodyBuffer00 = this.Encrypt(Body.Buffer, Body.Buffer.Length, JT809Config.JT809EncryptConfig); | |||
break; | |||
} | |||
//Content:Except BeginFlag & EndFlag | |||
var content = new byte[headerBuffer00.Length + bodyBuffer00.Length + Crc16ByteLength]; | |||
Array.Copy(headerBuffer00, 0, content, 0, headerBuffer00.Length); | |||
Array.Copy(bodyBuffer00, 0, content, headerBuffer00.Length, bodyBuffer00.Length); | |||
//Dealling Code On CRC16 | |||
CRC16 = this.CRC16_CCITT(content, 0, content.Length - Crc16ByteLength); | |||
var crc1600 = BitConverter.GetBytes(CRC16).Reverse().ToArray(); | |||
Array.Copy(crc1600, 0, content, headerBuffer00.Length + bodyBuffer00.Length, Crc16ByteLength); | |||
//Last Content | |||
var content00 = this.Escape(content); | |||
//ToBuffer Core. | |||
writer.WriteLittle(content00); | |||
writer.WriteLittle(EndFlag); | |||
} | |||
public static Package GeneratePackage(BusinessType businessType, MessageBody messageBody, JT809Config jt809Config) | |||
{ | |||
var header = new Header((uint)messageBody.Buffer.Length, businessType, jt809Config); | |||
return new Package(header, messageBody, jt809Config); | |||
} | |||
public static MessageBody GenerateBody(BusinessType businessID, byte[] bodyBuffer) | |||
{ | |||
return Activator.CreateInstance(typeof(object), bodyBuffer) as MessageBody; | |||
} | |||
} | |||
} |