using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump; using Edge.Core.Parser.BinaryParser.Util; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Edge.Core.Processor.Communicator; namespace Wayne_Pump_Dart { public class StateMachineMessageCutter : IMessageCutter { public byte[] Message { get; private set; } public event EventHandler OnMessageCut; public event EventHandler OnInvalidMessageRead; //static ILog innerLogger = log4net.LogManager.GetLogger("StateMachine"); static NLog.Logger innerLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("Communicator"); private string loggerAppendix = "Wayne_Pump_Dart msgCutter "; private readonly List buffer = new List(); /// /// if the 0xFA count is odd, will use round up for count/2. /// e.g.: 0xFA appeared 2 times, return 1. /// 0xFA appeared 3 times, return 2, this is considered as window is not big enough to include further 0xFA since they're always even. /// /// private int Get0xFAPairCountInWindow(IList target) { return (int)Math.Round(((double)(target.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero); } /// /// found all pair(one besides one) of 0xFA in a list, and reduce the pair to a single 0xFA. /// /// private int Reduce0xFAPair(IList target, int from) { var faAppearedPositions = new List(); for (int i = from; i < target.Count - 1; i++) { if (target[i] == 0x10 && target[i + 1] == 0xFA) { faAppearedPositions.Add(i); i++; } } for (int i = 0; i < faAppearedPositions.Count; i++) { target.RemoveAt(faAppearedPositions[i] - i); } return faAppearedPositions.Count; } /// /// Code Transparency /// Code transparency for 8 bit data is achieved by Data Link escape(DLE) inser-tion. /// DLE insertion is needed when any data byte or CRC has the value SF(stop flag). /// Transmitting device transmit DLE before SF is transmitted in the data field. /// Receiving device checks when receiving SF, /// if previous received character was DLE.If so DLE is over written by the received SF /// in the line buffer.Inserted DLE:s are not included in the CRC-calculation. /// /// ETX 03H End of text /// DLE 10H Data link escape /// SF FAH Stop flag /// /// Message format: /// ADR CTRL trans_Number trans_Length trans_data CRC-1 CRC-2 ETX(0x03) SF(0xFA) /// public StateMachineMessageCutter() { } public void Feed(byte[] next) { try { //innerLogger.Debug(this.loggerAppendix + " " + next.ToHexLogString() + " is feed in Window in state: " + nextState); for (int i = 0; i < next.Length; i++) { this.buffer.Add(next[i]); if (this.buffer[0] < 0x50 || this.buffer[0] > 0x6F) { this.buffer.Clear(); } //0x30 is data if (this.buffer.Count >= 2 && ((this.buffer[1] & 0xF0) != 0x30) //ack && ((this.buffer[1] & 0xF0) != 0xC0) //nak && ((this.buffer[1] & 0xF0) != 0x50) //eot && ((this.buffer[1] & 0xF0) != 0x70) //ackpoll && ((this.buffer[1] & 0xF0) != 0xe0)) { this.OnInvalidMessageRead?.Invoke(this, new MessageCutterInvalidMessageReadEventArg() { Message = "invalid byte[1]: 0x" + this.buffer[1].ToString("X2") + ", clear buf(valid byte[0]: 0x" + this.buffer[0].ToString("X2") + ") anyway" }); this.buffer.Clear(); } if (this.buffer.Count >= 3 && this.buffer[this.buffer.Count - 2] != 0x10 && this.buffer[this.buffer.Count - 1] == 0xFA) { Reduce0xFAPair(this.buffer, 0); if (this.buffer.Count >= 44) innerLogger.Info("Long length(len: " + this.buffer.Count + ") message was cut from MsgCutter: 0x" + this.buffer.ToHexLogString()); this.Message = this.buffer.ToArray(); var safe = this.OnMessageCut; safe?.Invoke(this, null); this.buffer.Clear(); } if (this.buffer.Count >= 45) innerLogger.Info("Long length(len: " + this.buffer.Count + ") message is still constructing in MsgCutter: 0x" + this.buffer.ToHexLogString()); } } catch (Exception exx) { innerLogger.Error($"Wayne_Pump_Dart.StateMachineMessageCutter, " + $"next: 0x{next?.ToHexLogString() ?? "null"}, " + $"this.buffer: 0x{this.buffer?.ToHexLogString() ?? "null"}" + $"{Environment.NewLine}exception detail: {exx}"); throw; } } } }