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 index = 0;//开始查找包头的下标 //循环处理,避免数据粘包发送过来时只处理了第一个包 while (true) { //查找包头位置 int fristIndex = -1; //第一个包头位置 int secondIndex = -1; //第二个包头位置 for (; index < tempBytes.Length - 1; index++) { //fa+fa,为数据中带fa,跳过多加的 1 byte Fa if (tempBytes[index] == STX && tempBytes[index+1] == STX) { index++; continue; } if (tempBytes[index] == STX && tempBytes[index + 1] != STX) // FA+非Fa ,包头 { if (fristIndex == -1) { fristIndex = index; } else { secondIndex = index; break; } } } //innerLogger.Info($"find head fristIndex = {fristIndex},secondIndex = {secondIndex}"); //若没有找到包头,证明目前缓存中都是垃圾数据,清掉 if (fristIndex == -1) { window.RemoveRange(0, tempBytes.Length); return; } //长度不够表示部分数据还未接收到,等待下一轮接收数据再处理 //1byte FA + 1 byte 目标地址 + 1 byte 源地址 + 1 byte 帧号 + 2 byte 有效数据长度 + 2 byte 数据校验 = 8byte if (fristIndex + 8 > tempBytes.Length) { innerLogger.Info($"Insufficient data length,at least ,need {fristIndex + 8},but length is {tempBytes.Length}"); return; } //获取有效数据长度 int dataLen = Bcd2Int(tempBytes[fristIndex + 4], tempBytes[fristIndex + 5]); byte[] reduceFAData = Reduce0xFAPair(tempBytes,fristIndex,secondIndex); string reduceFADataStr = BitConverter.ToString(reduceFAData).Replace("-", " "); //innerLogger.Info($"data length is ${dataLen},reduceFAData len is ${reduceFAData.Length},value is ${reduceFADataStr}"); //去除多余FA后,实际数据不足有效数据长度,表示有粘包,仍非完整数据,等待下一轮接收数据再处理 //1byte FA + 1 byte 目标地址 + 1 byte 源地址 + 1 byte 帧号 + 2 byte 有效数据长度 + dataLen byte 数据 + 2 byte 数据校验 if (reduceFAData.Length < 6 + dataLen + 2) { innerLogger.Info("Insufficient data length"); return; } //计算crc,若值对应不上,表示数据错误 ushort calculatorValue = HengshanCRC16.ComputeChecksum(reduceFAData.AsSpan(1, 5 + dataLen).ToArray()); byte highByte = reduceFAData[6 + dataLen]; byte lowByte = reduceFAData[7 + dataLen]; int crcValue = (highByte << 8) | lowByte; if (calculatorValue != crcValue) { //crc验证不通过,第一个包数据不正常,进入下一个循环,包头从第二个包头下标开始找(若没找到下个包头直接返回等待下一轮接收数据) innerLogger.Info($"crc value error,get value is {crcValue},calculator value is {calculatorValue}"); if(secondIndex == -1) { window.RemoveRange(0, tempBytes.Length); return; } } //获取到实际数据包,并将缓存数据删除 Message = reduceFAData; if (reduceFAData[6] != 0x10) { string reduceFaDataStr = BitConverter.ToString(reduceFAData).Replace("-", " "); innerLogger.Info($"receive reduceFa data : {reduceFaDataStr}"); } var safe = OnMessageCut; safe?.Invoke(this, null); //没有第二个包,清除缓存并结束 if(secondIndex == -1) { window.RemoveRange(0, tempBytes.Length); return; } } }; } 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,int firstIndex,int secondIndex) { int endIndex = data.Length; if (secondIndex != -1 && secondIndex > firstIndex) endIndex = secondIndex; List list = new(); for (int index = firstIndex; index < endIndex; 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; } } }