using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Buffers.Binary;
using System.Buffers;
namespace JT809.Protocol.JT809Extensions
{
public static class JT809BinaryExtensions
{
///
/// 日期限制于2000年
///
private const int DateLimitYear = 2000;
private const ushort cnCRC_CCITT = 0x1021; //CRC校验多项式
private static ulong[] CRC = new ulong[256]; //建立CRC16表
static JT809BinaryExtensions()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
encoding = Encoding.GetEncoding("GBK");
ushort i, j;
ushort nData;
ushort nAccum;
for (i = 0; i < 256; i++)
{
nData = (ushort)(i << 8);
nAccum = 0;
for (j = 0; j < 8; j++)
{
if (((nData ^ nAccum) & 0x8000) > 0)
nAccum = (ushort)((nAccum << 1) ^ cnCRC_CCITT);
else
nAccum <<= 1;
nData <<= 1;
}
CRC[i] = (ulong)nAccum;
}
}
private static Encoding encoding;
public static int ReadBCD32(this byte data, byte dig)
{
int result = Convert.ToInt32(data.ToString("X"));
return result * (int)Math.Pow(100, dig - 1);
}
public static int ReadBCD32(ReadOnlySpan read, ref int offset, int len)
{
int result = Convert.ToInt32(read[offset].ToString("X"));
offset += len;
return result * (int)Math.Pow(100, len - 1);
}
public static long ReadBCD64(this byte data, byte dig)
{
long result = Convert.ToInt64(data.ToString("X"));
return result * (long)Math.Pow(100, dig - 1);
}
public static string ReadStringLittle(ReadOnlySpan read, ref int offset, int len)
{
string value = encoding.GetString(read.Slice(offset, len).ToArray());
offset += len;
return value.Trim('\0');
}
public static string ReadStringLittle(ReadOnlySpan read, ref int offset)
{
string value = encoding.GetString(read.Slice(offset).ToArray());
offset += value.Length;
return value.Trim('\0');
}
public static long ReadBCD(ReadOnlySpan buf, ref int offset, int len)
{
long result = 0;
try
{
for (int i = offset; i < offset + len; i++)
{
result += buf[i].ReadBCD64((byte)(offset + len - i));
}
}
catch
{
}
offset = offset + len;
return result;
}
public static DateTime ReadDateTimeLittle(ReadOnlySpan buf, ref int offset)
{
DateTime dateTime = new DateTime(
(buf[offset]).ReadBCD32(1) + DateLimitYear,
(buf[offset + 1]).ReadBCD32(1),
(buf[offset + 2]).ReadBCD32(1),
(buf[offset + 3]).ReadBCD32(1),
(buf[offset + 4]).ReadBCD32(1),
(buf[offset + 5]).ReadBCD32(1));
offset = offset + 6;
return dateTime;
}
public static DateTime ReadDateLittle(ReadOnlySpan buf, ref int offset)
{
DateTime dateTime = new DateTime(
((buf[offset] << 8) | (buf[offset + 1])),
(buf[offset + 2]).ReadBCD32(1),
(buf[offset + 3]).ReadBCD32(1));
offset = offset + 4;
return dateTime;
}
public static int ReadInt32Little(ReadOnlySpan read, ref int offset)
{
int value = (read[offset] << 24) | (read[offset + 1] << 16) | (read[offset + 2] << 8) | read[offset + 3];
offset = offset + 4;
return value;
}
public static uint ReadUInt32Little(ReadOnlySpan read, ref int offset)
{
uint value = (uint)((read[offset] << 24) | (read[offset + 1] << 16) | (read[offset + 2] << 8) | read[offset + 3]);
offset = offset + 4;
return value;
}
public static ulong ReadUInt64Little(ReadOnlySpan read, ref int offset)
{
ulong value = (ulong)(
(read[offset] << 56) |
(read[offset + 1] << 48) |
(read[offset + 2] << 40) |
(read[offset + 3] << 32) |
(read[offset + 4] << 24) |
(read[offset + 5] << 16) |
(read[offset + 6] << 8) |
read[offset + 7]);
offset = offset + 8;
return value;
}
public static ushort ReadUInt16Little(ReadOnlySpan read, ref int offset)
{
ushort value = (ushort)((read[offset] << 8) | (read[offset + 1]));
offset = offset + 2;
return value;
}
public static byte ReadByteLittle(ReadOnlySpan read, ref int offset)
{
byte value = read[offset];
offset = offset + 1;
return value;
}
public static byte[] ReadBytesLittle(ReadOnlySpan read, ref int offset, int len)
{
ReadOnlySpan temp = read.Slice(offset, len);
offset = offset + len;
return temp.ToArray();
}
///
/// 数字编码 大端模式、高位在前
///
///
///
///
///
public static string ReadBigNumberLittle(ReadOnlySpan read, ref int offset, int len)
{
ulong result = 0;
for (int i = 0; i < len; i++)
{
ulong currentData = (ulong)read[offset+i] << (8 * (len - i - 1));
result += currentData;
}
offset += len;
return result.ToString();
}
///
/// 数字编码 小端模式、低位在前
///
///
///
///
///
public static string ReadLowNumberLittle(ReadOnlySpan read, ref int offset, int len)
{
ulong result = 0;
for (int i = 0; i < len; i++)
{
ulong currentData = (ulong)read[offset+i] << (8 * i);
result += currentData;
}
offset += len;
return result.ToString();
}
public static int WriteDateTime6Little(IMemoryOwner memoryOwner, int offset, DateTime date)
{
memoryOwner.Memory.Span[offset] = ((byte)(date.Year - DateLimitYear)).ToBcdByte();
memoryOwner.Memory.Span[offset + 1] = ((byte)(date.Month)).ToBcdByte();
memoryOwner.Memory.Span[offset + 2] = ((byte)(date.Day)).ToBcdByte();
memoryOwner.Memory.Span[offset + 3] = ((byte)(date.Hour)).ToBcdByte();
memoryOwner.Memory.Span[offset + 4] = ((byte)(date.Minute)).ToBcdByte();
memoryOwner.Memory.Span[offset + 5] = ((byte)(date.Second)).ToBcdByte();
return 6;
}
public static int WriteDateTime4Little(IMemoryOwner memoryOwner, int offset, DateTime date)
{
memoryOwner.Memory.Span[offset] = (byte)(date.Year >> 8);
memoryOwner.Memory.Span[offset + 1] = (byte)date.Year;
memoryOwner.Memory.Span[offset + 2] = ((byte)(date.Month)).ToBcdByte();
memoryOwner.Memory.Span[offset + 3] = ((byte)(date.Day)).ToBcdByte();
return 4;
}
public static int WriteInt32Little(IMemoryOwner memoryOwner, int offset, int data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 24);
memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 16);
memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 3] = (byte)data;
return 4;
}
public static int WriteUInt32Little(IMemoryOwner memoryOwner, int offset, uint data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 24);
memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 16);
memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 3] = (byte)data;
return 4;
}
public static int WriteUInt64Little(IMemoryOwner memoryOwner, int offset, ulong data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 56);
memoryOwner.Memory.Span[offset + 1] = (byte)(data >> 48);
memoryOwner.Memory.Span[offset + 2] = (byte)(data >> 40);
memoryOwner.Memory.Span[offset + 3] = (byte)(data >> 32);
memoryOwner.Memory.Span[offset + 4] = (byte)(data >> 24);
memoryOwner.Memory.Span[offset + 5] = (byte)(data >> 16);
memoryOwner.Memory.Span[offset + 6] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 7] = (byte)data;
return 8;
}
public static int WriteUInt16Little(IMemoryOwner memoryOwner, int offset, ushort data)
{
memoryOwner.Memory.Span[offset] = (byte)(data >> 8);
memoryOwner.Memory.Span[offset + 1] = (byte)data;
return 2;
}
public static int WriteByteLittle(IMemoryOwner memoryOwner, int offset, byte data)
{
memoryOwner.Memory.Span[offset] = data;
return 1;
}
public static int WriteBytesLittle(IMemoryOwner memoryOwner, int offset, byte[] data)
{
CopyTo(data, memoryOwner.Memory.Span, offset);
return data.Length;
}
public static int WriteStringLittle(IMemoryOwner memoryOwner, int offset, string data)
{
byte[] codeBytes = encoding.GetBytes(data);
CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
return codeBytes.Length;
}
public static int WriteStringLittle(IMemoryOwner memoryOwner, int offset, string data, int len)
{
byte[] bytes = null;
if (string.IsNullOrEmpty(data))
{
bytes = new byte[0];
}
else
{
bytes = encoding.GetBytes(data);
}
byte[] rBytes = new byte[len];
for (int i = 0; i < bytes.Length; i++)
{
if (i >= len) break;
rBytes[i] = bytes[i];
}
CopyTo(rBytes, memoryOwner.Memory.Span, offset);
return rBytes.Length;
}
public static int WriteStringPadLeftLittle(IMemoryOwner memoryOwner, int offset, string data, int len)
{
data = data.PadLeft(len, '\0');
byte[] codeBytes = encoding.GetBytes(data);
CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
return codeBytes.Length;
}
public static int WriteStringPadRightLittle(IMemoryOwner memoryOwner, int offset, string data, int len)
{
data = data.PadRight(len, '\0');
byte[] codeBytes = encoding.GetBytes(data);
CopyTo(codeBytes, memoryOwner.Memory.Span, offset);
return codeBytes.Length;
}
public static int WriteBCDLittle(IMemoryOwner memoryOwner, int offset, string data, int digit, int len)
{
ReadOnlySpan bcd = data.PadLeft(len, '0').AsSpan();
for (int i = 0; i < digit; i++)
{
memoryOwner.Memory.Span[offset + i] = Convert.ToByte(bcd.Slice(i * 2, 2).ToString(), 16);
}
return digit;
}
///
/// 数字编码 大端模式、高位在前
///
///
///
///
///
///
public static int WriteBigNumberLittle(IMemoryOwner memoryOwner, int offset, string data, int len)
{
ulong number = string.IsNullOrEmpty(data) ? 0 : (ulong)double.Parse(data);
for (int i = len - 1; i >= 0; i--)
{
memoryOwner.Memory.Span[offset+i] = (byte)(number & 0xFF); //取低8位
number = number >> 8;
}
return len;
}
///
/// 数字编码 小端模式、低位在前
///
///
///
///
///
///
public static int WriteLowNumberLittle(IMemoryOwner memoryOwner, int offset, string data, int len)
{
ulong number = string.IsNullOrEmpty(data) ? 0 : (ulong)double.Parse(data);
for (int i = 0; i < len; i++)
{
memoryOwner.Memory.Span[offset + i] = (byte)(number & 0xFF); //取低8位
number = number >> 8;
}
return len;
}
public static IEnumerable ToBytes(this string data, Encoding coding)
{
return coding.GetBytes(data);
}
public static IEnumerable ToBytes(this string data)
{
return ToBytes(data, encoding);
}
public static IEnumerable ToBytes(this int data, int len)
{
List bytes = new List();
int n = 1;
for (int i = 0; i < len; i++)
{
bytes.Add((byte)(data >> 8 * (len - n)));
n++;
}
return bytes;
}
///
/// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。
///
///
///
///
///
///
public static ushort ToCRC16_CCITT(this Span ucbuf, int offset, int iLen)
{
ushort checkCode = 0xFFFF;
for (int j = offset; j < iLen; ++j)
{
checkCode = (ushort)((checkCode << 8) ^ (ushort)CRC[(checkCode >> 8) ^ ucbuf[j]]);
}
return checkCode;
}
///
/// 从数据头到校验码前的 CRC 1 G-CCITT 的校验值,遵循人端排序方式的规定。
///
///
///
///
///
///
public static ushort ToCRC16_CCITT(this ReadOnlySpan ucbuf, int offset, int iLen)
{
ushort checkCode = 0xFFFF;
for (int j = offset; j < iLen; ++j)
{
checkCode = (ushort)((checkCode << 8) ^ (ushort)CRC[(checkCode >> 8) ^ ucbuf[j]]);
}
return checkCode;
}
public static byte ToBcdByte(this byte buf)
{
return (byte)Convert.ToInt32(buf.ToString(), 16);
}
///
/// 经纬度
///
///
///
public static double ToLatLng(this int latlng)
{
return Math.Round(latlng / Math.Pow(10, 6), 6);
}
public static void CopyTo(Span source, Span destination, int offset)
{
for (int i = 0; i < source.Length; i++)
{
destination[offset + i] = source[i];
}
}
///
/// 字节数组转16进制字符串
///
///
/// 默认 " "
///
public static string ToHexString(this byte[] bytes, string separator = " ")
{
return string.Join(separator, bytes.Select(s => s.ToString("X2")));
}
///
/// 16进制字符串转16进制数组
///
///
///
///
public static byte[] ToHexBytes(this string hexString, string separator = " ")
{
return hexString.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToByte(s, 16)).ToArray();
}
///
/// 16进制字符串转16进制数组
///
///
///
public static byte[] ToStr2HexBytes(this string hexString)
{
//byte[] buf = new byte[hexString.Length / 2];
//for (int i = 0; i < hexString.Length; i++)
//{
// if (i % 2 == 0)
// {
// buf[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16) ;
// }
//}
byte[] buf = new byte[hexString.Length / 2];
ReadOnlySpan readOnlySpan = hexString.AsSpan();
for (int i = 0; i < hexString.Length; i++)
{
if (i % 2 == 0)
{
buf[i / 2] = Convert.ToByte(readOnlySpan.Slice(i, 2).ToString(), 16);
}
}
return buf;
//List bytes = new List();
//while (hexString.Length>0)
//{
// bytes.Add(Convert.ToByte(hexString.AsSpan(0, 2).ToString(), 16));
// hexString = hexString.Remove(0,2);
//}
//return Regex.Replace(hexString, @"(\w{2})", "$1 ").Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToByte(s, 16)).ToArray();
}
}
}