diff --git a/src/JT808.Protocol/Interfaces/IJT808Config.cs b/src/JT808.Protocol/Interfaces/IJT808Config.cs index 2d0b1ad..7b6f963 100644 --- a/src/JT808.Protocol/Interfaces/IJT808Config.cs +++ b/src/JT808.Protocol/Interfaces/IJT808Config.cs @@ -61,6 +61,10 @@ namespace JT808.Protocol /// IJT808_0x8500_2019_Factory JT808_0x8500_2019_Factory { get; set; } /// + /// 记录仪工厂 + /// + IJT808_Recorder_Factory IJT808_Recorder_Factory { get; set; } + /// /// 统一编码 /// Encoding Encoding { get; set; } diff --git a/src/JT808.Protocol/Interfaces/IJT808_Recorder_Factory.cs b/src/JT808.Protocol/Interfaces/IJT808_Recorder_Factory.cs new file mode 100644 index 0000000..a6055bc --- /dev/null +++ b/src/JT808.Protocol/Interfaces/IJT808_Recorder_Factory.cs @@ -0,0 +1,16 @@ +using JT808.Protocol.MessageBody.Recorder; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Protocol.Interfaces +{ + /// + /// 记录仪工厂 + /// + public interface IJT808_Recorder_Factory : IJT808ExternalRegister + { + IDictionary Map { get; } + IJT808_Recorder_Factory SetMap() ; + } +} diff --git a/src/JT808.Protocol/MessageBody/Recorder/JT808_RecorderBody.cs b/src/JT808.Protocol/MessageBody/Recorder/JT808_RecorderBody.cs new file mode 100644 index 0000000..68772f2 --- /dev/null +++ b/src/JT808.Protocol/MessageBody/Recorder/JT808_RecorderBody.cs @@ -0,0 +1,29 @@ +using JT808.Protocol.Interfaces; +using JT808.Protocol.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Protocol.MessageBody.Recorder +{ + /// + /// 记录仪数据体 + /// + public abstract class JT808_RecorderBody : IJT808Description + { + /// + /// 命令字 + /// + public abstract byte CommandId { get; } + public abstract JT808_RecorderBody Deserialize(ref JT808MessagePackReader reader, IJT808Config config); + public abstract void Serialize(ref JT808MessagePackWriter writer, JT808_RecorderBody value, IJT808Config config); + /// + /// 跳过数据体序列化 + /// 默认不跳过 + /// 当数据体为空的时候,使用null作为空包感觉不适合,所以就算使用空包也需要new一下来表达意思。 + /// + public virtual bool SkipSerialization { get; set; } = false; + + public abstract string Description { get; } + } +} diff --git a/src/JT808.Protocol/MessageBody/Recorder/JT808_RecorderHeader.cs b/src/JT808.Protocol/MessageBody/Recorder/JT808_RecorderHeader.cs new file mode 100644 index 0000000..b2b43a2 --- /dev/null +++ b/src/JT808.Protocol/MessageBody/Recorder/JT808_RecorderHeader.cs @@ -0,0 +1,41 @@ +using JT808.Protocol.Formatters; +using JT808.Protocol.Interfaces; +using JT808.Protocol.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; + +namespace JT808.Protocol.MessageBody.Recorder +{ + public class JT808_RecorderHeader: IJT808MessagePackFormatter, IJT808Analyze + { + /// + /// 命令字 + /// + public byte CommandId { get; set; } + /// + /// 数据块长度 + /// + public ushort DataLength { get; set; } + + public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config) + { + throw new NotImplementedException(); + } + + public JT808_RecorderHeader Deserialize(ref JT808MessagePackReader reader, IJT808Config config) + { + JT808_RecorderHeader value = new JT808_RecorderHeader(); + value.CommandId = reader.ReadByte(); + value.DataLength = reader.ReadUInt16(); + return value; + } + + public void Serialize(ref JT808MessagePackWriter writer, JT808_RecorderHeader value, IJT808Config config) + { + writer.WriteByte(value.CommandId); + writer.WriteUInt16(value.DataLength); + } + } +} diff --git a/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorder_Down_0x00.cs b/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorder_Down_0x00.cs new file mode 100644 index 0000000..be9e669 --- /dev/null +++ b/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorder_Down_0x00.cs @@ -0,0 +1,33 @@ +using JT808.Protocol.Formatters; +using JT808.Protocol.Interfaces; +using JT808.Protocol.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; + +namespace JT808.Protocol.MessageBody.Recorder +{ + /// + /// 采集记录仪执行标准版本 + /// 返回:记录仪执行标准的年号及修改单号 + /// + public class JT808_Recorder_Down_0x00 : JT808_RecorderBody + { + public override byte CommandId =>0x00; + + public override string Description => "采集记录仪执行标准版本"; + + public override bool SkipSerialization { get; set; } = true; + + public override JT808_RecorderBody Deserialize(ref JT808MessagePackReader reader, IJT808Config config) + { + throw new NotImplementedException(); + } + + public override void Serialize(ref JT808MessagePackWriter writer, JT808_RecorderBody value, IJT808Config config) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorder_Up_0x00.cs b/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorder_Up_0x00.cs new file mode 100644 index 0000000..aff99c8 --- /dev/null +++ b/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorder_Up_0x00.cs @@ -0,0 +1,52 @@ +using JT808.Protocol.Formatters; +using JT808.Protocol.Interfaces; +using JT808.Protocol.MessagePack; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; + +namespace JT808.Protocol.MessageBody.Recorder +{ + /// + /// 采集记录仪执行标准版本 + /// 返回:记录仪执行标准的年号及修改单号 + /// + public class JT808_Recorder_Up_0x00 : JT808_RecorderBody, IJT808Analyze + { + public override byte CommandId => 0x00; + /// + /// 记录仪执行标准年号后 2 位 BCD 码 + /// 无应答则默认为 03 + /// + public string StandardYear { get; set; } + /// + /// 修改单号 + /// 无修改单或无应答则默认为 00H + /// + public byte ModifyNumber { get; set; } + public override string Description => "采集记录仪执行标准版本应答"; + + public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config) + { + + } + + public override JT808_RecorderBody Deserialize(ref JT808MessagePackReader reader, IJT808Config config) + { + JT808_Recorder_Up_0x00 value = new JT808_Recorder_Up_0x00(); + value.StandardYear = reader.ReadBCD(2); + value.ModifyNumber = reader.ReadByte(); + return value; + } + + public override void Serialize(ref JT808MessagePackWriter writer, JT808_RecorderBody jT808_RecorderBody, IJT808Config config) + { + JT808_Recorder_Up_0x00 value = jT808_RecorderBody as JT808_Recorder_Up_0x00; + writer.WriteBCD(value.StandardYear, 2); + writer.WriteByte(value.ModifyNumber); + } + + } +} diff --git a/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorderpackage.cs b/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorderpackage.cs new file mode 100644 index 0000000..cf3a8eb --- /dev/null +++ b/src/JT808.Protocol/MessageBody/Recorder/JT808_Recorderpackage.cs @@ -0,0 +1,117 @@ +using JT808.Protocol.Extensions; +using JT808.Protocol.Formatters; +using JT808.Protocol.Interfaces; +using JT808.Protocol.MessagePack; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; + +namespace JT808.Protocol.MessageBody.Recorder +{ + /// + /// 记录仪 + /// + public class JT808_RecorderPackage : IJT808MessagePackFormatter, IJT808Analyze + { + public const ushort BeginFlag = 0x557A; + /// + /// 起始字头 + /// + public ushort Begin { get; set; } = BeginFlag; + /// + /// 记录仪头部 + /// + public JT808_RecorderHeader JT808_RecorderHeader { get; set; } + /// + /// 保留字段 + /// + public byte KeepFields { get; set; } = 0x00; + /// + /// 记录仪体 + /// + public JT808_RecorderBody JT808_RecorderBody { get; set; } + /// + /// 校验字 + /// + public byte CheckCode { get; set; } + /// + /// 计算的异或校验码 + /// + public byte CalculateCheckXorCode { get; set; } = 0; + /// + /// 跳过数据体序列化 + /// 默认不跳过 + /// 当数据体为空的时候,使用null作为空包感觉不适合,所以就算使用空包也需要new一下来表达意思。 + /// + public virtual bool SkipSerialization { get; set; } = false; + + public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config) + { + throw new NotImplementedException(); + } + + public JT808_RecorderPackage Deserialize(ref JT808MessagePackReader reader, IJT808Config config) + { + JT808_RecorderPackage value = new JT808_RecorderPackage(); + value.CalculateCheckXorCode = CalculateXorCheckCode(reader); + value.Begin = reader.ReadUInt16(); + value.JT808_RecorderHeader = new JT808_RecorderHeader().Deserialize(ref reader, config); + value.KeepFields = reader.ReadByte(); + if (value.JT808_RecorderHeader.DataLength > 0) + { + if (config.IJT808_Recorder_Factory.Map.TryGetValue(value.JT808_RecorderHeader.CommandId, out var instance)) + { + //4.2.处理消息体 + value.JT808_RecorderBody = instance.Deserialize(ref reader, config); + } + } + value.CheckCode = reader.ReadByte(); + return value; + } + + public void Serialize(ref JT808MessagePackWriter writer, JT808_RecorderPackage value, IJT808Config config) + { + var currentPosition = writer.GetCurrentPosition(); + writer.WriteUInt16(value.Begin); + value.JT808_RecorderHeader.Serialize(ref writer, value.JT808_RecorderHeader, config); + writer.WriteByte(value.KeepFields); + if (value.JT808_RecorderHeader.DataLength > 0) { + if (config.IJT808_Recorder_Factory.Map.TryGetValue(value.JT808_RecorderHeader.CommandId, out var instance)) + { + if (!instance.SkipSerialization) + { + //4.2.处理消息体 + instance.Serialize(ref writer, value.JT808_RecorderBody, config); + } + } + } + writer.WriteByte(CalculateXorCheckCode(writer.FlushAndGetRealReadOnlySpan().Slice(currentPosition, writer.GetCurrentPosition() - currentPosition + 1))); + } + /// + /// 计算校验码 + /// + /// + /// + private byte CalculateXorCheckCode(JT808MessagePackReader reader) { + var header = reader.GetVirtualReadOnlySpan(5); + int xorByteLength = 5+1 + BinaryPrimitives.ReadInt16BigEndian(header.Slice(3)); + var xorReadOnlySpan = reader.GetVirtualReadOnlySpan(xorByteLength); + return CalculateXorCheckCode(xorReadOnlySpan); + } + /// + /// 计算校验码 + /// + /// + /// + private byte CalculateXorCheckCode(ReadOnlySpan xorReadOnlySpan) { + byte calculateXorCheckCode = 0; + foreach (var item in xorReadOnlySpan) + { + calculateXorCheckCode = (byte)(calculateXorCheckCode ^ item); + } + return calculateXorCheckCode; + } + } +} \ No newline at end of file