using System; using System.Diagnostics; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Fsm; using Aitex.Core.RT.Log; using Aitex.Core.Util; using MECF.Framework.Common.Equipment; namespace Aitex.Core.RT.Device { public abstract class DeviceEntityT : Entity, IEntity where T : class, IDeviceManager, new() { public enum STATE { INIT = 0, RUNNING = 1, WAIT_RESET = 2, ERROR = 3 } public enum MSG { INIT = 0, ERROR = 1, WAIT_RESET = 2, RESET = 3 } protected const int MIN_MONITOR_INV_MS = 0; protected const int MAX_MONITOR_INV_MS = 5000; protected const int DEF_MONITOR_INV_MS = 100; private readonly R_TRIG _rTrigOverallMonitorTooSlow = new(); private readonly R_TRIG _rTrigOverallMonitorInvTooLong = new(); private readonly DeviceTimer _tmrMonitorPeriod = new(); private readonly Stopwatch _swMonitorCost = new (); private readonly Stopwatch _swMonitorInv = new (); private int _overallMonitorCostMs = 0; private int _overallMonitorCnt = 0; private int _overallMonitorInvMs = 0; private T mgr = null; public bool IsWaitReset => fsm.State == 2; public DeviceEntityT() { base.Running = false; fsm = new StateMachine>("DeviceLayer", 0, 50); EnterExitTransition(STATE.INIT, null, MSG.INIT, null); Transition(STATE.INIT, MSG.INIT, fInit, STATE.RUNNING); Transition(STATE.RUNNING, FSM_MSG.TIMER, fRun, STATE.RUNNING); Transition(STATE.RUNNING, MSG.RESET, fReset, STATE.RUNNING); mgr = Singleton.Instance; DATA.Subscribe($"{ModuleName.System}.OverallMonitorCostMs", () => _overallMonitorCostMs); DATA.Subscribe($"{ModuleName.System}.OverallMonitorCnt", () => _overallMonitorCnt); DATA.Subscribe($"{ModuleName.System}.OverallMonitorInvMs", () => _overallMonitorInvMs); Debug.Assert(MIN_MONITOR_INV_MS < DEF_MONITOR_INV_MS, "const variable definition error."); Debug.Assert(MAX_MONITOR_INV_MS > DEF_MONITOR_INV_MS, "const variable definition error."); MonitorPeriodMs = DEF_MONITOR_INV_MS; _tmrMonitorPeriod.Start(MonitorPeriodMs); } public virtual int MonitorPeriodMs { get; private set; } public void ChangeMinMonitorPeriodMs(int period) { if (period == MonitorPeriodMs) return; var _ssPeriod = MIN_MONITOR_INV_MS; if (period < MIN_MONITOR_INV_MS) MonitorPeriodMs = MIN_MONITOR_INV_MS; else if (period > MAX_MONITOR_INV_MS) MonitorPeriodMs = MAX_MONITOR_INV_MS; else MonitorPeriodMs = period; LOG.Info($"{this}.{nameof(MonitorPeriodMs)} change from {_ssPeriod}ms to {MonitorPeriodMs}ms"); } public bool Check(int msg, out string reason, params object[] args) { reason = ""; return true; } private bool fInit(object[] objs) { return true; } private bool fRun(object[] objs) { try { if (_tmrMonitorPeriod.IsTimeout()) { _swMonitorInv.Stop(); _overallMonitorInvMs = (int)_swMonitorInv.Elapsed.TotalMilliseconds; _swMonitorCost.Reset(); _swMonitorCost.Start(); _tmrMonitorPeriod.Start(MonitorPeriodMs); mgr.Monitor(); _swMonitorCost.Stop(); _overallMonitorCostMs = (int)_swMonitorCost.Elapsed.TotalMilliseconds; _overallMonitorCnt++; _overallMonitorCnt %= 10000; _swMonitorInv.Reset(); _swMonitorInv.Start(); } _rTrigOverallMonitorTooSlow.CLK = _overallMonitorCostMs > 3000; if(_rTrigOverallMonitorTooSlow.Q) LOG.Warning($"Device Manager overall monitor too slow, costs {_overallMonitorCostMs}ms where the limit is 3000ms"); _rTrigOverallMonitorInvTooLong.CLK = _overallMonitorInvMs > MAX_MONITOR_INV_MS * 1.5; if(_rTrigOverallMonitorInvTooLong.Q) LOG.Warning($"Device Manager overall monitor interval is too long, costs {_overallMonitorInvMs}ms where the limit is {MAX_MONITOR_INV_MS * 1.5}ms"); } catch (Exception ex) { Running = false; LOG.Error("Device Run exception", ex); } Running = true; return true; } private bool fReset(object[] objs) { mgr.Reset(); return true; } } }