using Edge.Core.Database; using Edge.Core.Processor; using Edge.Core.IndustryStandardInterface.Pump; using Edge.Core.Processor.Communicator; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.DependencyInjection; namespace Wayne_VaporRecoveryDataCollectorBoard { public class StateMachineMessageCutter : IMessageCutter { public byte[] Message { get; private set; } public event EventHandler OnMessageCut; public event EventHandler OnInvalidMessageRead; static ILogger innerLogger = NullLogger.Instance; private string loggerAppendix = "Wayne_VaporRecoveryDataCollectorBoard msgCutter "; private readonly SizableWindow window; private State nextState = State.Uninitialized; public StateMachineMessageCutter() : this(null) { } /// /// 包起始标志(1B)+采集器地址Addr(1B)+命令代码(1B)+数据域长度(1B)+数据域(由数据域长度指定)+校验CS(1B)+包结束标志(1B)。 ///包起始标志:68; ///包结束标志:0x16; ///校验:从采集器地址开始(包括采集器地址)到校验字节前所有数据累加求和取低八位数据。 /// public StateMachineMessageCutter(IServiceProvider services) { var loggerFactory = services?.GetRequiredService(); innerLogger = loggerFactory?.CreateLogger("StateMachineMessageCutter") ?? NullLogger.Instance; //this.initWindowSize = initWindowSize; this.window = new SizableWindow(); this.window.OnWindowFull += (data) => { switch (nextState) { case State.Uninitialized: if (data.First() == 0x68) { this.window.NewSize = 4; this.nextState = State.LengthReady; if (innerLogger.IsEnabled(LogLevel.Trace)) innerLogger.LogTrace(this.loggerAppendix + " in State.Uninitialized read header 0x68, switch to LengthReady"); } else this.window.Clear(); break; case State.LengthReady: if (this.window.Skip(3).First() >= 40) { innerLogger.LogInformation($"{this.loggerAppendix } MsgBodyLen value: 0x{this.window.Skip(3).First().ToString("X").PadLeft(2, '0')} is too large, treat as error msg."); this.OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg() { Message = $"{this.loggerAppendix } MsgBodyLen value: 0x{this.window.Skip(3).First().ToString("X").PadLeft(2, '0')} is too large, treat as error msg." }); this.nextState = State.Uninitialized; this.window.Clear(); return; } if (this.window.Skip(2).First() == 0 && this.window.Skip(3).First() == 0) { /* handle a special case of 'device is in busy' command, it is like: 0x68 06 00 00 16*/ this.window.NewSize = 5; } else this.window.NewSize = this.window.Skip(3).First() + 4 + 1 + 1; this.nextState = State.BodyReady; if (innerLogger.IsEnabled(LogLevel.Trace)) innerLogger.LogTrace(this.loggerAppendix + " MsgBodyLen caculated with: " + this.window.NewSize); break; case State.BodyReady: if (this.window.Last() != 0x16) { innerLogger.LogInformation($"{this.loggerAppendix } last byte must be 0x16 but now is 0x{this.window.Last().ToString("X").PadLeft(2, '0')}, treat as error msg."); this.OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg() { Message = $"{this.loggerAppendix } last byte must be 0x16 but now is 0x{this.window.Last().ToString("X").PadLeft(2, '0')}, treat as error msg." }); this.nextState = State.Uninitialized; this.window.Clear(); return; } this.Message = this.window.ToArray(); /* handle a special case of 'device is in busy' command, it is like: 0x68 06 00 00 16*/ //make a hack for `device is in busy command` as the parser lib must have a concreate byte data to fill all properties. if (this.Message.Length == 5) this.Message = this.Message.Concat(new byte[] { 0x00 }).ToArray(); var safe = this.OnMessageCut; safe?.Invoke(this, null); this.nextState = State.Uninitialized; this.window.Clear(); //this.window.NewSize = this.initWindowSize; break; default: throw new ArgumentOutOfRangeException(); } }; } private enum State { Uninitialized, //HeaderSeeking, HeaderReady, LengthReady, BodyReady, } public void Feed(byte[] next) { //innerLogger.Debug(this.loggerAppendix + " " + next.ToHexLogString() + " is feed in Window in state: " + nextState); for (int i = 0; i < next.Length; i++) this.window.Add(next[i]); } } }