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.

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