You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
9.0 KiB

  1. using JT809.Protocol.JT809Attributes;
  2. using JT809.Protocol.JT809Enums;
  3. using JT809.Protocol.JT809Exceptions;
  4. using JT809.Protocol.JT809Extensions;
  5. using System;
  6. using System.Buffers;
  7. using System.Collections.Generic;
  8. using System.Text;
  9. namespace JT809.Protocol.JT809Formatters
  10. {
  11. public class JT809PackageFormatter : IJT809Formatter<JT809Package>
  12. {
  13. public object JT808BinaryExtensions { get; private set; }
  14. public JT809Package Deserialize(ReadOnlySpan<byte> bytes, out int readSize)
  15. {
  16. int offset = 0;
  17. JT809Package jT809Package = new JT809Package();
  18. // 转义还原——>验证校验码——>解析消息
  19. // 1. 解码(转义还原)
  20. ReadOnlySpan<byte> buffer = JT809DeEscape(bytes);
  21. // 2. 验证校验码
  22. // 2.1. 获取校验位索引
  23. int checkIndex = buffer.Length - 3;
  24. // 2.2. 获取校验码
  25. int crcCodeOffset = 0;
  26. jT809Package.CRCCode = JT809BinaryExtensions.ReadUInt16Little(buffer.Slice(checkIndex,2),ref crcCodeOffset);
  27. // 2.3. 从消息头到校验码前一个字节
  28. ushort checkCode = buffer.ToCRC16_CCITT(1, checkIndex);
  29. // 2.4. 验证校验码
  30. if (!JT809GlobalConfig.Instance.SkipCRCCode)
  31. {
  32. if (jT809Package.CRCCode != checkCode)
  33. {
  34. throw new JT809Exception(JT809ErrorCode.CRC16CheckInvalid, $"{jT809Package.CRCCode.ToString()}!={checkCode.ToString()}");
  35. }
  36. }
  37. jT809Package.BeginFlag = JT809BinaryExtensions.ReadByteLittle(buffer, ref offset);
  38. // 3.初始化消息头
  39. try
  40. {
  41. jT809Package.Header = JT809FormatterExtensions.GetFormatter<JT809Header>().Deserialize(buffer.Slice(offset, JT809Header.FixedByteLength), out readSize);
  42. }
  43. catch (Exception ex)
  44. {
  45. throw new JT809Exception(JT809ErrorCode.HeaderParseError, $"offset>{offset.ToString()}", ex);
  46. }
  47. offset += readSize;
  48. // 5.数据体处理
  49. // 5.1 判断是否有数据体(总长度-固定长度)> 0
  50. if ((jT809Package.Header.MsgLength - JT809Package.FixedByteLength) > 0)
  51. {
  52. //JT809.Protocol.JT809Enums.JT809BusinessType 映射对应消息特性
  53. JT809BodiesTypeAttribute jT809BodiesTypeAttribute = jT809Package.Header.BusinessType.GetAttribute<JT809BodiesTypeAttribute>();
  54. if (jT809BodiesTypeAttribute != null)
  55. {
  56. try
  57. {
  58. // 5.2 是否加密
  59. switch (jT809Package.Header.EncryptFlag)
  60. {
  61. case JT809Header_Encrypt.None:
  62. //5.3 处理消息体
  63. jT809Package.Bodies = JT809FormatterResolverExtensions.JT809DynamicDeserialize(JT809FormatterExtensions.GetFormatter(jT809BodiesTypeAttribute.JT809BodiesType), buffer.Slice(offset, checkIndex - offset), out readSize);
  64. break;
  65. case JT809Header_Encrypt.Common:
  66. byte[] bodiesData = JT809GlobalConfig.Instance.Encrypt.Decrypt(buffer.Slice(offset, checkIndex - offset).ToArray(), jT809Package.Header.EncryptKey);
  67. jT809Package.Bodies = JT809FormatterResolverExtensions.JT809DynamicDeserialize(JT809FormatterExtensions.GetFormatter(jT809BodiesTypeAttribute.JT809BodiesType), bodiesData, out readSize);
  68. break;
  69. }
  70. }
  71. catch (Exception ex)
  72. {
  73. throw new JT809Exception(JT809ErrorCode.BodiesParseError,$"offset>{offset.ToString()}", ex);
  74. }
  75. }
  76. }
  77. jT809Package.EndFlag = buffer[buffer.Length - 1];
  78. readSize = buffer.Length;
  79. return jT809Package;
  80. }
  81. public int Serialize(ref byte[] bytes, int offset, JT809Package value)
  82. {
  83. // 1. 先序列化数据体,根据数据体的长度赋值给头部,在序列化头部。
  84. int messageBodyOffset = 0;
  85. JT809BodiesTypeAttribute jT809BodiesTypeAttribute = value.Header.BusinessType.GetAttribute<JT809BodiesTypeAttribute>();
  86. if (jT809BodiesTypeAttribute != null)
  87. {
  88. if (value.Bodies != null)
  89. {
  90. // 1.1 处理数据体
  91. messageBodyOffset = JT809FormatterResolverExtensions.JT809DynamicSerialize(JT809FormatterExtensions.GetFormatter(jT809BodiesTypeAttribute.JT809BodiesType), ref bytes, messageBodyOffset, value.Bodies);
  92. }
  93. }
  94. byte[] messageBodyData=null;
  95. if (messageBodyOffset != 0)
  96. {
  97. messageBodyData = bytes.AsSpan(0, messageBodyOffset).ToArray();
  98. // 1.2 数据加密
  99. switch (value.Header.EncryptFlag)
  100. {
  101. case JT809Header_Encrypt.None:
  102. break;
  103. case JT809Header_Encrypt.Common:
  104. messageBodyData = JT809GlobalConfig.Instance.Encrypt.Encrypt(messageBodyData, value.Header.EncryptKey);
  105. break;
  106. }
  107. }
  108. // ------------------------------------开始组包
  109. // 1.起始符
  110. offset += JT809BinaryExtensions.WriteByteLittle(bytes, offset, value.BeginFlag);
  111. // 2.赋值头数据长度
  112. if (messageBodyOffset != 0)
  113. {
  114. value.Header.MsgLength = (uint)(JT809Package.FixedByteLength + messageBodyData.Length);
  115. }
  116. else
  117. {
  118. value.Header.MsgLength = JT809Package.FixedByteLength;
  119. }
  120. // 2.1写入头部数据
  121. offset = JT809FormatterExtensions.GetFormatter<JT809Header>().Serialize(ref bytes, offset, value.Header);
  122. if (messageBodyOffset != 0)
  123. {
  124. // 3. 写入数据体
  125. Array.Copy(messageBodyData, 0, bytes, offset, messageBodyData.Length);
  126. offset += messageBodyData.Length;
  127. messageBodyData = null;
  128. }
  129. // 4.校验码
  130. offset += JT809BinaryExtensions.WriteUInt16Little(bytes, offset, bytes.ToCRC16_CCITT(1, offset));
  131. // 5.终止符
  132. offset += JT809BinaryExtensions.WriteByteLittle(bytes, offset, value.EndFlag);
  133. // 6.转义
  134. byte[] temp = JT809Escape(bytes.AsSpan(0, offset));
  135. Array.Copy(temp, 0, bytes, 0, temp.Length);
  136. return temp.Length;
  137. }
  138. private static ReadOnlySpan<byte> JT809DeEscape(ReadOnlySpan<byte> buffer)
  139. {
  140. List<byte> dataList = new List<byte>();
  141. dataList.Add(buffer[0]);
  142. for (int i = 1; i < buffer.Length - 1; i++)
  143. {
  144. byte first = buffer[i];
  145. byte second = buffer[i + 1];
  146. if (first == 0x5a && second == 0x01)
  147. {
  148. dataList.Add(0x5b);
  149. i++;
  150. }
  151. else if (first == 0x5a && second == 0x02)
  152. {
  153. dataList.Add(0x5a);
  154. i++;
  155. }
  156. else if (first == 0x5e && second == 0x01)
  157. {
  158. dataList.Add(0x5d);
  159. i++;
  160. }
  161. else if (first == 0x5e && second == 0x02)
  162. {
  163. dataList.Add(0x5e);
  164. i++;
  165. }
  166. else
  167. {
  168. dataList.Add(first);
  169. }
  170. }
  171. dataList.Add(buffer[buffer.Length - 1]);
  172. return dataList.ToArray();
  173. }
  174. private static byte[] JT809Escape(Span<byte> buf)
  175. {
  176. List<byte> dataList = new List<byte>();
  177. dataList.Add(buf[0]);
  178. for (int i = 1; i < buf.Length - 1; i++)
  179. {
  180. var item = buf[i];
  181. switch (item)
  182. {
  183. case 0x5b:
  184. dataList.Add(0x5a);
  185. dataList.Add(0x01);
  186. break;
  187. case 0x5a:
  188. dataList.Add(0x5a);
  189. dataList.Add(0x02);
  190. break;
  191. case 0x5d:
  192. dataList.Add(0x5e);
  193. dataList.Add(0x01);
  194. break;
  195. case 0x5e:
  196. dataList.Add(0x5e);
  197. dataList.Add(0x02);
  198. break;
  199. default:
  200. dataList.Add(item);
  201. break;
  202. }
  203. }
  204. dataList.Add(buf[buf.Length - 1]);
  205. return dataList.ToArray();
  206. }
  207. }
  208. }