using Edge.Core.Parser; using Edge.Core.Parser.BinaryParser.MessageEntity; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace HengshanPaymentTerminal.MessageEntity { /// /// 与油机通讯的基础数据包对象 /// public abstract class CommonMessage: MessageTemplateBase { public enum Command { /// /// 通用应答命令字 /// COMMON = 0x55, /// /// 心跳命令字 /// HEART_BRET = 0x10, /// /// 油枪信息命令字 /// NOZZLE_INFO = 0x61, /// /// 油枪状态命令字 /// NOZZLE_STATE = 0x62, /// /// 发送二维码给油机命令字 /// SEND_QR_CODE = 0x63, /// /// 获取单价命令字 /// GET_PRICE = 0x64, /// /// 授权命令字 /// ACCREDIT = 0x65, /// /// 取消授权命令字 /// CANCEL_ACCREDIT = 0x66, /// /// 接收油机订单命令字 /// RECIEVE_TRANX = 0x18, /// /// 发送应付金额给油机命令字 /// SEND_NEED_AMOUNT = 0x19, /// /// 发送退款信息油机命令字 /// SEND_REFUND = 0x1A, } public enum ErrorType { DISCONNECT, TIMEOUT } /// /// 包头 0xFA /// public Byte Head { get; set; } = 0xFA; /// /// 目标地址 /// public Byte DestinationAddr { get; set; } = 0xFF; /// /// 源地址 /// public Byte SourceAddr { get; set; } = 0xE0; /// /// 帧号 /// public int FrameNum { get; set; } /// /// 有效数据长度,标识油机数据包中,有效数据的长度 /// public int DataLength { get; set; } /// /// 命令字,用来标识数据包传递的数据 /// public Byte Handle { get; set; } /// /// crc 校验值 /// public Byte[] CRC { get; set; } /// /// 是否为错误响应(与油机通讯协议无关) /// public bool IsError { get; set; } = false; /// /// 错误类型(与油机协议无关) /// public ErrorType TheErrorType { get; set; } /// /// 错误信息(与油机协议无关) /// public string ErrorMessage { get; set; } public CommonMessage getBaseData(byte[] data) { this.Head = data[0]; this.DestinationAddr = data[1]; this.SourceAddr = data[2]; this.FrameNum = data[3]; this.DataLength = Bcd2Int(data[4], data[5]); this.Handle = data[6]; this.CRC = new byte[]{ data[data.Length - 2],data[data.Length - 1] }; return this; } /// /// 传入有效数据,拼接为要发送给油机包 /// /// /// public byte[] content2data(byte[] content) { List list = new List(); //目标地址,源地址,帧号 byte[] head = new byte[] { this.SourceAddr, this.DestinationAddr, (byte)this.FrameNum }; byte[] length = Int2BCD(content.Length); list.AddRange(head); list.AddRange(length); list.AddRange(content); byte[] crc = HengshanCRC16.ComputeChecksumToBytes(list.ToArray()); list.AddRange(crc); List addFAList = addFA(list); addFAList.Insert(0,0xFA); return addFAList.ToArray(); } public int Bcd2Int(byte byte1, byte byte2) { // 提取第一个字节的高四位和低四位 int digit1 = (byte1 >> 4) & 0x0F; // 高四位 int digit2 = byte1 & 0x0F; // 低四位 // 提取第二个字节的高四位和低四位 int digit3 = (byte2 >> 4) & 0x0F; // 高四位 int digit4 = byte2 & 0x0F; // 低四位 // 组合成一个整数 int result = digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4; return result; } public byte[] Int2BCD(int number) { // 提取千位、百位、十位和个位 int thousands = number / 1000; int hundreds = (number / 100) % 10; int tens = (number / 10) % 10; int units = number % 10; // 将千位和百位组合成一个字节(千位在高四位,百位在低四位) byte firstByte = (byte)((thousands * 16) + hundreds); // 乘以16相当于左移4位 // 将十位和个位组合成一个字节(十位在高四位,个位在低四位) byte secondByte = (byte)((tens * 16) + units); // 返回结果数组 return new byte[] { firstByte, secondByte }; } /// /// 数组转数字 /// /// 数组 /// 开始的截取的下标 /// 截取长度 /// public T Bytes2Number(byte[] datas,int startIndex,int length) where T: unmanaged { int sizeOfT = Unsafe.SizeOf(); Span span = datas.AsSpan(startIndex, length); // 如果 span 的长度不够,补足长度 if (span.Length < sizeOfT) { // 使用数组而不是 stackalloc,避免栈溢出 byte[] paddedArray = new byte[sizeOfT]; Span paddedSpan = paddedArray.AsSpan(); // 在前面补零 span.CopyTo(paddedSpan.Slice(sizeOfT - span.Length)); if (BitConverter.IsLittleEndian) { // 小端序:反转字节顺序 paddedSpan.Reverse(); } return MemoryMarshal.Read(paddedSpan); } // 如果长度足够,直接读取 if (BitConverter.IsLittleEndian) { // 小端序:反转字节顺序 span.Reverse(); } return MemoryMarshal.Read(span); } public List addFA(List list) { List result = new List(); foreach (byte b in list) { if (b == 0xFA) { result.Add(0xFA); result.Add(0xFA); } else { result.Add(b); } } return result; } public DateTime bytes2DateTime(byte[] timeBytes) { string formate = "yyyyMMddHHmmss"; string timeStr = BitConverter.ToString(timeBytes).Replace("-", ""); DateTime parsedDateTime; bool success = DateTime.TryParseExact(timeStr, formate, null, System.Globalization.DateTimeStyles.None, out parsedDateTime); return success ? parsedDateTime : DateTime.Now; } /// /// 将数值转为byte[] /// /// 数值 /// 数组长度,不够高位补0 /// /// public static byte[] NumberToByteArrayWithPadding(int value, int length) { if (length < 0) { throw new ArgumentException("Length must be non-negative."); } // 创建一个指定长度的字节数组 byte[] paddedBytes = new byte[length]; // 确保是大端序 for (int i = 0; i < length && i < 4; i++) { paddedBytes[length - 1 - i] = (byte)(value >> (i * 8)); } return paddedBytes; } /// /// 将时间转为 BCD /// /// /// public static byte[] ConvertDateTimeToByteArray(DateTime dateTime) { // 创建byte数组 byte[] result = new byte[7]; // 年份处理 int year = dateTime.Year; result[0] = (byte)((year / 1000) * 16 + (year / 100) % 10); // 千年和百年 result[1] = (byte)((year / 10) % 10 * 16 + year % 10); // 十年和个年 // 月、日、小时、分钟、秒直接转换为BCD result[2] = (byte)(dateTime.Month / 10 * 16 + dateTime.Month % 10); result[3] = (byte)(dateTime.Day / 10 * 16 + dateTime.Day % 10); result[4] = (byte)(dateTime.Hour / 10 * 16 + dateTime.Hour % 10); result[5] = (byte)(dateTime.Minute / 10 * 16 + dateTime.Minute % 10); result[6] = (byte)(dateTime.Second / 10 * 16 + dateTime.Second % 10); return result; } public static byte[] FormatDecimal(decimal value) { // 四舍五入到两位小数 decimal roundedValue = Math.Round(value, 2, MidpointRounding.AwayFromZero); int valueInt = (int)(roundedValue * 100m); return NumberToByteArrayWithPadding(valueInt, 3); ; } } }