No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

445 líneas
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. if (value.Header.MsgId == default) value.Header.MsgId = value.Bodies.MsgId;
  169. writer.WriteUInt16(value.Header.MsgId);
  170. // 2.2.消息体属性(包含消息体长度所以先跳过)
  171. writer.Skip(2, out int msgBodiesPropertyPosition);
  172. if (writer.Version == JT808Version.JTT2019 || value.Header.MessageBodyProperty.VersionFlag)
  173. {
  174. //2019版本
  175. // 2.3.协议版本号
  176. writer.WriteByte(value.Header.ProtocolVersion);
  177. // 2.4.终端手机号
  178. writer.WriteBCD(value.Header.TerminalPhoneNo, 20);
  179. writer.Version = JT808Version.JTT2019;
  180. value.Header.MessageBodyProperty.VersionFlag = true;
  181. }
  182. else
  183. {
  184. //2013版本
  185. // 2.3.终端手机号 (写死大陆手机号码)
  186. writer.WriteBCD(value.Header.TerminalPhoneNo, config.TerminalPhoneNoLength);
  187. }
  188. if (value.Header.ManualMsgNum.HasValue)
  189. {
  190. // 2.4.消息流水号
  191. writer.WriteUInt16(value.Header.ManualMsgNum.Value);
  192. }
  193. else
  194. {
  195. // 2.4.消息流水号
  196. value.Header.MsgNum = config.MsgSNDistributed.Increment(value.Header.TerminalPhoneNo);
  197. writer.WriteUInt16(value.Header.MsgNum);
  198. }
  199. // 2.5.判断是否分包
  200. if (value.Header.MessageBodyProperty.IsPackage)
  201. {
  202. // 2.5.1.消息包总数
  203. writer.WriteUInt16(value.Header.PackgeCount);
  204. // 2.5.2.消息包序号
  205. writer.WriteUInt16(value.Header.PackageIndex);
  206. }
  207. int headerLength = writer.GetCurrentPosition();
  208. if (value.Header.MessageBodyProperty.IsPackage)
  209. {
  210. if (value.SubDataBodies != null)
  211. {
  212. //2.5.3.写入分包数据
  213. writer.WriteArray(value.SubDataBodies);
  214. }
  215. }
  216. else
  217. {
  218. // 3.处理数据体部分
  219. if (value.Bodies != null)
  220. {
  221. if (!value.Bodies.SkipSerialization)
  222. {
  223. value.Bodies.SerializeExt(ref writer, value.Bodies, config);
  224. }
  225. }
  226. }
  227. // 3.1.处理数据体长度
  228. // 2.2.回写消息体属性
  229. value.Header.MessageBodyProperty.DataLength = (writer.GetCurrentPosition() - headerLength);
  230. writer.WriteUInt16Return(value.Header.MessageBodyProperty.Wrap(), msgBodiesPropertyPosition);
  231. // 4.校验码
  232. writer.WriteXor();
  233. // 5.终止符
  234. writer.WriteEnd();
  235. // 6.编码
  236. writer.WriteEncode();
  237. // ---------------组包结束--------------
  238. }
  239. /// <summary>
  240. ///
  241. /// </summary>
  242. /// <param name="reader"></param>
  243. /// <param name="writer"></param>
  244. /// <param name="config"></param>
  245. public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
  246. {
  247. // ---------------开始解析对象--------------
  248. writer.WriteStartObject();
  249. // 1. 验证校验和
  250. if (!reader.CheckXorCodeVali)
  251. {
  252. writer.WriteString("检验和错误", $"{reader.RealCheckXorCode}!={reader.CalculateCheckXorCode}");
  253. }
  254. // 2.读取起始位置
  255. byte start = reader.ReadEnd();
  256. writer.WriteNumber($"[{start.ReadNumber()}]开始", start);
  257. var msgid = reader.ReadUInt16();
  258. writer.WriteNumber($"[{msgid.ReadNumber()}]消息Id", msgid);
  259. ushort messageBodyPropertyValue = reader.ReadUInt16();
  260. var headerMessageBodyProperty = new JT808HeaderMessageBodyProperty(messageBodyPropertyValue);
  261. //消息体属性对象 开始
  262. writer.WriteStartObject("消息体属性对象");
  263. ReadOnlySpan<char> messageBodyPropertyReadOnlySpan = messageBodyPropertyValue.ReadBinary();
  264. writer.WriteNumber($"[{messageBodyPropertyReadOnlySpan.ToString()}]消息体属性", messageBodyPropertyValue);
  265. if (reader.Version == JT808Version.JTT2013Force)
  266. {
  267. reader.Version = JT808Version.JTT2013;
  268. writer.WriteString("版本号", JT808Version.JTT2013.ToString());
  269. writer.WriteNumber("[bit15]保留", 0);
  270. writer.WriteNumber("[bit14]保留", 0);
  271. writer.WriteBoolean("[bit13]是否分包", headerMessageBodyProperty.IsPackage);
  272. writer.WriteString("[bit10~bit12]数据加密", headerMessageBodyProperty.Encrypt.ToString());
  273. writer.WriteNumber("[bit0~bit9]消息体长度", headerMessageBodyProperty.DataLength);
  274. writer.WriteEndObject();
  275. //2013版本
  276. // 3.3.读取终端手机号
  277. var terminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, false);
  278. //消息体属性对象 结束
  279. writer.WriteString($"[{terminalPhoneNo.PadLeft(config.TerminalPhoneNoLength, '0')}]终端手机号", terminalPhoneNo);
  280. }
  281. else
  282. {
  283. if (reader.Version == JT808Version.JTT2019 || headerMessageBodyProperty.VersionFlag)
  284. {
  285. reader.Version = JT808Version.JTT2019;
  286. writer.WriteString("版本号", JT808Version.JTT2019.ToString());
  287. writer.WriteNumber("[bit15]保留", 0);
  288. writer.WriteBoolean("[bit14]协议版本标识", headerMessageBodyProperty.VersionFlag);
  289. writer.WriteBoolean("[bit13]是否分包", headerMessageBodyProperty.IsPackage);
  290. writer.WriteString("[bit10~bit12]数据加密", headerMessageBodyProperty.Encrypt.ToString());
  291. writer.WriteNumber("[bit0~bit9]消息体长度", headerMessageBodyProperty.DataLength);
  292. //消息体属性对象 结束
  293. writer.WriteEndObject();
  294. //2019版本
  295. var protocolVersion = reader.ReadByte();
  296. writer.WriteNumber($"[{protocolVersion.ReadNumber()}]协议版本号(2019)", protocolVersion);
  297. // 3.4.读取终端手机号
  298. var terminalPhoneNo = reader.ReadBCD(20, config.Trim);
  299. writer.WriteString($"[{terminalPhoneNo.PadLeft(20, '0')}]终端手机号", terminalPhoneNo);
  300. }
  301. else
  302. {
  303. reader.Version = JT808Version.JTT2013;
  304. writer.WriteString("版本号", JT808Version.JTT2013.ToString());
  305. writer.WriteNumber("[bit15]保留", 0);
  306. writer.WriteNumber("[bit14]保留", 0);
  307. writer.WriteBoolean("[bit13]是否分包", headerMessageBodyProperty.IsPackage);
  308. writer.WriteString("[bit10~bit12]数据加密", headerMessageBodyProperty.Encrypt.ToString());
  309. writer.WriteNumber("[bit0~bit9]消息体长度", headerMessageBodyProperty.DataLength);
  310. writer.WriteEndObject();
  311. //2013版本
  312. // 3.3.读取终端手机号
  313. var terminalPhoneNo = reader.ReadBCD(config.TerminalPhoneNoLength, false);
  314. //消息体属性对象 结束
  315. writer.WriteString($"[{terminalPhoneNo.PadLeft(config.TerminalPhoneNoLength, '0')}]终端手机号", terminalPhoneNo);
  316. }
  317. }
  318. // 3.4.读取消息流水号
  319. var msgNum = reader.ReadUInt16();
  320. writer.WriteNumber($"[{msgNum.ReadNumber()}]消息流水号", msgNum);
  321. // 3.5.判断有无分包
  322. uint packgeCount = 0, packageIndex = 0;
  323. if (headerMessageBodyProperty.IsPackage)
  324. {
  325. //3.5.1.读取消息包总数
  326. packgeCount = reader.ReadUInt16();
  327. writer.WriteNumber($"[{packgeCount.ReadNumber()}]消息包总数", packgeCount);
  328. //3.5.2.读取消息包序号
  329. packageIndex = reader.ReadUInt16();
  330. writer.WriteNumber($"[{packageIndex.ReadNumber()}]消息包序号", packageIndex);
  331. }
  332. // 4.处理数据体
  333. // 4.1.判断有无数据体
  334. if (headerMessageBodyProperty.DataLength > 0)
  335. {
  336. //数据体属性对象 开始
  337. writer.WriteStartObject("数据体对象");
  338. string description = "数据体";
  339. if (headerMessageBodyProperty.IsPackage)
  340. {
  341. //读取分包的数据体
  342. try
  343. {
  344. writer.WriteString($"[分包]数据体", reader.ReadArray(reader.ReadCurrentRemainContentLength()).ToArray().ToHexString());
  345. }
  346. catch (IndexOutOfRangeException ex)
  347. {
  348. writer.WriteString($"数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  349. }
  350. catch (ArgumentOutOfRangeException ex)
  351. {
  352. writer.WriteString($"[分包]数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  353. }
  354. catch (Exception ex)
  355. {
  356. writer.WriteString($"[分包]数据体异常", ex.StackTrace);
  357. }
  358. }
  359. else
  360. {
  361. if (config.MsgIdFactory.TryGetValue(msgid, out object instance))
  362. {
  363. if (instance is IJT808Description jT808Description)
  364. {
  365. //4.2.处理消息体
  366. description = jT808Description.Description;
  367. }
  368. try
  369. {
  370. //数据体长度正常
  371. writer.WriteString($"{description}", reader.ReadVirtualArray(reader.ReadCurrentRemainContentLength()).ToArray().ToHexString());
  372. if (instance is IJT808Analyze analyze)
  373. {
  374. //4.2.处理消息体
  375. analyze.Analyze(ref reader, writer, config);
  376. }
  377. }
  378. catch (IndexOutOfRangeException ex)
  379. {
  380. writer.WriteString($"数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  381. }
  382. catch (ArgumentOutOfRangeException ex)
  383. {
  384. writer.WriteString($"数据体解析异常,无可用数据体进行解析", ex.StackTrace);
  385. }
  386. catch (Exception ex)
  387. {
  388. writer.WriteString($"数据体异常", ex.StackTrace);
  389. }
  390. }
  391. else
  392. {
  393. writer.WriteString($"[未知]数据体", reader.ReadArray(reader.ReadCurrentRemainContentLength()).ToArray().ToHexString());
  394. }
  395. }
  396. //数据体属性对象 结束
  397. writer.WriteEndObject();
  398. }
  399. else
  400. {
  401. if (config.MsgIdFactory.TryGetValue(msgid, out object instance))
  402. {
  403. //数据体属性对象 开始
  404. writer.WriteStartObject("数据体对象");
  405. string description = "[Null]数据体";
  406. if (instance is IJT808Description jT808Description)
  407. {
  408. //4.2.处理消息体
  409. description = jT808Description.Description;
  410. }
  411. writer.WriteNull(description);
  412. //数据体属性对象 结束
  413. writer.WriteEndObject();
  414. }
  415. else
  416. {
  417. writer.WriteNull($"[Null]数据体");
  418. }
  419. }
  420. try
  421. {
  422. // 5.读取校验码
  423. reader.ReadByte();
  424. writer.WriteNumber($"[{reader.RealCheckXorCode.ReadNumber()}]校验码", reader.RealCheckXorCode);
  425. // 6.读取终止位置
  426. byte end = reader.ReadEnd();
  427. writer.WriteNumber($"[{end.ReadNumber()}]结束", end);
  428. }
  429. catch (ArgumentOutOfRangeException ex)
  430. {
  431. writer.WriteString($"数据解析异常,无可用数据进行解析", ex.StackTrace);
  432. }
  433. catch (Exception ex)
  434. {
  435. writer.WriteString($"数据解析异常", ex.StackTrace);
  436. }
  437. finally
  438. {
  439. writer.WriteEndObject();
  440. }
  441. }
  442. }
  443. }