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.

509 lines
18 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Buffers.Binary;
  6. using System.Buffers;
  7. namespace JT809.Protocol.JT809Extensions
  8. {
  9. public static class JT809BinaryExtensions
  10. {
  11. /// <summary>
  12. /// 日期限制于2000年
  13. /// </summary>
  14. private const int DateLimitYear = 2000;
  15. private const ushort cnCRC_CCITT = 0x1021; //CRC校验多项式
  16. private static ulong[] CRC = new ulong[256]; //建立CRC16表
  17. static JT809BinaryExtensions()
  18. {
  19. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
  20. encoding = Encoding.GetEncoding("GBK");
  21. ushort i, j;
  22. ushort nData;
  23. ushort nAccum;
  24. for (i = 0; i < 256; i++)
  25. {
  26. nData = (ushort)(i << 8);
  27. nAccum = 0;
  28. for (j = 0; j < 8; j++)
  29. {
  30. if (((nData ^ nAccum) & 0x8000) > 0)
  31. nAccum = (ushort)((nAccum << 1) ^ cnCRC_CCITT);
  32. else
  33. nAccum <<= 1;
  34. nData <<= 1;
  35. }
  36. CRC[i] = (ulong)nAccum;
  37. }
  38. }
  39. private static Encoding encoding;
  40. public static int ReadBCD32(this byte data, byte dig)
  41. {
  42. int result = Convert.ToInt32(data.ToString("X"));
  43. return result * (int)Math.Pow(100, dig - 1);
  44. }
  45. public static int ReadBCD32(ReadOnlySpan<byte> read, ref int offset, int len)
  46. {
  47. int result = Convert.ToInt32(read[offset].ToString("X"));
  48. offset += len;
  49. return result * (int)Math.Pow(100, len - 1);
  50. }
  51. public static long ReadBCD64(this byte data, byte dig)
  52. {
  53. long result = Convert.ToInt64(data.ToString("X"));
  54. return result * (long)Math.Pow(100, dig - 1);
  55. }
  56. public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset, int len)
  57. {
  58. string value = encoding.GetString(read.Slice(offset, len).ToArray());
  59. offset += len;
  60. return value.Trim('\0');
  61. }
  62. public static string ReadStringLittle(ReadOnlySpan<byte> read, ref int offset)
  63. {
  64. string value = encoding.GetString(read.Slice(offset).ToArray());
  65. offset += value.Length;
  66. return value.Trim('\0');
  67. }
  68. public static long ReadBCD(ReadOnlySpan<byte> buf, ref int offset, int len)
  69. {
  70. long result = 0;
  71. try
  72. {
  73. for (int i = offset; i < offset + len; i++)
  74. {
  75. result += buf[i].ReadBCD64((byte)(offset + len - i));
  76. }
  77. }
  78. catch
  79. {
  80. }
  81. offset = offset + len;
  82. return result;
  83. }
  84. public static DateTime ReadDateTimeLittle(ReadOnlySpan<byte> buf, ref int offset)
  85. {
  86. DateTime dateTime = new DateTime(
  87. (buf[offset]).ReadBCD32(1) + DateLimitYear,
  88. (buf[offset + 1]).ReadBCD32(1),
  89. (buf[offset + 2]).ReadBCD32(1),
  90. (buf[offset + 3]).ReadBCD32(1),
  91. (buf[offset + 4]).ReadBCD32(1),
  92. (buf[offset + 5]).ReadBCD32(1));
  93. offset = offset + 6;
  94. return dateTime;
  95. }
  96. public static DateTime ReadDateLittle(ReadOnlySpan<byte> buf, ref int offset)
  97. {
  98. DateTime dateTime = new DateTime(
  99. ((buf[offset] << 8) | (buf[offset + 1])),
  100. (buf[offset + 2]).ReadBCD32(1),
  101. (buf[offset + 3]).ReadBCD32(1));
  102. offset = offset + 4;
  103. return dateTime;
  104. }
  105. public static int ReadInt32Little(ReadOnlySpan<byte> read, ref int offset)
  106. {
  107. int value = (read[offset] << 24) | (read[offset + 1] << 16) | (read[offset + 2] << 8) | read[offset + 3];
  108. offset = offset + 4;
  109. return value;
  110. }
  111. public static uint ReadUInt32Little(ReadOnlySpan<byte> read, ref int offset)
  112. {
  113. uint value = (uint)((read[offset] << 24) | (read[offset + 1] << 16) | (read[offset + 2] << 8) | read[offset + 3]);
  114. offset = offset + 4;
  115. return value;
  116. }
  117. public static ulong ReadUInt64Little(ReadOnlySpan<byte> read, ref int offset)
  118. {
  119. ulong value = (ulong)(
  120. (read[offset] << 56) |
  121. (read[offset + 1] << 48) |
  122. (read[offset + 2] << 40) |
  123. (read[offset + 3] << 32) |
  124. (read[offset + 4] << 24) |
  125. (read[offset + 5] << 16) |
  126. (read[offset + 6] << 8) |
  127. read[offset + 7]);
  128. offset = offset + 8;
  129. return value;
  130. }
  131. public static ushort ReadUInt16Little(ReadOnlySpan<byte> read, ref int offset)
  132. {
  133. ushort value = (ushort)((read[offset] << 8) | (read[offset + 1]));
  134. offset = offset + 2;
  135. return value;
  136. }
  137. public static byte ReadByteLittle(ReadOnlySpan<byte> read, ref int offset)
  138. {
  139. byte value = read[offset];
  140. offset = offset + 1;
  141. return value;
  142. }
  143. public static byte[] ReadBytesLittle(ReadOnlySpan<byte> read, ref int offset, int len)
  144. {
  145. ReadOnlySpan<byte> temp = read.Slice(offset, len);
  146. offset = offset + len;
  147. return temp.ToArray();
  148. }
  149. /// <summary>
  150. /// 数字编码 大端模式、高位在前
  151. /// </summary>
  152. /// <param name="read"></param>
  153. /// <param name="offset"></param>
  154. /// <param name="len"></param>
  155. /// <returns></returns>
  156. public static string ReadBigNumberLittle(ReadOnlySpan<byte> read, ref int offset, int len)
  157. {
  158. ulong result = 0;
  159. for (int i = 0; i < len; i++)
  160. {
  161. ulong currentData = (ulong)read[offset+i] << (8 * (len - i - 1));
  162. result += currentData;
  163. }
  164. offset += len;
  165. return result.ToString();
  166. }
  167. /// <summary>
  168. /// 数字编码 小端模式、低位在前
  169. /// </summary>
  170. /// <param name="read"></param>
  171. /// <param name="offset"></param>
  172. /// <param name="len"></param>
  173. /// <returns></returns>
  174. public static string ReadLowNumberLittle(ReadOnlySpan<byte> read, ref int offset, int len)
  175. {
  176. ulong result = 0;
  177. for (int i = 0; i < len; i++)
  178. {
  179. ulong currentData = (ulong)read[offset+i] << (8 * i);
  180. result += currentData;
  181. }
  182. offset += len;
  183. return result.ToString();
  184. }
  185. public static int WriteDateTime6Little(IMemoryOwner<byte> memoryOwner, int offset, DateTime date)
  186. {
  187. memoryOwner.Memory.Span[offset] = ((byte)(date.Year - DateLimitYear)).ToBcdByte();
  188. memoryOwner.Memory.Span[offset + 1] = ((byte)(date.Month)).ToBcdByte();
  189. memoryOwner.Memory.Span[offset + 2] = ((byte)(date.Day)).ToBcdByte();
  190. memoryOwner.Memory.Span[offset + 3] = ((byte)(date.Hour)).ToBcdByte();
  191. memoryOwner.Memory.Span[offset + 4] = ((byte)(date.Minute)).ToBcdByte();
  192. memoryOwner.Memory.Span[offset + 5] = ((byte)(date.Second)).ToBcdByte();
  193. return 6;
  194. }
  195. public static int WriteDateTime4Little(IMemoryOwner<byte> memoryOwner, int offset, DateTime date)
  196. {
  197. memoryOwner.Memory.Span[offset] = (byte)(date.Year >> 8);
  198. memoryOwner.Memory.Span[offset + 1] = (byte)date.Year;
  199. memoryOwner.Memory.Span[offset + 2] = ((byte)(date.Month)).ToBcdByte();
  200. memoryOwner.Memory.Span[offset + 3] = ((byte)(date.Day)).ToBcdByte();
  201. return 4;
  202. }
  203. public static int WriteInt32Little(IMemoryOwner<byte> memoryOwner, int offset, int data)
  204. {
  205. memoryOwner.Memory.Span[offset] = (byte)(data >> 24);
  206. memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 16);
  207. memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 8);
  208. memoryOwner.Memory.Span[offset + 3] = (byte)data;
  209. return 4;
  210. }
  211. public static int WriteUInt32Little(IMemoryOwner<byte> memoryOwner, int offset, uint data)
  212. {
  213. memoryOwner.Memory.Span[offset] = (byte)(data >> 24);
  214. memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 16);
  215. memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 8);
  216. memoryOwner.Memory.Span[offset + 3] = (byte)data;
  217. return 4;
  218. }
  219. public static int WriteUInt64Little(IMemoryOwner<byte> memoryOwner, int offset, ulong data)
  220. {
  221. memoryOwner.Memory.Span[offset] = (byte)(data >> 56);
  222. memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 48);
  223. memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 40);
  224. memoryOwner.Memory.Span[offset + 3] = (byte)(data >> 32);
  225. memoryOwner.Memory.Span[offset + 4] = (byte)(data >> 24);
  226. memoryOwner.Memory.Span[offset + 5] = (byte)(data >> 16);
  227. memoryOwner.Memory.Span[offset + 6] = (byte)(data >> 8);
  228. memoryOwner.Memory.Span[offset + 7] = (byte)data;
  229. return 8;
  230. }
  231. public static int WriteUInt16Little(IMemoryOwner<byte> memoryOwner, int offset, ushort data)
  232. {
  233. memoryOwner.Memory.Span[offset] = (byte)(data >> 8);
  234. memoryOwner.Memory.Span[offset + 1] = (byte)data;
  235. return 2;
  236. }
  237. public static int WriteByteLittle(IMemoryOwner<byte> memoryOwner, int offset, byte data)
  238. {
  239. memoryOwner.Memory.Span[offset] = data;
  240. return 1;
  241. }
  242. public static int WriteBytesLittle(IMemoryOwner<byte> memoryOwner, int offset, byte[] data)
  243. {
  244. CopyTo(data, memoryOwner.Memory.Span, offset);
  245. return data.Length;
  246. }
  247. public static int WriteStringLittle(IMemoryOwner<byte> memoryOwner, int offset, string data)
  248. {
  249. byte[] codeBytes = encoding.GetBytes(data);
  250. CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
  251. return codeBytes.Length;
  252. }
  253. public static int WriteStringLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len)
  254. {
  255. byte[] bytes = null;
  256. if (string.IsNullOrEmpty(data))
  257. {
  258. bytes = new byte[0];
  259. }
  260. else
  261. {
  262. bytes = encoding.GetBytes(data);
  263. }
  264. byte[] rBytes = new byte[len];
  265. for (int i = 0; i < bytes.Length; i++)
  266. {
  267. if (i >= len) break;
  268. rBytes[i] = bytes[i];
  269. }
  270. CopyTo(rBytes, memoryOwner.Memory.Span, offset);
  271. return rBytes.Length;
  272. }
  273. public static int WriteStringPadLeftLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len)
  274. {
  275. data = data.PadLeft(len, '\0');
  276. byte[] codeBytes = encoding.GetBytes(data);
  277. CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
  278. return codeBytes.Length;
  279. }
  280. public static int WriteStringPadRightLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len)
  281. {
  282. data = data.PadRight(len, '\0');
  283. byte[] codeBytes = encoding.GetBytes(data);
  284. CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
  285. return codeBytes.Length;
  286. }
  287. public static int WriteBCDLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int digit, int len)
  288. {
  289. ReadOnlySpan<char> bcd = data.PadLeft(len, '0').AsSpan();
  290. for (int i = 0; i < digit; i++)
  291. {
  292. memoryOwner.Memory.Span[offset + i] = Convert.ToByte(bcd.Slice(i * 2, 2).ToString(), 16);
  293. }
  294. return digit;
  295. }
  296. /// <summary>
  297. /// 数字编码 大端模式、高位在前
  298. /// </summary>
  299. /// <param name="memoryOwner"></param>
  300. /// <param name="offset"></param>
  301. /// <param name="data"></param>
  302. /// <param name="len"></param>
  303. /// <returns></returns>
  304. public static int WriteBigNumberLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len)
  305. {
  306. ulong number = string.IsNullOrEmpty(data) ? 0 : (ulong)double.Parse(data);
  307. for (int i = len - 1; i >= 0; i--)
  308. {
  309. memoryOwner.Memory.Span[offset+i] = (byte)(number & 0xFF); //取低8位
  310. number = number >> 8;
  311. }
  312. return len;
  313. }
  314. /// <summary>
  315. /// 数字编码 小端模式、低位在前
  316. /// </summary>
  317. /// <param name="memoryOwner"></param>
  318. /// <param name="offset"></param>
  319. /// <param name="data"></param>
  320. /// <param name="len"></param>
  321. /// <returns></returns>
  322. public static int WriteLowNumberLittle(IMemoryOwner<byte> memoryOwner, int offset, string data, int len)
  323. {
  324. ulong number = string.IsNullOrEmpty(data) ? 0 : (ulong)double.Parse(data);
  325. for (int i = 0; i < len; i++)
  326. {
  327. memoryOwner.Memory.Span[offset + i] = (byte)(number & 0xFF); //取低8位
  328. number = number >> 8;
  329. }
  330. return len;
  331. }
  332. public static IEnumerable<byte> ToBytes(this string data, Encoding coding)
  333. {
  334. return coding.GetBytes(data);
  335. }
  336. public static IEnumerable<byte> ToBytes(this string data)
  337. {
  338. return ToBytes(data, encoding);
  339. }
  340. public static IEnumerable<byte> ToBytes(this int data, int len)
  341. {
  342. List<byte> bytes = new List<byte>();
  343. int n = 1;
  344. for (int i = 0; i < len; i++)
  345. {
  346. bytes.Add((byte)(data >> 8 * (len - n)));
  347. n++;
  348. }
  349. return bytes;
  350. }
  351. /// <summary>
  352. /// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。
  353. /// </summary>
  354. /// <param name="packege"></param>
  355. /// <param name="ucbuf"></param>
  356. /// <param name="offset"></param>
  357. /// <param name="iLen"></param>
  358. /// <returns></returns>
  359. public static ushort ToCRC16_CCITT(this Span<byte> ucbuf, int offset, int iLen)
  360. {
  361. ushort checkCode = 0xFFFF;
  362. for (int j = offset; j < iLen; ++j)
  363. {
  364. checkCode = (ushort)((checkCode << 8) ^ (ushort)CRC[(checkCode >> 8) ^ ucbuf[j]]);
  365. }
  366. return checkCode;
  367. }
  368. /// <summary>
  369. /// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。
  370. /// </summary>
  371. /// <param name="packege"></param>
  372. /// <param name="ucbuf"></param>
  373. /// <param name="offset"></param>
  374. /// <param name="iLen"></param>
  375. /// <returns></returns>
  376. public static ushort ToCRC16_CCITT(this ReadOnlySpan<byte> ucbuf, int offset, int iLen)
  377. {
  378. ushort checkCode = 0xFFFF;
  379. for (int j = offset; j < iLen; ++j)
  380. {
  381. checkCode = (ushort)((checkCode << 8) ^ (ushort)CRC[(checkCode >> 8) ^ ucbuf[j]]);
  382. }
  383. return checkCode;
  384. }
  385. public static byte ToBcdByte(this byte buf)
  386. {
  387. return (byte)Convert.ToInt32(buf.ToString(), 16);
  388. }
  389. /// <summary>
  390. /// 经纬度
  391. /// </summary>
  392. /// <param name="latlng"></param>
  393. /// <returns></returns>
  394. public static double ToLatLng(this int latlng)
  395. {
  396. return Math.Round(latlng / Math.Pow(10, 6), 6);
  397. }
  398. public static void CopyTo(Span<byte> source, Span<byte> destination, int offset)
  399. {
  400. for (int i = 0; i < source.Length; i++)
  401. {
  402. destination[offset + i] = source[i];
  403. }
  404. }
  405. /// <summary>
  406. /// 字节数组转16进制字符串
  407. /// </summary>
  408. /// <param name="bytes"></param>
  409. /// <param name="separator">默认 " "</param>
  410. /// <returns></returns>
  411. public static string ToHexString(this byte[] bytes, string separator = " ")
  412. {
  413. return string.Join(separator, bytes.Select(s => s.ToString("X2")));
  414. }
  415. /// <summary>
  416. /// 16进制字符串转16进制数组
  417. /// </summary>
  418. /// <param name="hexString"></param>
  419. /// <param name="separator"></param>
  420. /// <returns></returns>
  421. public static byte[] ToHexBytes(this string hexString, string separator = " ")
  422. {
  423. return hexString.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToByte(s, 16)).ToArray();
  424. }
  425. /// <summary>
  426. /// 16进制字符串转16进制数组
  427. /// </summary>
  428. /// <param name="hexString"></param>
  429. /// <returns></returns>
  430. public static byte[] ToStr2HexBytes(this string hexString)
  431. {
  432. //byte[] buf = new byte[hexString.Length / 2];
  433. //for (int i = 0; i < hexString.Length; i++)
  434. //{
  435. // if (i % 2 == 0)
  436. // {
  437. // buf[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16) ;
  438. // }
  439. //}
  440. byte[] buf = new byte[hexString.Length / 2];
  441. ReadOnlySpan<char> readOnlySpan = hexString.AsSpan();
  442. for (int i = 0; i < hexString.Length; i++)
  443. {
  444. if (i % 2 == 0)
  445. {
  446. buf[i / 2] = Convert.ToByte(readOnlySpan.Slice(i, 2).ToString(), 16);
  447. }
  448. }
  449. return buf;
  450. //List<byte> bytes = new List<byte>();
  451. //while (hexString.Length>0)
  452. //{
  453. // bytes.Add(Convert.ToByte(hexString.AsSpan(0, 2).ToString(), 16));
  454. // hexString = hexString.Remove(0,2);
  455. //}
  456. //return Regex.Replace(hexString, @"(\w{2})", "$1 ").Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToByte(s, 16)).ToArray();
  457. }
  458. }
  459. }