using System; using System.Diagnostics; using System.Threading; using System.Collections.Generic; using System.Collections.Concurrent; using Aitex.Core.RT.Log; using Aitex.Core.Util; using Aitex.Core.Utilities; using System.Threading.Tasks; using Aitex.Core.MES; using Aitex.Core.RT.SCCore; using Aitex.Core.MES.YZQZ; namespace Aitex.Core.RT.Fsm { /// /// FSM transition function /// 返回值: true 需要转换状态 /// false 保持状态不变 /// /// /// public enum FSM_MSG { TIMER = 0x0FFFFFF0, NONE, WARNING, ALARM, } public enum FSM_STATE { UNDEFINE = 0x0FFFFFF0, SAME, ANY, } public class StateMachine : IStateMachine { public string Name { get; set; } public int ElapsedTime { get { int ticket = Environment.TickCount; return ticket > enterTime ? ticket - enterTime : 0x7FFFFFFF + ticket - enterTime; } } public int EnterTime { set { enterTime = value; } } public int State { get; set; } public int PrevState { get; set; } private bool _enableRepeatedMsg; public int MaxMsgInQueue { get; set; } private int enterTime; private int interval; private CancellationTokenSource cancelToken; private BlockingCollection> msgQuene; private KeyValuePair timeoutMsg = new KeyValuePair((int)FSM_MSG.TIMER, null); /// /// 状态迁移表 当前状态, 消息, 函数, 迁移状态 /// AnyState迁移表 消息, 函数, 迁移状态 /// 状态进入/退出迁移表 状态,进入函数,进入消息,退出函数, /// private Dictionary>> transition; private Dictionary> anyStateTransition; private Dictionary> enterExitTransition; private Dictionary _stringState = new Dictionary(); private Dictionary _stringMessage = new Dictionary(); DeviceTimer _loopTimer = new DeviceTimer(); public StateMachine(string name, int initState = (int)FSM_STATE.UNDEFINE, int interval = 100) { Name = name + " FSM"; MaxMsgInQueue = 500; this.State = initState; this.PrevState = initState; this.interval = interval; cancelToken = new CancellationTokenSource(); msgQuene = new BlockingCollection>(); transition = new Dictionary>>(); anyStateTransition = new Dictionary>(); enterExitTransition = new Dictionary>(); EnumLoop.ForEach((item) => { MapState((int)item, item.ToString()); }); EnumLoop.ForEach((item) => { MapMessage((int)item, item.ToString()); }); } #region Interface public void Start() { OnEnterState(this.State); } public void Loop() { while (!cancelToken.IsCancellationRequested) { KeyValuePair msg = timeoutMsg; try { int timeout = interval - (int)_loopTimer.GetElapseTime(); if (timeout < 50) timeout = 50; if (!msgQuene.TryTake(out msg, timeout, cancelToken.Token)) msg = timeoutMsg; _loopTimer.Start(0); //Loop AnyState迁移表 if (anyStateTransition.ContainsKey(msg.Key)) { if (anyStateTransition[msg.Key].Item1 != null) { if (anyStateTransition[msg.Key].Item1(msg.Value)) //need ChangeState { if (anyStateTransition[msg.Key].Item2 != State && anyStateTransition[msg.Key].Item2 != (int)FSM_STATE.SAME) { OnExitState((int)FSM_STATE.ANY); OnExitState(State); enterTime = Environment.TickCount; PrevState = State; State = anyStateTransition[msg.Key].Item2; OnEnterState((int)FSM_STATE.ANY); OnEnterState((int)State); } } } continue; } if (!transition.ContainsKey(State)) { if (msg.Key != (int)FSM_MSG.TIMER) { LOG.Warning("状态机{0}未定义在状态{1}时处理方法。", Name, GetStringState(State)); } continue; } if (!transition[State].ContainsKey(msg.Key)) { if (msg.Key != (int)FSM_MSG.TIMER) { LOG.Warning("状态机{0}未定义在状态{1}时收到消息{2}的处理方法。", Name, GetStringState(State), GetStringMessage(msg.Key)); } continue; } //Loop Transition //if fun is null or fun return true need change if (transition[State][msg.Key].Item1 == null || transition[State][msg.Key].Item1(msg.Value)) { if (transition[State][msg.Key].Item2 != State && transition[State][msg.Key].Item2 != (int)FSM_STATE.SAME) { OnExitState((int)FSM_STATE.ANY); OnExitState(State); enterTime = Environment.TickCount; PrevState = State; State = transition[State][msg.Key].Item2; OnEnterState((int)FSM_STATE.ANY); OnEnterState((int)State); postYZQZMachineStatus((int)State); } } } catch (OperationCanceledException ex) { LOG.Error("FSM cancel", ex); } catch (Exception ex) { LOG.Error(String.Format("{0}: State {1},Msg{2} Loop has exception ", Name, GetStringState(State), GetStringMessage(msg.Key)), ex); try { StackFrame sf = new StackTrace(true).GetFrame(3); LOG.Error(string.Format("State Machine running error in {0}, {1}", sf.GetFileLineNumber() , sf.GetMethod().Name)); } catch (Exception) { } } } } private async void postYZQZMachineStatus(int state) { await Task.Run(() => { Fab fb = (Fab)Enum.Parse(typeof(Fab), SC.GetValue(SCName.System_Company).ToString()); if (fb == Fab.YZQZ) { FabAutoComm com = new YZQZFabAuto(); com.SaveMachineStatusRecord(state); } }); } public void Stop() { cancelToken.Cancel(); } string GetStringState(int state) { if (_stringState.ContainsKey(state)) return _stringState[state]; return state.ToString(); } string GetStringMessage(int message) { if (_stringMessage.ContainsKey(message)) return _stringMessage[message]; return message.ToString(); } public void MapState(int state, string stringState) { System.Diagnostics.Debug.Assert(!_stringState.ContainsKey(state)); _stringState[state] = stringState; } public void MapMessage(int message, string stringMessage) { System.Diagnostics.Debug.Assert(!_stringMessage.ContainsKey(message)); _stringMessage[message] = stringMessage; } public bool FindTransition(int state, int msg) { if (anyStateTransition.ContainsKey(msg)) return true; if (transition.ContainsKey(state) && transition[state] != null) { Dictionary> table = transition[state]; if (table.ContainsKey(msg)) return true; } return false; } public void Transition(int state, int msg, FsmFunc func, int next) { if (!transition.ContainsKey(state) || transition[state] == null) { transition[state] = new Dictionary>(); } transition[state][msg] = new Tuple(func, next); } public void AnyStateTransition(int msg, FsmFunc func, int next) { anyStateTransition[msg] = new Tuple(func, next); } public void EnterExitTransition(int state, FsmFunc enter, int msg, FsmFunc exit) { enterExitTransition[state] = new Tuple(enter, msg, exit); } public void EnableRepeatedMsg(bool enable) { _enableRepeatedMsg = enable; } public void PostMsg(int msg, params object[] args) { foreach (var item in msgQuene) { if (item.Key == msg && !_enableRepeatedMsg) { if (msg != (int)FSM_MSG.WARNING && msg != (int)FSM_MSG.ALARM) LOG.Warning("状态机【{0}】收到重复发送的消息{1},该条消息被忽略。",Name, msg); return; } } if (msgQuene.Count > MaxMsgInQueue) { LOG.Warning("状态机【{0}】收到 的消息超过{1}条,消息{2}被忽略。",Name, MaxMsgInQueue, msg); } msgQuene.Add(new KeyValuePair(msg, args)); } #endregion private void OnEnterState(int state) { if (enterExitTransition.ContainsKey(state)) { if (enterExitTransition[state].Item1 != null) { enterExitTransition[state].Item1(null); } if (enterExitTransition[state].Item2 != (int)FSM_MSG.NONE) { PostMsg(enterExitTransition[state].Item2, null); } } } private void OnExitState(int state) { if (enterExitTransition.ContainsKey(state)) { if (enterExitTransition[state].Item3 != null) { enterExitTransition[state].Item3(null); } } } } }