| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 | using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Edge.Core.Parser.BinaryParser.Util;using Edge.Core.Processor.Communicator;namespace LanTian_Sinopec_PumpIcCardReader{    public class StateMachineMessageCutter : IMessageCutter<byte[]>    {        public byte[] Message { get; private set; }        public event EventHandler OnMessageCut;        public event EventHandler<MessageCutterInvalidMessageReadEventArg> OnInvalidMessageRead;        static NLog.Logger innerLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("StateMachineMessageCutter");        private string loggerAppendix = "LanTian_Sinopec_PumpIcCardReader msgCutter ";        private readonly SizableWindow<byte> window;        private State nextState = State.Uninitialized;                                public StateMachineMessageCutter()        {            this.window = new SizableWindow<byte>(1);                        int extendBufferTimes = 0;            this.window.OnWindowFull += (data) =>            {                switch (nextState)                {                    case State.Uninitialized:                        if (data[0] == 0xFA)                        {                            extendBufferTimes = 0;                            this.window.NewSize = 2;                            this.nextState = State.HeaderReady;                            if (innerLogger.IsDebugEnabled)                                innerLogger.Debug(this.loggerAppendix + " state is State.Uninitialized and next is 0xFA, switch to HeaderReady");                        }                        else                        {                            this.window.Clear();                            return;                        }                        break;                    case State.HeaderReady:                        if (this.window.Count(h => h == 0xFA) == 1)                        {                            if (innerLogger.IsDebugEnabled)                                innerLogger.Debug(this.loggerAppendix + " Only 1 time of 0xFA in header window, switch to LengthReady");                            this.nextState = State.LengthReady;                            this.window.NewSize += 4;                        }                        else                        {                            if (innerLogger.IsDebugEnabled)                                innerLogger.Debug(this.loggerAppendix + " 2 times of 0xFA in header window, drop all and wait...");                                                        this.nextState = State.Uninitialized;                            this.window.Clear();                            this.window.NewSize = 1;                        }                        break;                    case State.LengthReady:                        var bodyLen = this.window[4] * 10 + this.window[5];                        if (bodyLen > 9999 || bodyLen < 2)                        {                            var safe8 = this.OnInvalidMessageRead;                            safe8?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()                            {                                Message = "MessageBody Length is a 2 bytes BCD encoded and expected value here is >=2 and <=9999 while now is " + bodyLen                            });                            this.nextState = State.Uninitialized;                            this.window.Clear();                            this.window.NewSize = 1;                            return;                        }                        this.window.NewSize += bodyLen;                        this.nextState = State.BodyReady;                        if (innerLogger.IsDebugEnabled)                            innerLogger.Debug(this.loggerAppendix + " MsgBodyLen caculated with: " + this.window.NewSize + ", and set default windowSize to this value.");                        break;                    case State.BodyReady:                                                var s = this.Get0xFAPairCountInWindow(this.window.Skip(6));                        if (extendBufferTimes < s)                        {                            this.window.NewSize += s - extendBufferTimes;                            extendBufferTimes = s;                            return;                        }                        extendBufferTimes = 0;                        this.window.NewSize += 2;                                                this.window.NewSize -= this.Reduce0xFAPair(this.window, 6);                        this.nextState = State.CrcReady;                        break;                    case State.CrcReady:                        bodyLen = this.window[4] * 10 + this.window[5];                        var p = this.Get0xFAPairCountInWindow(this.window.Skip(6 + bodyLen));                        if (extendBufferTimes < p)                        {                            this.window.NewSize += p - extendBufferTimes;                            extendBufferTimes = p;                            return;                        }                        this.Reduce0xFAPair(this.window, 6 + bodyLen);                        if (this.window.Count != (6 + bodyLen + 2))                        {                            var safe8 = this.OnInvalidMessageRead;                            safe8?.Invoke(this, new MessageCutterInvalidMessageReadEventArg()                            {                                Message = "CRC part is invalid"                            });                            this.nextState = State.Uninitialized;                            this.window.Clear();                            this.window.NewSize = 1;                            return;                        }                        this.Message = this.window.ToArray();                        var safe11 = this.OnMessageCut;                        safe11?.Invoke(this, null);                        this.nextState = State.Uninitialized;                        this.window.Clear();                        this.window.NewSize = 1;                        return;                    default:                        throw new ArgumentOutOfRangeException();                }            };        }                                                        private int Get0xFAPairCountInWindow(IEnumerable<byte> data)        {            return (int)Math.Round(((double)(data.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero);        }                                                        public int Reduce0xFAPair(IList<byte> target, int startIndex)        {            int reducedCount = 0;            var faAppearedPositions = new List<int>();            for (int i = startIndex; i < target.Count; i++)            {                if (target[i] == 0xFA)                {                    if (i <= (target.Count - 2))                    {                        if (target[i + 1] == 0xFA)                        {                            faAppearedPositions.Add(i);                            i++;                        }                    }                }            }            for (int i = 0; i < faAppearedPositions.Count; i++)            {                target.RemoveAt(faAppearedPositions[i] - i);                reducedCount++;            }            return reducedCount;        }        private enum State        {            Uninitialized,                        HeaderReady,            LengthReady,            BodyReady,            CrcReady,        }        public void Feed(byte[] next)        {                        for (int i = 0; i < next.Length; i++)                this.window.Add(next[i]);        }    }}
 |