using Edge.Core.Processor.Communicator; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HengshanPaymentTerminal { public class StateMachineMessageCutter : IMessageCutter { #region Internal State enum private enum State { Uninitialized, LengthReady, BodyReady, EtxReady, CrcReady } #endregion #region Fields public byte[] Message { get; private set; } public event EventHandler OnMessageCut; public event EventHandler OnInvalidMessageRead; private string loggerAppendix = "HengshanPay Terminal"; private readonly SizableWindow window; //private State nextState = State.Uninitialized; private const int STX = 0xFA; #endregion #region Logger static NLog.Logger innerLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("Communicator"); #endregion public StateMachineMessageCutter() { window = new SizableWindow(); window.OnWindowFull += (data) => { byte[] tempBytes = window.ToArray(); string receiveStr = BitConverter.ToString(tempBytes).Replace("-", " "); innerLogger.Info($"receive data : ${receiveStr}"); //查找包头位置 int findIndex = -1; for (int index = 0;index < tempBytes.Length - 1;index++) { if (tempBytes[index] == STX && tempBytes[index + 1] != STX) { findIndex = index; break; } } innerLogger.Info($"find head index = ${findIndex}"); //若没有找到包头,证明目前缓存中都是垃圾数据,清掉 if (findIndex == -1) { window.RemoveRange(0, tempBytes.Length); return; } //长度不够表示有粘包,部分数据还未接收到,等待下一轮接收数据再处理 //1byte FA + 1 byte 目标地址 + 1 byte 源地址 + 1 byte 帧号 + 2 byte 有效数据长度 + 2 byte 数据校验 = 8byte if(findIndex + 8 > tempBytes.Length) { innerLogger.Info($"Insufficient data length,at least ,need {findIndex + 8},but length is {tempBytes.Length}"); return; } //获取有效数据长度 int dataLen = Bcd2Int(tempBytes[4], tempBytes[5]); byte[] reduceFAData = Reduce0xFAPair(tempBytes); string reduceFADataStr = BitConverter.ToString(reduceFAData).Replace("-", " "); innerLogger.Info($"data length is ${dataLen},reduceFAData len is ${reduceFAData.Length},value is ${reduceFADataStr}"); //去除多余FA后,实际数据不足有效数据长度,表示有粘包,仍非完整数据,等待下一轮接收数据再处理 if(reduceFAData.Length < dataLen + 2) { innerLogger.Info("Insufficient data length"); return; } //计算crc,若值对应不上,表示数据错误 ushort calculatorValue = HengshanCRC16.ComputeChecksum(reduceFAData.AsSpan(1,reduceFAData.Length - 3).ToArray()); byte highByte = reduceFAData[reduceFAData.Length - 2]; byte lowByte = reduceFAData[reduceFAData.Length - 1]; int crcValue = (highByte << 8) | lowByte; if (calculatorValue != crcValue) { innerLogger.Info($"crc value error,get value is {crcValue},calculator value is {calculatorValue}"); window.RemoveRange(0, tempBytes.Length); return; } //获取到实际数据包,并将缓存数据删除 Message = reduceFAData; var safe = OnMessageCut; safe?.Invoke(this, null); window.RemoveRange(0, tempBytes.Length); }; } public void Feed(byte[] data) { List list = new(data); window.Add(list); //for (int i = 0; i < data.Length; i++) //{ // window.Add(data[i]); //} } private int Get0xFAPairCountInWindow(IEnumerable data) { return (int)Math.Round(((double)(data.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero); } /// /// 删除多余的FA,在接收到的一个完整数据包中,数据包头为FA,其余数据中每一个FA会替换为两个FA,这里要删除多余的fa来获取实际数据包 /// /// 原数据包 /// public byte[] Reduce0xFAPair(byte[] data) { List list = new(); for (int index = 0; index < data.Length; index++) { if (index < data.Length -1 && data[index] == STX && data[index + 1] == STX) { list.Add(STX); index++; } else { list.Add(data[index]); } } return list.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; } } }