using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.Util; namespace Aitex.Core.RT.Routine { public class RoutineFaildException : ApplicationException { public RoutineFaildException() { } public RoutineFaildException(string message) : base(message) { } } public class RoutineBreakException : ApplicationException { public RoutineBreakException() { } public RoutineBreakException(string message) : base(message) { } } public enum RoutineState { Running, Failed, Timeout, Finished, } public class RoutineResult { public RoutineState Result; public string ErrorMessage; } public class SeqenecRoutine { //timer, 计算routine时间 protected DeviceTimer counter = new DeviceTimer(); protected DeviceTimer delayTimer = new DeviceTimer(); private enum STATE { IDLE, WAIT, } public int TokenId { get { return _id; } } private int _id; //step index protected List _historySteps = new List(); protected List _waitSteps = new List(); /// /// already done steps /// private Stack _steps = new Stack(); public Stack Steps { get { return _steps; } set { _steps = value; } } private STATE state; //step state //idel,wait, //loop control private int loop = 0; private int loopCount = 0; private int loopID = 0; protected DeviceTimer timer = new DeviceTimer(); public DeviceTimer Timer => timer; public int LoopCounter { get { return loop; } set { loop = value; } } public int LoopTotalTime { get { return loopCount; } } // public int Timeout { get { return (int)(timer.GetTotalTime() / 1000); } } //状态持续时间,单位为秒 public int Elapsed { get { return (int)(timer.GetElapseTime() / 1000); } } protected RoutineResult RoutineToken = new RoutineResult() { Result = RoutineState.Running }; protected bool IsCurrentStepExcuteFailed { get; private set; } //状态持续时间,单位为秒 private double _pauseTime; public void Reset() { _id = 0; _steps.Clear(); loop = 0; loopCount = 0; IsCurrentStepExcuteFailed = false; state = STATE.IDLE; counter.Start(60*60*100); //默认1小时 RoutineToken.Result = RoutineState.Running; } public void ResetState() { state = STATE.IDLE; } protected void PerformRoutineStep(int id, Func execution, RoutineResult result) { if (!Acitve(id)) return; result.Result = execution(); } #region interface public void StopLoop() { loop = loopCount; } public Tuple Loop(T id, Func func, int count) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (!func()) { return Tuple.Create(bActive, Result.FAIL); //执行错误 } loopID = idx; loopCount = count; next(); return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } public Tuple EndLoop(T id, Func func) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (++loop >= loopCount) //Loop 结束 { if (!func()) { return Tuple.Create(bActive, Result.FAIL); //执行错误 } loop = 0; loopCount = 0; // Loop 结束时,当前loop和loop总数都清零 next(); return Tuple.Create(true, Result.RUN); } //继续下一LOOP next(loopID); return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } public Tuple ExecuteAndWait(T id, IRoutine routine) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (state == STATE.IDLE) { Result startRet = routine.Start(); if (startRet == Result.FAIL) { return Tuple.Create(true, Result.FAIL); //执行错误 }else if (startRet == Result.DONE) { next(); return Tuple.Create(true, Result.DONE); } state = STATE.WAIT; } Result ret = routine.Monitor(); if (ret == Result.DONE) { next(); return Tuple.Create(true, Result.DONE); } else if (ret == Result.FAIL || ret == Result.TIMEOUT) { return Tuple.Create(true, Result.FAIL); } else { return Tuple.Create(true, Result.RUN); } } return Tuple.Create(false, Result.RUN); } public Tuple ExecuteAndWait(T id, List routines) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (state == STATE.IDLE) { foreach (var item in routines) { if (item.Start() == Result.FAIL) return Tuple.Create(true, Result.FAIL); } state = STATE.WAIT; } //wait all sub failed or completedboo bool bFail = false; bool bDone = true; foreach (var item in routines) { Result ret = item.Monitor(); bDone &= (ret == Result.FAIL || ret == Result.DONE); bFail |= ret == Result.FAIL; } if (bDone) { next(); if(bFail) return Tuple.Create(true, Result.FAIL); return Tuple.Create(true, Result.DONE); } return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } public Tuple Check(T id, Func func) //顺序执行 { return Check(Check(Convert.ToInt32(id), func)); } public Tuple Execute(T id, Func func) //顺序执行 { return Check(execute(Convert.ToInt32(id), func)); } public Tuple Wait(T id, Func func, double timeout = int.MaxValue) //Wait condition { return Check(wait(Convert.ToInt32(id), func, timeout)); } public Tuple Wait(T id, Func func, double timeout = int.MaxValue) //Wait condition { return Check(wait(Convert.ToInt32(id), func, timeout)); } public Tuple ExecuteAndWait(T id, Func execute, Func check, double timeout = int.MaxValue) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); bool? bExecute = false; if (bActive) { if (state == STATE.IDLE) { if (!execute()) { return Tuple.Create(bActive, Result.FAIL); //执行错误 } timer.Start(timeout); state = STATE.WAIT; } bExecute = check(); if (bExecute == null) { return Tuple.Create(bActive, Result.FAIL); //Termianate } else { if (bExecute.Value) //检查Success, next { next(); return Tuple.Create(true, Result.RUN); } } if(timer.IsTimeout()) return Tuple.Create(true, Result.TIMEOUT); return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } public Tuple ExecuteAndWait(T id, Func execute, Func check, Func time) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); bool? bExecute = false; double timeout = 0; if (bActive) { if (state == STATE.IDLE) { timeout = time(); if (!execute()) { return Tuple.Create(true, Result.FAIL); //执行错误 } timer.Start(timeout); state = STATE.WAIT; } bExecute = check(); if (bExecute == null) { return Tuple.Create(true, Result.FAIL); //Termianate } if (bExecute.Value) //检查Success, next { next(); return Tuple.Create(true, Result.RUN); } if (timer.IsTimeout()) return Tuple.Create(true, Result.TIMEOUT); return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } public Tuple Wait(T id, IRoutine rt) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (state == STATE.IDLE) { rt.Start(); state = STATE.WAIT; } Result ret = rt.Monitor(); return Tuple.Create(true, ret); } return Tuple.Create(false, Result.RUN); } //Monitor public Tuple Monitor(T id, Func func, Func check, double time) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); bool bCheck = false; if (bActive) { if (state == STATE.IDLE) { if ((func != null) && !func()) { return Tuple.Create(true, Result.FAIL); } timer.Start(time); state = STATE.WAIT; } bCheck = check(); if (!bCheck) { return Tuple.Create(true, Result.FAIL); //Termianate } if (timer.IsTimeout()) { next(); } return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } //Delay public Tuple Delay(T id, Func func, double time) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (state == STATE.IDLE) { if ((func != null) && !func()) { return Tuple.Create(true, Result.FAIL); } timer.Start(time); state = STATE.WAIT; } if (timer.IsTimeout()) { next(); } return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } //先delay 再运行 public Tuple DelayCheck(T id, Func func, double time) { int idx = Convert.ToInt32(id); bool bActive = Acitve(idx); if (bActive) { if (state == STATE.IDLE) { timer.Start(time); state = STATE.WAIT; } if (timer.IsTimeout()) { if (func != null && !func()) { return Tuple.Create(true, Result.FAIL); } next(); } return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } #endregion private Tuple execute(int id, Func func) //顺序执行 { bool bActive = Acitve(id); bool bExecute = false; if (bActive) { bExecute = func(); if (bExecute) { next(); } } return Tuple.Create(bActive, bExecute); } private Tuple Check(int id, Func func) //check { bool bActive = Acitve(id); bool bExecute = false; if (bActive) { bExecute = func(); next(); } return Tuple.Create(bActive, bExecute); } /// /// /// /// /// /// /// item1 Active /// item2 execute /// item3 Timeout /// private Tuple wait(int id, Func func, double timeout = int.MaxValue) //Wait condition { bool bActive = Acitve(id); bool bExecute = false; bool bTimeout = false; if (bActive) { if (state == STATE.IDLE) { timer.Start(timeout); state = STATE.WAIT; } bExecute = func(); if (bExecute) { next(); } bTimeout = timer.IsTimeout(); } return Tuple.Create(bActive, bExecute, bTimeout); } private Tuple wait(int id, Func func, double timeout = int.MaxValue) //Wait condition && Check error { bool bActive = Acitve(id); bool? bExecute = false; bool bTimeout = false; if (bActive) { if (state == STATE.IDLE) { timer.Start(timeout); state = STATE.WAIT; } bExecute = func(); if (bExecute.HasValue && bExecute.Value) { next(); } bTimeout = timer.IsTimeout(); } return Tuple.Create(bActive, bExecute, bTimeout); } /// /// /// /// /// item1 true, return item2 /// private Tuple Check(Tuple value) { if (value.Item1) { if (!value.Item2) { return Tuple.Create(true, Result.FAIL); } return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } private Tuple Check(Tuple value) { if (value.Item1) // 当前执行 { if (CheckTimeout(value)) //timeout { return Tuple.Create(true, Result.TIMEOUT); } return Tuple.Create(true, Result.RUN); } return Tuple.Create(false, Result.RUN); } private Tuple Check(Tuple value) { if (value.Item1) // 当前执行 { if (value.Item2 == null) { return Tuple.Create(true, Result.FAIL); } else { if (value.Item2 == false && value.Item3 == true) //timeout { return Tuple.Create(true, Result.TIMEOUT); } return Tuple.Create(true, Result.RUN); } } return Tuple.Create(false, Result.RUN); } private bool CheckTimeout(Tuple value) { return value.Item1 == true && value.Item2 == false && value.Item3 == true; } private bool Acitve(int id) // { if (_steps.Contains(id)) return false; this._id = id; return true; } private void next() { if(!IsCurrentStepExcuteFailed) _steps.Push(this._id); state = STATE.IDLE; } private void next(int step) //loop { while(_steps.Pop() != step); state = STATE.IDLE; } public void Delay(int id, double delaySeconds) { Tuple ret = Delay(id, () => { return true; }, delaySeconds * 1000); if (ret.Item1) { if (ret.Item2 == Result.RUN) { throw (new RoutineBreakException()); } } } public bool IsActived(int id) { return _steps.Contains(id); } public void RetryCurrentStep(int step) { if (_steps.Contains(step)) { _steps.Pop(); } IsCurrentStepExcuteFailed = true; } public void StartRetry() { IsCurrentStepExcuteFailed = false; state = STATE.IDLE; } public void PauseRountine(bool isPause) { if (isPause && !timer.IsIdle())//暂停 { _pauseTime = timer.GetTotalTime(); timer.Stop(); } if (!isPause && timer.IsIdle()) { if (_pauseTime > 0) { timer.Start(_pauseTime); } } } } public class ModuleRoutine : SeqenecRoutine { protected bool _isHasAlarm = false; public string Module { get; set; } public string Name { get; set; } public string StepName { get { return _stepName; } } protected string _stepName; public TimeSpan StepLeftTime { get { if (_stepSpan.TotalMilliseconds < 1) return _stepSpan; return (_stepSpan - (DateTime.Now - _stepStartTime)); } } protected TimeSpan _stepSpan = new TimeSpan(0, 0, 0, 0); protected DateTime _stepStartTime; public delegate RoutineState RoutineFunc(T arg); protected Result RoutineStepResult { get; set; } protected void Notify(string message) { EV.PostInfoLog(Module, $"{Module} {Name}, {message}"); } protected void Stop(string failReason) { EV.PostAlarmLog(Module, $"{Module} {Name} failed, {failReason}"); } private static object locker=new object(); public void Abort(string failReason) { //lock (locker) //{ //Thread.Sleep(500); EV.PostAlarmLog(Module, $"{Module} {Name} {failReason}"); //} } public void TimeDelay(int id, string stepName, double time) { Tuple ret = Delay(id, () => { Notify($"Delay {time} seconds"); _stepSpan = new TimeSpan(0, 0, 0, (int)time); _stepStartTime = DateTime.Now; _stepName = stepName; return true; }, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.RUN) { throw (new RoutineBreakException()); } } } public void TimeDelay(int id, double time) { Tuple ret = Delay(id, () => { Notify($"Delay {time} seconds"); _stepSpan = new TimeSpan(0,0,0,(int)time); _stepStartTime = DateTime.Now; return true; }, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.RUN) { throw (new RoutineBreakException()); } } } protected void ExecuteRoutine(int id, IRoutine routine) { Tuple ret = ExecuteAndWait(id, routine); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.RUN) { throw (new RoutineBreakException()); } } } protected void PerformStep(T step, RoutineFunc func, T1 param1) { int idx = Convert.ToInt32(step); RoutineState state = func(param1); } public void Loop(int id, int count) { Tuple ret = Loop(id, () => { Notify($"Start loop {LoopCounter+1}/{count}"); return true; }, count); if (ret.Item1) { if (ret.Item2 == Result.FAIL) throw new RoutineFaildException(); } } public void EndLoop(int id) { Tuple ret = EndLoop(id, () => { Notify($"Loop finished"); return true; }); if (ret.Item1) { throw new RoutineBreakException(); } } public virtual Result Monitor() { RoutineStart(); MonitorStep(); RoutineStop(); return RoutineStepResult; } protected virtual void MonitorStep() { } protected void RoutineStart() { if (_historySteps.Count == 0 && TokenId == -1) { LOG.Write($"{Module}.{Name} begin"); RoutineStepResult = Result.RUN; } } protected void RoutineStop() { if (_waitSteps.Count == 0 && _historySteps.Contains(TokenId) && RoutineStepResult == Result.RUN) { RoutineStepResult = Result.DONE; LOG.Write($"{Module}.{Name} end"); } } } public class QueueRoutine { private Queue< IRoutine > _steps = new Queue< IRoutine >(); private IRoutine _currentStep = null; public void Add(IRoutine step) { _steps.Enqueue(step); } public void Reset() { _steps.Clear(); _currentStep = null; } public void Abort() { if (_currentStep != null) _currentStep.Abort(); Reset(); } public Result Start(params object[] objs) { if (_steps.Count == 0) return Result.DONE; _currentStep = _steps.Dequeue(); return _currentStep.Start(objs); } public Result Monitor(params object[] objs) { Result ret = Result.FAIL; if (_currentStep != null) { ret = _currentStep.Monitor(); } if (ret == Result.DONE) { _currentStep = _steps.Count > 0 ? _steps.Dequeue() : null; if (_currentStep != null) { return _currentStep.Start(objs); } } return ret; } } }