@@ -61,6 +61,10 @@ namespace JT808.Protocol | |||||
/// </summary> | /// </summary> | ||||
IJT808_0x8500_2019_Factory JT808_0x8500_2019_Factory { get; set; } | IJT808_0x8500_2019_Factory JT808_0x8500_2019_Factory { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// 记录仪工厂 | |||||
/// </summary> | |||||
IJT808_Recorder_Factory IJT808_Recorder_Factory { get; set; } | |||||
/// <summary> | |||||
/// 统一编码 | /// 统一编码 | ||||
/// </summary> | /// </summary> | ||||
Encoding Encoding { get; set; } | Encoding Encoding { get; set; } | ||||
@@ -0,0 +1,16 @@ | |||||
using JT808.Protocol.MessageBody.Recorder; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT808.Protocol.Interfaces | |||||
{ | |||||
/// <summary> | |||||
/// 记录仪工厂 | |||||
/// </summary> | |||||
public interface IJT808_Recorder_Factory : IJT808ExternalRegister | |||||
{ | |||||
IDictionary<byte, JT808_RecorderBody> Map { get; } | |||||
IJT808_Recorder_Factory SetMap<TJT808_RecorderBody>() ; | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 记录仪数据体 | |||||
/// </summary> | |||||
public abstract class JT808_RecorderBody : IJT808Description | |||||
{ | |||||
/// <summary> | |||||
/// 命令字 | |||||
/// </summary> | |||||
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); | |||||
/// <summary> | |||||
/// 跳过数据体序列化 | |||||
/// 默认不跳过 | |||||
/// 当数据体为空的时候,使用null作为空包感觉不适合,所以就算使用空包也需要new一下来表达意思。 | |||||
/// </summary> | |||||
public virtual bool SkipSerialization { get; set; } = false; | |||||
public abstract string Description { get; } | |||||
} | |||||
} |
@@ -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<JT808_RecorderHeader>, IJT808Analyze | |||||
{ | |||||
/// <summary> | |||||
/// 命令字 | |||||
/// </summary> | |||||
public byte CommandId { get; set; } | |||||
/// <summary> | |||||
/// 数据块长度 | |||||
/// </summary> | |||||
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); | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 采集记录仪执行标准版本 | |||||
/// 返回:记录仪执行标准的年号及修改单号 | |||||
/// </summary> | |||||
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(); | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 采集记录仪执行标准版本 | |||||
/// 返回:记录仪执行标准的年号及修改单号 | |||||
/// </summary> | |||||
public class JT808_Recorder_Up_0x00 : JT808_RecorderBody, IJT808Analyze | |||||
{ | |||||
public override byte CommandId => 0x00; | |||||
/// <summary> | |||||
/// 记录仪执行标准年号后 2 位 BCD 码 | |||||
/// 无应答则默认为 03 | |||||
/// </summary> | |||||
public string StandardYear { get; set; } | |||||
/// <summary> | |||||
/// 修改单号 | |||||
/// 无修改单或无应答则默认为 00H | |||||
/// </summary> | |||||
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); | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 记录仪 | |||||
/// </summary> | |||||
public class JT808_RecorderPackage : IJT808MessagePackFormatter<JT808_RecorderPackage>, IJT808Analyze | |||||
{ | |||||
public const ushort BeginFlag = 0x557A; | |||||
/// <summary> | |||||
/// 起始字头 | |||||
/// </summary> | |||||
public ushort Begin { get; set; } = BeginFlag; | |||||
/// <summary> | |||||
/// 记录仪头部 | |||||
/// </summary> | |||||
public JT808_RecorderHeader JT808_RecorderHeader { get; set; } | |||||
/// <summary> | |||||
/// 保留字段 | |||||
/// </summary> | |||||
public byte KeepFields { get; set; } = 0x00; | |||||
/// <summary> | |||||
/// 记录仪体 | |||||
/// </summary> | |||||
public JT808_RecorderBody JT808_RecorderBody { get; set; } | |||||
/// <summary> | |||||
/// 校验字 | |||||
/// </summary> | |||||
public byte CheckCode { get; set; } | |||||
/// <summary> | |||||
/// 计算的异或校验码 | |||||
/// </summary> | |||||
public byte CalculateCheckXorCode { get; set; } = 0; | |||||
/// <summary> | |||||
/// 跳过数据体序列化 | |||||
/// 默认不跳过 | |||||
/// 当数据体为空的时候,使用null作为空包感觉不适合,所以就算使用空包也需要new一下来表达意思。 | |||||
/// </summary> | |||||
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))); | |||||
} | |||||
/// <summary> | |||||
/// 计算校验码 | |||||
/// </summary> | |||||
/// <param name="readOnlySpan"></param> | |||||
/// <returns></returns> | |||||
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); | |||||
} | |||||
/// <summary> | |||||
/// 计算校验码 | |||||
/// </summary> | |||||
/// <param name="xorReadOnlySpan"></param> | |||||
/// <returns></returns> | |||||
private byte CalculateXorCheckCode(ReadOnlySpan<byte> xorReadOnlySpan) { | |||||
byte calculateXorCheckCode = 0; | |||||
foreach (var item in xorReadOnlySpan) | |||||
{ | |||||
calculateXorCheckCode = (byte)(calculateXorCheckCode ^ item); | |||||
} | |||||
return calculateXorCheckCode; | |||||
} | |||||
} | |||||
} |