123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- 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<byte[]>
- {
- #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<MessageCutterInvalidMessageReadEventArg> OnInvalidMessageRead;
- private string loggerAppendix = "HengshanPay Terminal";
- private readonly SizableWindow<byte> 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<byte>();
- 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<byte> list = new(data);
- window.Add(list);
- //for (int i = 0; i < data.Length; i++)
- //{
- // window.Add(data[i]);
- //}
- }
- private int Get0xFAPairCountInWindow(IEnumerable<byte> data)
- {
- return (int)Math.Round(((double)(data.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero);
- }
- /// <summary>
- /// 删除多余的FA,在接收到的一个完整数据包中,数据包头为FA,其余数据中每一个FA会替换为两个FA,这里要删除多余的fa来获取实际数据包
- /// </summary>
- /// <param name="data">原数据包</param>
- /// <param name="firstIndex">第一个包头下标</param>
- /// <param name="secondIndex">第二个包头下标</param>
- /// <returns></returns>
- public byte[] Reduce0xFAPair(byte[] data,int firstIndex,int secondIndex)
- {
- int endIndex = data.Length;
- if (secondIndex != -1 && secondIndex > firstIndex) endIndex = secondIndex;
- List<byte> 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;
- }
- }
- }
|