浏览代码

1.增加JT809头部数据包解析及测试

2.将809编解码移到工具类
tags/v1.3.0
SmallChi 6 年前
父节点
当前提交
359a347cec
共有 5 个文件被更改,包括 232 次插入82 次删除
  1. +32
    -0
      src/JT809.Protocol.Test/JT809Packages/JT809HeaderPackageTest.cs
  2. +84
    -0
      src/JT809.Protocol/Formatters/JT809HeaderPackageFromatter.cs
  3. +2
    -82
      src/JT809.Protocol/Formatters/JT809PackageFormatter.cs
  4. +25
    -0
      src/JT809.Protocol/JT809HeaderPackage.cs
  5. +89
    -0
      src/JT809.Protocol/JT809Util.cs

+ 32
- 0
src/JT809.Protocol.Test/JT809Packages/JT809HeaderPackageTest.cs 查看文件

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using JT809.Protocol;
using JT809.Protocol.Extensions;
using JT809.Protocol.MessageBody;
using JT809.Protocol.Enums;

namespace JT809.Protocol.Test.JT809Packages
{
public class JT809HeaderPackageTest
{
[Fact]
public void Test1()
{
var bytes = "5B 00 00 00 48 00 00 00 85 10 01 01 33 EF B8 01 00 00 00 00 00 27 0F 01 33 EF B8 32 30 31 38 30 39 32 30 31 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 29 6A 91 5D".ToHexBytes();
JT809HeaderPackage jT809HeaderPackage = JT809Serializer.Deserialize<JT809HeaderPackage>(bytes);
Assert.Equal((uint)72, jT809HeaderPackage.Header.MsgLength);
Assert.Equal((uint)133, jT809HeaderPackage.Header.MsgSN);
Assert.Equal((uint)9999, jT809HeaderPackage.Header.EncryptKey);
Assert.Equal((uint)20180920, jT809HeaderPackage.Header.MsgGNSSCENTERID);
Assert.Equal(JT809BusinessType.主链路登录请求消息, jT809HeaderPackage.Header.BusinessType);
Assert.Equal(new JT809Header_Version().ToString(), jT809HeaderPackage.Header.Version.ToString());
JT809_0x1001 jT809_0X1001 = JT809Serializer.Deserialize<JT809_0x1001>(jT809HeaderPackage.Bodies);
Assert.Equal((uint)20180920, jT809_0X1001.UserId);
Assert.Equal("20180920", jT809_0X1001.Password);
Assert.Equal("127.0.0.1", jT809_0X1001.DownLinkIP);
Assert.Equal((ushort)809, jT809_0X1001.DownLinkPort);
}
}
}

+ 84
- 0
src/JT809.Protocol/Formatters/JT809HeaderPackageFromatter.cs 查看文件

@@ -0,0 +1,84 @@
using JT809.Protocol.Attributes;
using JT809.Protocol.Enums;
using JT809.Protocol.Exceptions;
using JT809.Protocol.Extensions;
using System;

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

public int Serialize(ref byte[] bytes, int offset, JT809HeaderPackage value)
{
throw new NotImplementedException("只适用反序列化");
}
}
}

+ 2
- 82
src/JT809.Protocol/Formatters/JT809PackageFormatter.cs 查看文件

@@ -17,7 +17,7 @@ namespace JT809.Protocol.Formatters
JT809Package jT809Package = new JT809Package();
// 转义还原——>验证校验码——>解析消息
// 1. 解码(转义还原)
ReadOnlySpan<byte> buffer = JT809DeEscape(bytes);
ReadOnlySpan<byte> buffer = JT809Util.JT809DeEscape(bytes);
// 2. 验证校验码
// 2.1. 获取校验位索引
int checkIndex = buffer.Length - 3;
@@ -132,87 +132,7 @@ namespace JT809.Protocol.Formatters
// 5.终止符
offset += JT809BinaryExtensions.WriteByteLittle(bytes, offset, value.EndFlag);
// 6.转义
return JT809Escape(ref bytes, offset);
}

internal static ReadOnlySpan<byte> JT809DeEscape(ReadOnlySpan<byte> buffer)
{
byte[] tmpBuffer = JT809ArrayPool.Rent(buffer.Length - 1);
try
{
int offset = 0;
tmpBuffer[offset++] = buffer[0];
for (int i = 1; i < buffer.Length - 1; i++)
{
byte first = buffer[i];
byte second = buffer[i + 1];
if (first == 0x5a && second == 0x01)
{
tmpBuffer[offset++] = 0x5b;
i++;
}
else if (first == 0x5a && second == 0x02)
{
tmpBuffer[offset++] = 0x5a;
i++;
}
else if (first == 0x5e && second == 0x01)
{
tmpBuffer[offset++] = 0x5d;
i++;
}
else if (first == 0x5e && second == 0x02)
{
tmpBuffer[offset++] = 0x5e;
i++;
}
else
{
tmpBuffer[offset++] = first;
}
}
tmpBuffer[offset++] = buffer[buffer.Length - 1];
return tmpBuffer.AsSpan(0, offset).ToArray();
}
finally
{
JT809ArrayPool.Return(tmpBuffer);
}
}

internal static int JT809Escape(ref byte[] buffer, int offset)
{
byte[] tmpBuffer = buffer.AsSpan(0, offset).ToArray();
int tmpOffset = 0;
buffer[tmpOffset++] = tmpBuffer[0];
for (int i = 1; i < offset - 1; i++)
{
var item = tmpBuffer[i];
switch (item)
{
case 0x5b:
buffer[tmpOffset++] = 0x5a;
buffer[tmpOffset++] = 0x01;
break;
case 0x5a:
buffer[tmpOffset++] = 0x5a;
buffer[tmpOffset++] = 0x02;
break;
case 0x5d:
buffer[tmpOffset++] = 0x5e;
buffer[tmpOffset++] = 0x01;
break;
case 0x5e:
buffer[tmpOffset++] = 0x5e;
buffer[tmpOffset++] = 0x02;
break;
default:
buffer[tmpOffset++] = item;
break;
}
}
buffer[tmpOffset++]= tmpBuffer[tmpBuffer.Length - 1];
return tmpOffset;
return JT809Util.JT809Escape(ref bytes, offset);
}
}
}

+ 25
- 0
src/JT809.Protocol/JT809HeaderPackage.cs 查看文件

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

namespace JT809.Protocol
{
/// <summary>
/// JT809头部数据包
/// </summary>
[JT809Formatter(typeof(JT809HeaderPackageFromatter))]
public class JT809HeaderPackage
{
public byte BeginFlag { get; set; } = JT809Package.BEGINFLAG;

public JT809Header Header { get; set; }

public byte[] Bodies { get; set; }

public ushort CRCCode { get; set; }

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

+ 89
- 0
src/JT809.Protocol/JT809Util.cs 查看文件

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

namespace JT809.Protocol
{
public static class JT809Util
{
internal static ReadOnlySpan<byte> JT809DeEscape(ReadOnlySpan<byte> buffer)
{
byte[] tmpBuffer = JT809ArrayPool.Rent(buffer.Length - 1);
try
{
int offset = 0;
tmpBuffer[offset++] = buffer[0];
for (int i = 1; i < buffer.Length - 1; i++)
{
byte first = buffer[i];
byte second = buffer[i + 1];
if (first == 0x5a && second == 0x01)
{
tmpBuffer[offset++] = 0x5b;
i++;
}
else if (first == 0x5a && second == 0x02)
{
tmpBuffer[offset++] = 0x5a;
i++;
}
else if (first == 0x5e && second == 0x01)
{
tmpBuffer[offset++] = 0x5d;
i++;
}
else if (first == 0x5e && second == 0x02)
{
tmpBuffer[offset++] = 0x5e;
i++;
}
else
{
tmpBuffer[offset++] = first;
}
}
tmpBuffer[offset++] = buffer[buffer.Length - 1];
return tmpBuffer.AsSpan(0, offset).ToArray();
}
finally
{
JT809ArrayPool.Return(tmpBuffer);
}
}

internal static int JT809Escape(ref byte[] buffer, int offset)
{
byte[] tmpBuffer = buffer.AsSpan(0, offset).ToArray();
int tmpOffset = 0;
buffer[tmpOffset++] = tmpBuffer[0];
for (int i = 1; i < offset - 1; i++)
{
var item = tmpBuffer[i];
switch (item)
{
case 0x5b:
buffer[tmpOffset++] = 0x5a;
buffer[tmpOffset++] = 0x01;
break;
case 0x5a:
buffer[tmpOffset++] = 0x5a;
buffer[tmpOffset++] = 0x02;
break;
case 0x5d:
buffer[tmpOffset++] = 0x5e;
buffer[tmpOffset++] = 0x01;
break;
case 0x5e:
buffer[tmpOffset++] = 0x5e;
buffer[tmpOffset++] = 0x02;
break;
default:
buffer[tmpOffset++] = item;
break;
}
}
buffer[tmpOffset++] = tmpBuffer[tmpBuffer.Length - 1];
return tmpOffset;
}
}
}

正在加载...
取消
保存