using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Aitex.Core.RT.Fsm; using Aitex.Core.RT.IOCore; using Aitex.Core.Util; using Aitex.Core.RT.Log; namespace Aitex.Core.RT.PLC { public class PLCEntityT : Entity where T : IDataDevice, new() where TBuffer : IDataBuffer, new() where TInput : struct where TOutput : struct { private T device = default(T); private Dictionary _buffers = new Dictionary(); //retry private int error = 0; private int retryWaitTime = 100; private int retryTimes = 10; private R_TRIG errTrig = new R_TRIG(); public enum STATE { INIT, RUNNING, ERROR, // }; public enum MSG { INIT, ERROR, RECOVERY, RESET, }; public PLCEntityT() { Running = false; device = new T(); foreach (var type in device.GetTypes()) { _buffers[type] = new TBuffer(); } fsm = new StateMachine>("PLC", (int)STATE.INIT, 100); EnterExitTransition(STATE.INIT, null, MSG.INIT, null); Transition(STATE.INIT, MSG.INIT, OpenDevice, STATE.RUNNING); Transition(STATE.RUNNING, FSM_MSG.TIMER, Run, STATE.RUNNING); Transition(STATE.RUNNING, MSG.RESET, Reset, STATE.RUNNING); Transition(STATE.ERROR, FSM_MSG.TIMER, Retry, STATE.RUNNING); Transition(STATE.ERROR, MSG.RECOVERY, Recovery, STATE.INIT); AnyStateTransition(MSG.ERROR, Error, STATE.ERROR); errTrig.CLK = false; } #region FSM Function private bool OpenDevice(object[] objs) { Running = false; if (!device.Open()) { PostMsg(MSG.ERROR); return false; //don't change state } return true; } private bool Run(object[] objs) { try { foreach (var type in device.GetTypes()) { try { if (!device.IsOpen(type)) { device.Open(type); continue; } object obj = device.Read(type); if (obj == null) { throw new Exception(); } _buffers[type].Input = (TInput)obj; Singleton.Instance.Update(type, _buffers[type]); if (device.Write(type, _buffers[type].Output)) { errTrig.CLK = false; error = 0; } } catch (Exception ex) { device.Close(type); LOG.Write(ex); } } } catch (Exception ex) { errTrig.CLK = true; if (errTrig.Q) { LOG.Write(ex); } } Running = true; return true; } private bool Error(object[] objs) { //add log if (error++ > retryTimes || !device.IsOpened) { PostMsg(MSG.RECOVERY); } return true; } private bool Retry(object[] objs) { //add log int elapsed = fsm.ElapsedTime; if (elapsed > retryWaitTime) { return true; } return false; } //关闭连接 private bool Recovery(object[] objs) { device.Close(); return true; } private bool Reset(object[] objs) { errTrig.RST = true; return true; } #endregion } }