Просмотр исходного кода

v2.3.7

1.增加0x0200兼容多1个字节的重复附加Id解析(兼容坑爹设备)
2.修复0x0100分析器输出名称
3.增加demo10兼容附加Id的处理
4.修改文档
tags/v2.3.7
SmallChi(Koike) 4 лет назад
Родитель
Сommit
104eb9b31a
9 измененных файлов: 294 добавлений и 20 удалений
  1. +7
    -0
      README.md
  2. +0
    -7
      src/JT808.Protocol.Test/MessageBody/JT808_0x0100Test.cs
  3. +51
    -0
      src/JT808.Protocol.Test/MessageBody/JT808_0x0200Test.cs
  4. +124
    -0
      src/JT808.Protocol.Test/Simples/Demo10.cs
  5. +1
    -1
      src/JT808.Protocol/JT808.Protocol.csproj
  6. +28
    -0
      src/JT808.Protocol/JT808.Protocol.xml
  7. +2
    -2
      src/JT808.Protocol/JT808Package.cs
  8. +3
    -3
      src/JT808.Protocol/MessageBody/JT808_0x0100.cs
  9. +78
    -7
      src/JT808.Protocol/MessageBody/JT808_0x0200.cs

+ 7
- 0
README.md Просмотреть файл

@@ -290,6 +290,13 @@ JT808Serializer DT2JT808Serializer = new JT808Serializer(DT2JT808Config);

[可以参考Simples的Demo9](https://github.com/SmallChi/JT808/blob/master/src/JT808.Protocol.Test/Simples/Demo9.cs)

### 举个栗子10

场景:
有些设备,不会按照国标的附加信息Id来搞,把附加信息Id搞为两个字节,这样在上报上来的数据就会存在重复的附加Id,导致平台解析出错。

[可以参考Simples的Demo10](https://github.com/SmallChi/JT808/blob/master/src/JT808.Protocol.Test/Simples/Demo10.cs)

## NuGet安装

| Package Name | Version | Downloads |


+ 0
- 7
src/JT808.Protocol.Test/MessageBody/JT808_0x0100Test.cs Просмотреть файл

@@ -54,13 +54,6 @@ namespace JT808.Protocol.Test.MessageBody
Assert.Equal("smallchi123000000000", JT808Bodies.TerminalModel);
}

[Fact]
public void Test1_2()
{
byte[] bytes = "7E01000022040666575073004A00000000373231303447354C00000000003430363636353702D5E3483137323030000F7E".ToHexBytes();
string json = JT808Serializer.Analyze(bytes);
}

[Fact]
public void Test2019_1()
{


+ 51
- 0
src/JT808.Protocol.Test/MessageBody/JT808_0x0200Test.cs Просмотреть файл

@@ -18,13 +18,18 @@ namespace JT808.Protocol.Test.MessageBody
public class JT808_0x0200Test
{
JT808Serializer JT808Serializer;
JT808Serializer JT808Serializer1;

public JT808_0x0200Test()
{
IJT808Config jT808Config = new DefaultGlobalConfig();
IJT808Config jT808Config1 = new DefaultGlobalConfig();
jT808Config1.SkipCRCCode = true;
jT808Config.JT808_0X0200_Custom_Factory.SetMap<JT808LocationAttachImpl0x06>();
JT808Serializer = new JT808Serializer(jT808Config);
JT808Serializer1 = new JT808Serializer(jT808Config1);
}

[Fact]
public void Test1()
{
@@ -337,6 +342,52 @@ namespace JT808.Protocol.Test.MessageBody
string json = JT808Serializer.Analyze<JT808_0x0200>(bodys);
}

[Fact]
public void Test7()
{
//"附加信息列表": [
// {
// "[01]附加信息Id": 1,
// "[04]附加信息长度": 4,
// "[000024C7]里程": 9415
// },
// {
// "[2B]附加信息Id": 43,
// "[04]附加信息长度": 4,
// "[0B290B29]模拟量": 187239209
// },
// {
// "[30]附加信息Id": 48,
// "[01]附加信息长度": 1,
// "[17]无线通信网络信号强度": 23
// },
// {
// "[31]附加信息Id": 49,
// "[01]附加信息长度": 1,
// "[1B]GNSS定位卫星数": 27
// },
// {
// "[00]未知附加信息Id": 0, 坑爹,相同的
// "[04]未知附加信息长度": 4,
// "未知附加信息": "000400CE0B29"
// },
// {
// "[00]未知附加信息Id": 0, 坑爹,相同的
// "[0C]未知附加信息长度": 12,
// "未知附加信息": "000C00B289860620150013559848"
// },
// {
// "[EB]未知附加信息Id": 235,
// "[0E]未知附加信息长度": 14,
// "未知附加信息": "EB0E000C00B289860620150013559848"
// }
//]
byte[] bodys = "7E020000520111111111100002000000000000000301789B3406238AFA0000018B00F62104020046090104000024C72B040B290B2930011731011B000400CE0B29000C00B289860620150013559848EB0E000C00B2898606201500135598486C7E".ToHexBytes();
var package = JT808Serializer1.Deserialize(bodys);
JT808_0x0200 jT808UploadLocationRequest = (JT808_0x0200)package.Bodies;
Assert.Single(jT808UploadLocationRequest.ExceptionLocationAttachOriginalData);
}

[Fact]
public void Test_all_attcahids()
{


+ 124
- 0
src/JT808.Protocol.Test/Simples/Demo10.cs Просмотреть файл

@@ -0,0 +1,124 @@
using JT808.Protocol.Enums;
using JT808.Protocol.Interfaces;
using JT808.Protocol.Internal;
using JT808.Protocol.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using JT808.Protocol.MessageBody;
using JT808.Protocol.Formatters;
using JT808.Protocol.MessagePack;
using System.Text.Json;
using JT808.Protocol.MessageBody.CarDVR;

namespace JT808.Protocol.Test.Simples
{
public class Demo10
{
JT808Serializer JT808Serializer;

public Demo10()
{
IJT808Config jT808Config = new DefaultGlobalConfig();
jT808Config.JT808_0X0200_Custom_Factory.SetMap<JT808LocationAttachImpl0x00>();
JT808Serializer = new JT808Serializer(jT808Config);
}

[Fact]
public void Test1()
{
JT808_0x0200 jT808UploadLocationRequest = new JT808_0x0200
{
AlarmFlag = 1,
Altitude = 40,
GPSTime = DateTime.Parse("2021-04-03 11:10:10"),
Lat = 12222222,
Lng = 132444444,
Speed = 60,
Direction = 0,
StatusFlag = 2,
JT808CustomLocationAttachData = new Dictionary<byte, JT808_0x0200_CustomBodyBase>(),
ExceptionLocationAttachData = new List<JT808_0x0200_CustomBodyBase>()
};
jT808UploadLocationRequest.JT808CustomLocationAttachData.Add(0x00, new JT808LocationAttachImpl0x00
{
TestValue=new byte[] {0,1,2,3}
});
jT808UploadLocationRequest.ExceptionLocationAttachData.Add(new JT808LocationAttachImpl0x00
{
TestId= "012345678912"
});
var hex = JT808Serializer.Serialize(jT808UploadLocationRequest).ToHexString();
Assert.Equal("000000010000000200BA7F0E07E4F11C0028003C0000210403111010000400010203000C303132333435363738393132", hex);
}

[Fact]
public void Test1_1()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C0000210403111010000400010203000C303132333435363738393132".ToHexBytes();
JT808_0x0200 jT808UploadLocationRequest = JT808Serializer.Deserialize<JT808_0x0200>(bodys);
Assert.Equal((uint)1, jT808UploadLocationRequest.AlarmFlag);
Assert.Equal(DateTime.Parse("2021-04-03 11:10:10"), jT808UploadLocationRequest.GPSTime);
Assert.Equal(12222222, jT808UploadLocationRequest.Lat);
Assert.Equal(132444444, jT808UploadLocationRequest.Lng);
Assert.Equal(60, jT808UploadLocationRequest.Speed);
Assert.Equal((uint)2, jT808UploadLocationRequest.StatusFlag);
Assert.Equal(new byte[] { 0, 1, 2, 3 }, ((JT808LocationAttachImpl0x00)jT808UploadLocationRequest.JT808CustomLocationAttachData[0x00]).TestValue);
Assert.Equal("012345678912", ((JT808LocationAttachImpl0x00)jT808UploadLocationRequest.ExceptionLocationAttachData[0]).TestId);
}
}

public class JT808LocationAttachImpl0x00 : JT808_0x0200_CustomBodyBase, IJT808MessagePackFormatter<JT808LocationAttachImpl0x00>
{
/// <summary>
/// 附加Id 0x00
/// </summary>
public override byte AttachInfoId { get; set; } = 0x00;
/// <summary>
/// 不固定
/// </summary>
public override byte AttachInfoLength { get; set; }
/// <summary>
/// 只能存在一个 AttachInfoLength == 12
/// </summary>
public string TestId { get; set; }

/// <summary>
/// 只能存在一个 AttachInfoLength == 4
/// </summary>
public byte[] TestValue { get; set; }

public JT808LocationAttachImpl0x00 Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
{
JT808LocationAttachImpl0x00 jT808LocationAttachImpl0X00 = new JT808LocationAttachImpl0x00();
jT808LocationAttachImpl0X00.AttachInfoId = reader.ReadByte();
jT808LocationAttachImpl0X00.AttachInfoLength = reader.ReadByte();
if (jT808LocationAttachImpl0X00.AttachInfoLength == 12)
{
jT808LocationAttachImpl0X00.TestId = reader.ReadString(12);
}
else if(jT808LocationAttachImpl0X00.AttachInfoLength == 4)
{
jT808LocationAttachImpl0X00.TestValue = reader.ReadArray(4).ToArray();
}
return jT808LocationAttachImpl0X00;
}

public void Serialize(ref JT808MessagePackWriter writer, JT808LocationAttachImpl0x00 value, IJT808Config config)
{
writer.WriteByte(value.AttachInfoId);
if (!string.IsNullOrEmpty(value.TestId))
{
writer.WriteByte(12);
writer.WriteString(value.TestId.ValiString(nameof(TestId), 12));
}
else if (value.TestValue != null)
{
writer.WriteByte(4);
writer.WriteArray(value.TestValue.ValiBytes(nameof(TestValue), 4));
}
}
}
}

+ 1
- 1
src/JT808.Protocol/JT808.Protocol.csproj Просмотреть файл

@@ -15,7 +15,7 @@
<license>https://github.com/SmallChi/JT808/blob/master/LICENSE</license>
<DocumentationFile>JT808.Protocol.xml</DocumentationFile>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>2.3.6</Version>
<Version>2.3.7</Version>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<AnalysisLevel>latest</AnalysisLevel>
<EnableNETAnalyzers>true</EnableNETAnalyzers>


+ 28
- 0
src/JT808.Protocol/JT808.Protocol.xml Просмотреть файл

@@ -8879,6 +8879,34 @@
依赖平台录入的设备类型
</summary>
</member>
<member name="P:JT808.Protocol.MessageBody.JT808_0x0200.ExceptionLocationAttachOriginalData">
<summary>
有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。
形如:
00 0C 这个是长度
00 B2 这个是长度
实际解析
00 附加信息Id
0C 附加信息长度
00 附加信息Id
B2 附加信息长度
只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧
</summary>
</member>
<member name="P:JT808.Protocol.MessageBody.JT808_0x0200.ExceptionLocationAttachData">
<summary>
有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。
形如:
00 0C 这个是长度
00 B2 这个是长度
实际解析
00 附加信息Id
0C 附加信息长度
00 附加信息Id
B2 附加信息长度
只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧
</summary>
</member>
<member name="M:JT808.Protocol.MessageBody.JT808_0x0200.Deserialize(JT808.Protocol.MessagePack.JT808MessagePackReader@,JT808.Protocol.IJT808Config)">
<summary>


+ 2
- 2
src/JT808.Protocol/JT808Package.cs Просмотреть файл

@@ -294,7 +294,7 @@ namespace JT808.Protocol
writer.WriteNumber($"[{protocolVersion.ReadNumber()}]协议版本号(2019)", protocolVersion);
// 3.4.读取终端手机号
var terminalPhoneNo = reader.ReadBCD(20, config.Trim);
writer.WriteString($"[{terminalPhoneNo}]终端手机号", terminalPhoneNo);
writer.WriteString($"[{terminalPhoneNo.PadLeft(20,'0')}]终端手机号", terminalPhoneNo);
}
else
{
@@ -309,7 +309,7 @@ namespace JT808.Protocol
// 3.3.读取终端手机号
var terminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, false);
//消息体属性对象 结束
writer.WriteString($"[{terminalPhoneNo}]终端手机号", terminalPhoneNo);
writer.WriteString($"[{terminalPhoneNo.PadLeft(config.TerminalPhoneNoLength, '0')}]终端手机号", terminalPhoneNo);
}
// 3.4.读取消息流水号
var msgNum = reader.ReadUInt16();


+ 3
- 3
src/JT808.Protocol/MessageBody/JT808_0x0100.cs Просмотреть файл

@@ -147,7 +147,7 @@ namespace JT808.Protocol.MessageBody
writer.WriteString($"[{tmSpan.ToArray().ToHexString()}]终端型号(30)", jT808_0X0100.TerminalModel);
ReadOnlySpan<byte> tidSpan = reader.ReadVirtualArray(30);
jT808_0X0100.TerminalId = reader.ReadString(30);
writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端型号(30)", jT808_0X0100.TerminalId);
writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端ID(30)", jT808_0X0100.TerminalId);
}
else
{
@@ -159,13 +159,13 @@ namespace JT808.Protocol.MessageBody
writer.WriteString($"[{tmSpan.ToArray().ToHexString()}]终端型号(20)", jT808_0X0100.TerminalModel);
ReadOnlySpan<byte> tidSpan = reader.ReadVirtualArray(7);
jT808_0X0100.TerminalId = reader.ReadString(7);
writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端型号(7)", jT808_0X0100.TerminalId);
writer.WriteString($"[{tidSpan.ToArray().ToHexString()}]终端ID(7)", jT808_0X0100.TerminalId);
}
jT808_0X0100.PlateColor = reader.ReadByte();
writer.WriteNumber($"[{jT808_0X0100.PlateColor.ReadNumber()}]车牌颜色", jT808_0X0100.PlateColor);
ReadOnlySpan<byte> vnoSpan = reader.ReadVirtualArray(reader.ReadCurrentRemainContentLength());
jT808_0X0100.PlateNo = reader.ReadRemainStringContent();
writer.WriteString($"[{vnoSpan.ToArray().ToHexString()}]车牌颜色", jT808_0X0100.PlateNo);
writer.WriteString($"[{vnoSpan.ToArray().ToHexString()}]车牌号码", jT808_0X0100.PlateNo);
}
}
}

+ 78
- 7
src/JT808.Protocol/MessageBody/JT808_0x0200.cs Просмотреть файл

@@ -81,6 +81,32 @@ namespace JT808.Protocol.MessageBody
/// </summary>
public Dictionary<byte, JT808_0x0200_CustomBodyBase> JT808CustomLocationAttachData { get; set; }
/// <summary>
/// 有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。
/// 形如:
/// 00 0C 这个是长度
/// 00 B2 这个是长度
/// 实际解析
/// 00 附加信息Id
/// 0C 附加信息长度
/// 00 附加信息Id
/// B2 附加信息长度
/// 只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧
/// </summary>
public List<byte[]> ExceptionLocationAttachOriginalData { get; set; }
/// <summary>
/// 有些坑爹的设备,不讲武德,不会按照国标的附加信息Id来搞,变成附加信息Id搞为两个字节,导致解析的时候出问题,存在重复的附加Id。
/// 形如:
/// 00 0C 这个是长度
/// 00 B2 这个是长度
/// 实际解析
/// 00 附加信息Id
/// 0C 附加信息长度
/// 00 附加信息Id
/// B2 附加信息长度
/// 只能兼容作为一个字节的兼容,恰恰好一般长度不会超过255,要是超过就去怼厂家吧
/// </summary>
public List<JT808_0x0200_CustomBodyBase> ExceptionLocationAttachData { get; set; }
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
@@ -115,27 +141,57 @@ namespace JT808.Protocol.MessageBody
jT808_0X0200.JT808LocationAttachData = new Dictionary<byte, JT808_0x0200_BodyBase>();
jT808_0X0200.JT808CustomLocationAttachData = new Dictionary<byte, JT808_0x0200_CustomBodyBase>();
jT808_0X0200.JT808UnknownLocationAttachOriginalData = new Dictionary<byte, byte[]>();
jT808_0X0200.ExceptionLocationAttachOriginalData = new List<byte[]>();
jT808_0X0200.ExceptionLocationAttachData = new List<JT808_0x0200_CustomBodyBase>();
while (reader.ReadCurrentRemainContentLength() > 0)
{
try
{
ReadOnlySpan<byte> attachSpan = reader.GetVirtualReadOnlySpan(2);
byte attachId = attachSpan[0];
byte attachLen = attachSpan[1];
byte attachLen = attachSpan[1];
if (config.JT808_0X0200_Factory.Map.TryGetValue(attachId, out object jT808LocationAttachInstance))
{
dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(jT808LocationAttachInstance, ref reader, config);
jT808_0X0200.JT808LocationAttachData.Add(attachImpl.AttachInfoId, attachImpl);
if (jT808_0X0200.JT808LocationAttachData.ContainsKey(attachId))
{
//存在重复的就不解析,把数据统一放在异常定位数据里面
reader.Skip(2);
jT808_0X0200.ExceptionLocationAttachOriginalData.Add(reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
reader.Skip(attachLen);
}
else
{
dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(jT808LocationAttachInstance, ref reader, config);
jT808_0X0200.JT808LocationAttachData.Add(attachImpl.AttachInfoId, attachImpl);
}
}
else if (config.JT808_0X0200_Custom_Factory.Map.TryGetValue(attachId,out object customAttachInstance))
{
dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(customAttachInstance, ref reader, config);
jT808_0X0200.JT808CustomLocationAttachData.Add(attachImpl.AttachInfoId, attachImpl);
if (jT808_0X0200.JT808CustomLocationAttachData.ContainsKey(attachId))
{
//目前根据坑爹的协议只做了附加Id相同的情况下,长度不同的解析方式。
//在已知的情况:附加Id相同,但是长度不同的时候,只能当做用长度来识别是对应的哪个,然后把数据剩下一个放在异常附加数据里面
dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(customAttachInstance, ref reader, config);
jT808_0X0200.ExceptionLocationAttachData.Add(attachImpl);
}
else
{
dynamic attachImpl = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(customAttachInstance, ref reader, config);
jT808_0X0200.JT808CustomLocationAttachData.Add(attachImpl.AttachInfoId, attachImpl);
}
}
else
{
reader.Skip(2);
jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
if (jT808_0X0200.JT808UnknownLocationAttachOriginalData.ContainsKey(attachId))
{
//未知的情况下:存在重复的就不解析,把数据统一放在异常定位数据里面
jT808_0X0200.ExceptionLocationAttachOriginalData.Add(reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
}
else
{
jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
}
reader.Skip(attachLen);
}
}
@@ -145,7 +201,15 @@ namespace JT808.Protocol.MessageBody
{
byte attachId = reader.ReadByte();
byte attachLen = reader.ReadByte();
jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
if (jT808_0X0200.JT808UnknownLocationAttachOriginalData.ContainsKey(attachId))
{
//未知的情况下:存在重复的就不解析,把数据统一放在异常定位数据里面
jT808_0X0200.ExceptionLocationAttachOriginalData.Add(reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
}
else
{
jT808_0X0200.JT808UnknownLocationAttachOriginalData.Add(attachId, reader.ReadArray(reader.ReaderCount - 2, attachLen + 2).ToArray());
}
reader.Skip(attachLen);
}
catch (Exception ex)
@@ -220,6 +284,13 @@ namespace JT808.Protocol.MessageBody
JT808MessagePackFormatterResolverExtensions.JT808DynamicSerialize(item.Value, ref writer, item.Value, config);
}
}
if (value.ExceptionLocationAttachData != null && value.ExceptionLocationAttachData.Count > 0)
{
foreach (var item in value.ExceptionLocationAttachData)
{
JT808MessagePackFormatterResolverExtensions.JT808DynamicSerialize(item, ref writer, item, config);
}
}
}
/// <summary>
///


Загрузка…
Отмена
Сохранить