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