using JT809.Protocol.Buffers; using JT809.Protocol.Extensions; using System; using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; namespace JT809.Protocol.MessagePack { public ref struct JT809MessagePackReader { public ReadOnlySpan Reader { get; private set; } public ReadOnlySpan SrcBuffer { get; } public int ReaderCount { get; private set; } private ushort _calculateCheckCRCCode; private ushort _realCheckCRCCode; private bool _checkCRCCodeVali; /// /// 是否进行解码操作 /// 若进行解码操作,则对应的是一个正常的包 /// 若不进行解码操作,则对应的是一个非正常的包(头部包,数据体包等等) /// 主要用来一次性读取所有数据体内容操作 /// private bool _decoded; private static byte[] decode5a01 = new byte[] { 0x5a, 0x01 }; private static byte[] decode5a02 = new byte[] { 0x5a, 0x02 }; private static byte[] decode5e01 = new byte[] { 0x5e, 0x01 }; private static byte[] decode5e02 = new byte[] { 0x5e, 0x02 }; /// /// 解码(转义还原),计算校验和 /// /// public JT809MessagePackReader(ReadOnlySpan srcBuffer) { SrcBuffer = srcBuffer; ReaderCount = 0; _realCheckCRCCode = 0x00; _calculateCheckCRCCode = 0xFFFF; _checkCRCCodeVali = false; _decoded = false; Reader = srcBuffer; } /// /// 在解码的时候把校验和也计算出来,避免在循环一次进行校验 /// /// public void Decode() { Span span = new byte[SrcBuffer.Length]; Decode(span); _decoded = true; } /// /// 在解码的时候把校验和也计算出来,避免在循环一次进行校验 /// /// public void Decode(Span allocateBuffer) { int offset = 0; int len = SrcBuffer.Length; allocateBuffer[offset++] = SrcBuffer[0]; // 取出校验码看是否需要转义 ReadOnlySpan checkCodeBufferSpan1 = SrcBuffer.Slice(len - 3, 2); int checkCodeLen = 0; if (TryDecode(checkCodeBufferSpan1, out byte value1)) { //最后两位是转义的 byte[] tmpCrc2 = new byte[2]; checkCodeLen += 2; tmpCrc2[1] = value1; //从最后往前在取两位进行转义 ReadOnlySpan checkCodeBufferSpan2 = SrcBuffer.Slice(len - 5, 2); if (TryDecode(checkCodeBufferSpan2, out byte value2)) { //转义成功 tmpCrc2[0] = value2; checkCodeLen += 2; } else { //转义不成功取当前最后一位 tmpCrc2[0] = checkCodeBufferSpan2[1]; checkCodeLen += 1; } _realCheckCRCCode = ReadUInt16(tmpCrc2); } else { //最后两位不是转义的 _realCheckCRCCode=ReadUInt16(checkCodeBufferSpan1); checkCodeLen += 2; } //转义数据长度 len = len - checkCodeLen - 1 - 1; ReadOnlySpan tmpBufferSpan = SrcBuffer.Slice(1, len); for (int i = 0; i < tmpBufferSpan.Length; i++) { byte tmp = 0; if ((tmpBufferSpan.Length - i) >= 2) { if (TryDecode(tmpBufferSpan.Slice(i, 2), out tmp)) { i++; } } else { tmp = tmpBufferSpan[i]; } allocateBuffer[offset++] = tmp; _calculateCheckCRCCode = (ushort)((_calculateCheckCRCCode << 8) ^ (ushort)CRCUtil.CRC[(_calculateCheckCRCCode >> 8) ^ tmp]); } allocateBuffer[offset++] = (byte)(_calculateCheckCRCCode >> 8); allocateBuffer[offset++] = (byte)_calculateCheckCRCCode; allocateBuffer[offset++] = SrcBuffer[SrcBuffer.Length- 1]; _checkCRCCodeVali = (_calculateCheckCRCCode == _realCheckCRCCode); Reader = allocateBuffer.Slice(0, offset); _decoded = true; } public void FullDecode() { int offset = 0; Span span = new byte[SrcBuffer.Length]; int len = SrcBuffer.Length; for (int i = 0; i < len; i++) { byte tmp = 0; if ((SrcBuffer.Length - i) >= 2) { if (TryDecode(SrcBuffer.Slice(i, 2), out tmp)) { i++; } } else { tmp = SrcBuffer[i]; } span[offset++] = tmp; } Reader = span.Slice(0, offset); } private bool TryDecode(ReadOnlySpan buffer,out byte value) { if (buffer.SequenceEqual(decode5a01)) { value = 0x5b; return true; } else if (buffer.SequenceEqual(decode5a02)) { value = 0x5a; return true; } else if (buffer.SequenceEqual(decode5e01)) { value = 0x5d; return true; } else if (buffer.SequenceEqual(decode5e02)) { value = 0x5e; return true; } else { value = buffer[0]; return false; } } public ushort CalculateCheckXorCode => _calculateCheckCRCCode; public ushort RealCheckXorCode => _realCheckCRCCode; public bool CheckXorCodeVali => _checkCRCCodeVali; public byte ReadStart()=> ReadByte(); public byte ReadEnd()=> ReadByte(); public ushort ReadUInt16() { return BinaryPrimitives.ReadUInt16BigEndian(GetReadOnlySpan(2)); } public ushort ReadUInt16(ReadOnlySpan buffer) { return BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(0, 2)); } public uint ReadUInt32() { return BinaryPrimitives.ReadUInt32BigEndian(GetReadOnlySpan(4)); } public int ReadInt32() { return BinaryPrimitives.ReadInt32BigEndian(GetReadOnlySpan(4)); } public ulong ReadUInt64() { return BinaryPrimitives.ReadUInt64BigEndian(GetReadOnlySpan(8)); } public long ReadInt64() { return BinaryPrimitives.ReadInt64BigEndian(GetReadOnlySpan(8)); } public byte ReadByte() { return GetReadOnlySpan(1)[0]; } public byte ReadVirtualByte() { return GetVirtualReadOnlySpan(1)[0]; } public ushort ReadVirtualUInt16() { return BinaryPrimitives.ReadUInt16BigEndian(GetVirtualReadOnlySpan(2)); } public short ReadVirtualInt16() { return BinaryPrimitives.ReadInt16BigEndian(GetVirtualReadOnlySpan(2)); } public uint ReadVirtualUInt32() { return BinaryPrimitives.ReadUInt32BigEndian(GetVirtualReadOnlySpan(4)); } public int ReadVirtualInt32() { return BinaryPrimitives.ReadInt32BigEndian(GetVirtualReadOnlySpan(4)); } public ulong ReadVirtualUInt64() { return BinaryPrimitives.ReadUInt64BigEndian(GetVirtualReadOnlySpan(8)); } public long ReadVirtualInt64() { return BinaryPrimitives.ReadInt64BigEndian(GetVirtualReadOnlySpan(8)); } /// /// 数字编码 大端模式、高位在前 /// /// public string ReadBigNumber(int len) { ulong result = 0; var readOnlySpan = GetReadOnlySpan(len); for (int i = 0; i < len; i++) { ulong currentData = (ulong)readOnlySpan[i] << (8 * (len - i - 1)); result += currentData; } return result.ToString(); } public ReadOnlySpan ReadArray(int len) { return GetReadOnlySpan(len).Slice(0, len); } public ReadOnlySpan ReadArray(int start,int end) { return Reader.Slice(start,end); } public string ReadString(int len) { var readOnlySpan = GetReadOnlySpan(len); string value = JT809Constants.Encoding.GetString(readOnlySpan.Slice(0, len).ToArray()); return value.Trim('\0'); } public string ReadRemainStringContent() { var readOnlySpan = ReadContent(0); string value = JT809Constants.Encoding.GetString(readOnlySpan.ToArray()); return value.Trim('\0'); } public string ReadHex(int len) { var readOnlySpan = GetReadOnlySpan(len); string hex = HexUtil.DoHexDump(readOnlySpan, 0, len); return hex; } /// /// yyMMddHHmmss /// /// >D2: 10 X2:16 public DateTime ReadDateTime6(string format = "X2") { DateTime d; try { var readOnlySpan = GetReadOnlySpan(6); int year = Convert.ToInt32(readOnlySpan[0].ToString(format)) + JT809Constants.DateLimitYear; int month = Convert.ToInt32(readOnlySpan[1].ToString(format)); int day = Convert.ToInt32(readOnlySpan[2].ToString(format)); int hour = Convert.ToInt32(readOnlySpan[3].ToString(format)); int minute = Convert.ToInt32(readOnlySpan[4].ToString(format)); int second = Convert.ToInt32(readOnlySpan[5].ToString(format)); d = new DateTime(year, month, day, hour, minute, second); } catch (Exception) { d = JT809Constants.UTCBaseTime; } return d; } /// /// HH-mm-ss-msms /// HH-mm-ss-fff /// /// D2: 10 X2:16 public DateTime ReadDateTime5(string format = "X2") { DateTime d; try { var readOnlySpan = GetReadOnlySpan(5); d = new DateTime( DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, Convert.ToInt32(readOnlySpan[0].ToString(format)), Convert.ToInt32(readOnlySpan[1].ToString(format)), Convert.ToInt32(readOnlySpan[2].ToString(format)), Convert.ToInt32(((readOnlySpan[3] << 8) + readOnlySpan[4]))); } catch { d = JT809Constants.UTCBaseTime; } return d; } /// /// YYYYMMDD /// /// D2: 10 X2:16 public DateTime ReadDateTime4(string format = "X2") { DateTime d; try { var readOnlySpan = GetReadOnlySpan(4); d = new DateTime( (Convert.ToInt32(readOnlySpan[0].ToString(format)) << 8) + Convert.ToByte(readOnlySpan[1]), Convert.ToInt32(readOnlySpan[2].ToString(format)), Convert.ToInt32(readOnlySpan[3].ToString(format))); } catch (Exception) { d = JT809Constants.UTCBaseTime; } return d; } public DateTime ReadUTCDateTime() { DateTime d; try { ulong result = 0; var readOnlySpan = GetReadOnlySpan(8); for (int i = 0; i < 8; i++) { ulong currentData = (ulong)readOnlySpan[i] << (8 * (8 - i - 1)); result += currentData; } d = JT809Constants.UTCBaseTime.AddSeconds(result).AddHours(8); } catch (Exception) { d = JT809Constants.UTCBaseTime; } return d; } public string ReadBCD(int len) { int count = len / 2; var readOnlySpan = GetReadOnlySpan(count); StringBuilder bcdSb = new StringBuilder(count); for (int i = 0; i < count; i++) { bcdSb.Append(readOnlySpan[i].ToString("X2")); } // todo:对于协议来说这个0是有意义的,下个版本在去掉 return bcdSb.ToString().TrimStart('0'); } private ReadOnlySpan GetReadOnlySpan(int count) { ReaderCount += count; return Reader.Slice(ReaderCount - count); } public ReadOnlySpan GetVirtualReadOnlySpan(int count) { return Reader.Slice(ReaderCount, count); } public ReadOnlySpan ReadContent(int count=0) { if (_decoded) { //内容长度=总长度-读取的长度-3(校验码1位+终止符1位) int totalContent = Reader.Length - ReaderCount - 3; //实际读取内容长度 int realContent = totalContent - count; int tempReaderCount = ReaderCount; ReaderCount += realContent; return Reader.Slice(tempReaderCount, realContent); } else { return Reader.Slice(ReaderCount); } } public int ReadCurrentRemainContentLength() { if (_decoded) { //内容长度=总长度-读取的长度-3(校验码2位+终止符1位) return Reader.Length - ReaderCount - 3; } else { return Reader.Length - ReaderCount; } } public void Skip(int count=1) { ReaderCount += count; } } }