Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

444 строки
20 KiB

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