123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- 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, localTcpServerListeningPort) =>
- {
- 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,int localTcpServerListeningPort = 0)
- {
- List<byte> list = new(data);
- window.Add(list, localTcpServerListeningPort);
- //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>
- /// <returns></returns>
- public byte[] Reduce0xFAPair(byte[] data)
- {
- List<byte> 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;
- }
- }
- }
|