465 line
20 KiB

  1. using JT808.Protocol.Enums;
  2. using JT808.Protocol.Exceptions;
  3. using JT808.Protocol.Extensions;
  4. using JT808.Protocol.Formatters;
  5. using JT808.Protocol.Interfaces;
  6. using JT808.Protocol.MessagePack;
  7. using System;
  8. using System.Text.Json;
  9. namespace JT808.Protocol
  10. {
  11. /// <summary>
  12. /// JT808数据包
  13. /// </summary>
  14. public class JT808Package : IJT808MessagePackFormatter<JT808Package>, IJT808Analyze
  15. {
  16. /// <summary>
  17. /// 起始符
  18. /// </summary>
  19. public const byte BeginFlag = 0x7e;
  20. /// <summary>
  21. /// 终止符
  22. /// </summary>
  23. public const byte EndFlag = 0x7e;
  24. /// <summary>
  25. /// 起始符
  26. /// </summary>
  27. public byte Begin { get; set; } = BeginFlag;
  28. /// <summary>
  29. /// 头数据
  30. /// </summary>
  31. public JT808Header Header { get; set; }
  32. /// <summary>
  33. /// 数据体
  34. /// </summary>
  35. public JT808Bodies Bodies { get; set; }
  36. /// <summary>
  37. /// 分包数据体
  38. /// </summary>
  39. public byte[] SubDataBodies { get; set; }
  40. /// <summary>
  41. /// 校验码
  42. /// 从消息头开始,同后一字节异或,直到校验码前一个字节,占用一个字节。
  43. /// </summary>
  44. public byte CheckCode { get; set; }
  45. /// <summary>
  46. /// 终止符
  47. /// </summary>
  48. public byte End { get; set; } = EndFlag;
  49. /// <summary>
  50. /// 808版本号
  51. /// </summary>
  52. public JT808Version Version
  53. {
  54. get
  55. {
  56. if (Header != null)
  57. {
  58. try
  59. {
  60. if (Header.MessageBodyProperty.VersionFlag)
  61. {
  62. return JT808Version.JTT2019;
  63. }
  64. else
  65. {
  66. return JT808Version.JTT2013;
  67. }
  68. }
  69. catch
  70. {
  71. return JT808Version.JTT2013;
  72. }
  73. }
  74. else
  75. {
  76. return JT808Version.JTT2013;
  77. }
  78. }
  79. }
  80. /// <summary>
  81. ///
  82. /// </summary>
  83. /// <param name="reader"></param>
  84. /// <param name="config"></param>
  85. /// <returns></returns>
  86. public JT808Package Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
  87. {
  88. // 1. 验证校验和
  89. if (!config.SkipCRCCode)
  90. {
  91. if (!reader.CheckXorCodeVali)
  92. {
  93. throw new JT808Exception(JT808ErrorCode.CheckCodeNotEqual, $"{reader.RealCheckXorCode}!={reader.CalculateCheckXorCode}");
  94. }
  95. }
  96. JT808Package jT808Package = new JT808Package();
  97. // ---------------开始解包--------------
  98. // 2.读取起始位置
  99. jT808Package.Begin = reader.ReadStart();
  100. // 3.读取头部信息
  101. jT808Package.Header = new JT808Header();
  102. // 3.1.读取消息Id
  103. jT808Package.Header.MsgId = reader.ReadUInt16();
  104. // 3.2.读取消息体属性
  105. jT808Package.Header.MessageBodyProperty = new JT808HeaderMessageBodyProperty(reader.ReadUInt16());
  106. if (reader.Version == JT808Version.JTT2013Force)
  107. {
  108. jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim);
  109. reader.Version = JT808Version.JTT2013;
  110. }
  111. else {
  112. if (reader.Version == JT808Version.JTT2019 || jT808Package.Header.MessageBodyProperty.VersionFlag)
  113. {
  114. //2019版本
  115. jT808Package.Header.ProtocolVersion = reader.ReadByte();
  116. // 3.4.读取终端手机号
  117. jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(20, config.Trim);
  118. reader.Version = JT808Version.JTT2019;
  119. }
  120. else
  121. {
  122. //2013版本
  123. // 3.3.读取终端手机号
  124. jT808Package.Header.TerminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, config.Trim);
  125. }
  126. }
  127. // 3.4.读取消息流水号
  128. jT808Package.Header.MsgNum = reader.ReadUInt16();
  129. // 3.5.判断有无分包
  130. if (jT808Package.Header.MessageBodyProperty.IsPackage)
  131. {
  132. //3.5.1.读取消息包总数
  133. jT808Package.Header.PackgeCount = reader.ReadUInt16();
  134. //3.5.2.读取消息包序号
  135. jT808Package.Header.PackageIndex = reader.ReadUInt16();
  136. }
  137. // 4.处理数据体
  138. // 4.1.判断有无数据体
  139. if (jT808Package.Header.MessageBodyProperty.DataLength > 0)
  140. {
  141. if (config.MsgIdFactory.TryGetValue(jT808Package.Header.MsgId, out object instance))
  142. {
  143. if (jT808Package.Header.MessageBodyProperty.IsPackage)
  144. {
  145. //读取分包的数据体
  146. try
  147. {
  148. jT808Package.SubDataBodies = reader.ReadArray(jT808Package.Header.MessageBodyProperty.DataLength).ToArray();
  149. }
  150. catch (Exception ex)
  151. {
  152. throw new JT808Exception(JT808ErrorCode.BodiesParseError, ex);
  153. }
  154. }
  155. else
  156. {
  157. try
  158. {
  159. //4.2.处理消息体
  160. jT808Package.Bodies = JT808MessagePackFormatterResolverExtensions.JT808DynamicDeserialize(
  161. instance,
  162. ref reader, config);
  163. }
  164. catch (Exception ex)
  165. {
  166. throw new JT808Exception(JT808ErrorCode.BodiesParseError, ex);
  167. }
  168. }
  169. }
  170. }
  171. // 5.读取校验码
  172. jT808Package.CheckCode = reader.ReadByte();
  173. // 6.读取终止位置
  174. jT808Package.End = reader.ReadEnd();
  175. // ---------------解包完成--------------
  176. return jT808Package;
  177. }
  178. /// <summary>
  179. ///
  180. /// </summary>
  181. /// <param name="writer"></param>
  182. /// <param name="value"></param>
  183. /// <param name="config"></param>
  184. public void Serialize(ref JT808MessagePackWriter writer, JT808Package value, IJT808Config config)
  185. {
  186. // ---------------开始组包--------------
  187. // 1.起始符
  188. writer.WriteStart();
  189. // 2.写入头部 //部分有带数据体的长度,那么先跳过写入头部部分
  190. // 2.1.消息ID
  191. writer.WriteUInt16(value.Header.MsgId);
  192. // 2.2.消息体属性(包含消息体长度所以先跳过)
  193. writer.Skip(2, out int msgBodiesPropertyPosition);
  194. if (writer.Version == JT808Version.JTT2019 || value.Header.MessageBodyProperty.VersionFlag)
  195. {
  196. //2019版本
  197. // 2.3.协议版本号
  198. writer.WriteByte(value.Header.ProtocolVersion);
  199. // 2.4.终端手机号
  200. writer.WriteBCD(value.Header.TerminalPhoneNo, 20);
  201. writer.Version = JT808Version.JTT2019;
  202. }
  203. else
  204. {
  205. //2013版本
  206. // 2.3.终端手机号 (写死大陆手机号码)
  207. writer.WriteBCD(value.Header.TerminalPhoneNo, config.TerminalPhoneNoLength);
  208. }
  209. if (value.Header.ManualMsgNum.HasValue)
  210. {
  211. // 2.4.消息流水号
  212. writer.WriteUInt16(value.Header.ManualMsgNum.Value);
  213. }
  214. else
  215. {
  216. // 2.4.消息流水号
  217. value.Header.MsgNum = config.MsgSNDistributed.Increment(value.Header.TerminalPhoneNo);
  218. writer.WriteUInt16(value.Header.MsgNum);
  219. }
  220. // 2.5.判断是否分包
  221. if (value.Header.MessageBodyProperty.IsPackage)
  222. {
  223. // 2.5.1.消息包总数
  224. writer.WriteUInt16(value.Header.PackgeCount);
  225. // 2.5.2.消息包序号
  226. writer.WriteUInt16(value.Header.PackageIndex);
  227. }
  228. int headerLength = writer.GetCurrentPosition();
  229. if (value.Header.MessageBodyProperty.IsPackage)
  230. {
  231. if (value.SubDataBodies != null)
  232. {
  233. //2.5.3.写入分包数据
  234. writer.WriteArray(value.SubDataBodies);
  235. }
  236. }
  237. else
  238. {
  239. // 3.处理数据体部分
  240. if (value.Bodies != null)
  241. {
  242. if (!value.Bodies.SkipSerialization)
  243. {
  244. JT808MessagePackFormatterResolverExtensions.JT808DynamicSerialize(value.Bodies,
  245. ref writer, value.Bodies,
  246. config);
  247. }
  248. }
  249. }
  250. // 3.1.处理数据体长度
  251. // 2.2.回写消息体属性
  252. value.Header.MessageBodyProperty.DataLength = (writer.GetCurrentPosition() - headerLength);
  253. writer.WriteUInt16Return(value.Header.MessageBodyProperty.Wrap(), msgBodiesPropertyPosition);
  254. // 4.校验码
  255. writer.WriteXor();
  256. // 5.终止符
  257. writer.WriteEnd();
  258. // 6.编码
  259. writer.WriteEncode();
  260. // ---------------组包结束--------------
  261. }
  262. /// <summary>
  263. ///
  264. /// </summary>
  265. /// <param name="reader"></param>
  266. /// <param name="writer"></param>
  267. /// <param name="config"></param>
  268. public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
  269. {
  270. // ---------------开始解析对象--------------
  271. writer.WriteStartObject();
  272. // 1. 验证校验和
  273. if (!reader.CheckXorCodeVali)
  274. {
  275. writer.WriteString("检验和错误", $"{reader.RealCheckXorCode}!={reader.CalculateCheckXorCode}");
  276. }
  277. // 2.读取起始位置
  278. byte start = reader.ReadEnd();
  279. writer.WriteNumber($"[{start.ReadNumber()}]开始", start);
  280. var msgid = reader.ReadUInt16();
  281. writer.WriteNumber($"[{msgid.ReadNumber()}]消息Id", msgid);
  282. ushort messageBodyPropertyValue = reader.ReadUInt16();
  283. var headerMessageBodyProperty = new JT808HeaderMessageBodyProperty(messageBodyPropertyValue);
  284. //消息体属性对象 开始
  285. writer.WriteStartObject("消息体属性对象");
  286. ReadOnlySpan<char> messageBodyPropertyReadOnlySpan = messageBodyPropertyValue.ReadBinary();
  287. writer.WriteNumber($"[{messageBodyPropertyReadOnlySpan.ToString()}]消息体属性", messageBodyPropertyValue);
  288. if (reader.Version == JT808Version.JTT2013Force)
  289. {
  290. reader.Version = JT808Version.JTT2013;
  291. writer.WriteNumber("[bit15]保留", 0);
  292. writer.WriteNumber("[bit14]保留", 0);
  293. writer.WriteBoolean("[bit13]是否分包", headerMessageBodyProperty.IsPackage);
  294. writer.WriteString("[bit10~bit12]数据加密", headerMessageBodyProperty.Encrypt.ToString());
  295. writer.WriteNumber("[bit0~bit9]消息体长度", headerMessageBodyProperty.DataLength);
  296. writer.WriteEndObject();
  297. //2013版本
  298. // 3.3.读取终端手机号
  299. var terminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, false);
  300. //消息体属性对象 结束
  301. writer.WriteString($"[{terminalPhoneNo.PadLeft(config.TerminalPhoneNoLength, '0')}]终端手机号", terminalPhoneNo);
  302. }
  303. else {
  304. if (reader.Version == JT808Version.JTT2019 || headerMessageBodyProperty.VersionFlag)
  305. {
  306. reader.Version = JT808Version.JTT2019;
  307. writer.WriteNumber("[bit15]保留", 0);
  308. writer.WriteBoolean("[bit14]协议版本标识", headerMessageBodyProperty.VersionFlag);
  309. writer.WriteBoolean("[bit13]是否分包", headerMessageBodyProperty.IsPackage);
  310. writer.WriteString("[bit10~bit12]数据加密", headerMessageBodyProperty.Encrypt.ToString());
  311. writer.WriteNumber("[bit0~bit9]消息体长度", headerMessageBodyProperty.DataLength);
  312. //消息体属性对象 结束
  313. writer.WriteEndObject();
  314. //2019版本
  315. var protocolVersion = reader.ReadByte();
  316. writer.WriteNumber($"[{protocolVersion.ReadNumber()}]协议版本号(2019)", protocolVersion);
  317. // 3.4.读取终端手机号
  318. var terminalPhoneNo = reader.ReadBCD(20, config.Trim);
  319. writer.WriteString($"[{terminalPhoneNo.PadLeft(20, '0')}]终端手机号", terminalPhoneNo);
  320. }
  321. else
  322. {
  323. reader.Version = JT808Version.JTT2013;
  324. writer.WriteNumber("[bit15]保留", 0);
  325. writer.WriteNumber("[bit14]保留", 0);
  326. writer.WriteBoolean("[bit13]是否分包", headerMessageBodyProperty.IsPackage);
  327. writer.WriteString("[bit10~bit12]数据加密", headerMessageBodyProperty.Encrypt.ToString());
  328. writer.WriteNumber("[bit0~bit9]消息体长度", headerMessageBodyProperty.DataLength);
  329. writer.WriteEndObject();
  330. //2013版本
  331. // 3.3.读取终端手机号
  332. var terminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, false);
  333. //消息体属性对象 结束
  334. writer.WriteString($"[{terminalPhoneNo.PadLeft(config.TerminalPhoneNoLength, '0')}]终端手机号", terminalPhoneNo);
  335. }
  336. }
  337. // 3.4.读取消息流水号
  338. var msgNum = reader.ReadUInt16();
  339. writer.WriteNumber($"[{msgNum.ReadNumber()}]消息流水号", msgNum);
  340. // 3.5.判断有无分包
  341. uint packgeCount = 0, packageIndex = 0;
  342. if (headerMessageBodyProperty.IsPackage)
  343. {
  344. //3.5.1.读取消息包总数
  345. packgeCount = reader.ReadUInt16();
  346. writer.WriteNumber($"[{packgeCount.ReadNumber()}]消息包总数", packgeCount);
  347. //3.5.2.读取消息包序号
  348. packageIndex = reader.ReadUInt16();
  349. writer.WriteNumber($"[{packageIndex.ReadNumber()}]消息包序号", packageIndex);
  350. }
  351. // 4.处理数据体
  352. // 4.1.判断有无数据体
  353. if (headerMessageBodyProperty.DataLength > 0)
  354. {
  355. //数据体属性对象 开始
  356. writer.WriteStartObject("数据体对象");
  357. string description = "数据体";
  358. if (headerMessageBodyProperty.IsPackage)
  359. {
  360. //读取分包的数据体
  361. try
  362. {
  363. writer.WriteString($"[分包]数据体", reader.ReadArray(reader.ReadCurrentRemainContentLength()).ToArray().ToHexString());
  364. }
  365. catch (IndexOutOfRangeException ex)
  366. {
  367. writer.WriteString($"数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  368. }
  369. catch (ArgumentOutOfRangeException ex)
  370. {
  371. writer.WriteString($"[分包]数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  372. }
  373. catch (Exception ex)
  374. {
  375. writer.WriteString($"[分包]数据体异常", ex.StackTrace);
  376. }
  377. }
  378. else
  379. {
  380. if (config.MsgIdFactory.TryGetValue(msgid, out object instance))
  381. {
  382. if (instance is IJT808Description jT808Description)
  383. {
  384. //4.2.处理消息体
  385. description = jT808Description.Description;
  386. }
  387. try
  388. {
  389. //数据体长度正常
  390. writer.WriteString($"{description}", reader.ReadVirtualArray(reader.ReadCurrentRemainContentLength()).ToArray().ToHexString());
  391. if (instance is IJT808Analyze analyze)
  392. {
  393. //4.2.处理消息体
  394. analyze.Analyze(ref reader, writer, config);
  395. }
  396. }
  397. catch (IndexOutOfRangeException ex)
  398. {
  399. writer.WriteString($"数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  400. }
  401. catch (ArgumentOutOfRangeException ex)
  402. {
  403. writer.WriteString($"数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  404. }
  405. catch (Exception ex)
  406. {
  407. writer.WriteString($"数据体异常", ex.StackTrace);
  408. }
  409. }
  410. else
  411. {
  412. writer.WriteString($"[未知]数据体", reader.ReadArray(reader.ReadCurrentRemainContentLength()).ToArray().ToHexString());
  413. }
  414. }
  415. //数据体属性对象 结束
  416. writer.WriteEndObject();
  417. }
  418. else
  419. {
  420. if (config.MsgIdFactory.TryGetValue(msgid, out object instance))
  421. {
  422. //数据体属性对象 开始
  423. writer.WriteStartObject("数据体对象");
  424. string description = "[Null]数据体";
  425. if (instance is IJT808Description jT808Description)
  426. {
  427. //4.2.处理消息体
  428. description = jT808Description.Description;
  429. }
  430. writer.WriteNull(description);
  431. //数据体属性对象 结束
  432. writer.WriteEndObject();
  433. }
  434. else
  435. {
  436. writer.WriteNull($"[Null]数据体");
  437. }
  438. }
  439. try
  440. {
  441. // 5.读取校验码
  442. reader.ReadByte();
  443. writer.WriteNumber($"[{reader.RealCheckXorCode.ReadNumber()}]校验码", reader.RealCheckXorCode);
  444. // 6.读取终止位置
  445. byte end = reader.ReadEnd();
  446. writer.WriteNumber($"[{end.ReadNumber()}]结束", end);
  447. }
  448. catch (ArgumentOutOfRangeException ex)
  449. {
  450. writer.WriteString($"数据解析异常,无可用数据进行解析", ex.StackTrace);
  451. }
  452. catch (Exception ex)
  453. {
  454. writer.WriteString($"数据解析异常", ex.StackTrace);
  455. }
  456. finally
  457. {
  458. writer.WriteEndObject();
  459. }
  460. }
  461. }
  462. }