using System; using System.Diagnostics; using System.Threading; using System.Collections.Generic; using System.Collections.Concurrent; using Aitex.Core.RT.Log; using Aitex.Core.Utilities; 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 : StateMachine { public StateMachine(string name = "FSM", int initState = (int)FSM_STATE.UNDEFINE, int interval = 100) : base(name, initState, interval) { } } 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; } public int LastMsg { get; private set; } private int enterTime; private int interval; private CancellationTokenSource cancelToken; private BlockingCollection> _msgQueue; private object _lockerMsgQueue = new object(); 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(); private KeyValuePair _msgInProcess = new KeyValuePair((int)FSM_MSG.TIMER, null); private long _msgCounter = 0; public StateMachine(string name, int initState = (int)FSM_STATE.UNDEFINE, int interval = 100) { Name = name + " FSM"; this.State = initState; this.PrevState = initState; this.interval = interval; cancelToken = new CancellationTokenSource(); _msgQueue = 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 Init(int initState, int intervalTimeMs) { State = initState; interval = intervalTimeMs; } public void Start() { OnEnterState(this.State); } public void Loop() { while (!cancelToken.IsCancellationRequested) { //_msgInProcess = timeoutMsg; try { KeyValuePair msg = timeoutMsg; lock (_lockerMsgQueue) { if (!_msgQueue.TryTake(out msg, interval, cancelToken.Token)) _msgInProcess = timeoutMsg; else { _msgInProcess = msg; } } //Loop AnyState迁移表 if (anyStateTransition.ContainsKey(_msgInProcess.Key)) { if (anyStateTransition[_msgInProcess.Key].Item1 != null) { if (anyStateTransition[_msgInProcess.Key].Item1(_msgInProcess.Value)) //need ChangeState { if (anyStateTransition[_msgInProcess.Key].Item2 != State && anyStateTransition[_msgInProcess.Key].Item2 != (int)FSM_STATE.SAME) { OnExitState((int)FSM_STATE.ANY); OnExitState(State); enterTime = Environment.TickCount; LastMsg = msg.Key; PrevState = State; State = anyStateTransition[_msgInProcess.Key].Item2; OnEnterState((int)FSM_STATE.ANY); OnEnterState((int)State); TraceState(PrevState, State, "anyStateTransition 过程"); } } } if (_msgInProcess.Key != timeoutMsg.Key) { Interlocked.Decrement(ref _msgCounter); //System.Diagnostics.Trace.WriteLine($"message out1: {Name}--> {_msgCounter}"); } continue; } if (!transition.ContainsKey(State)) { if (_msgInProcess.Key != (int)FSM_MSG.TIMER) { LOG.Warning($"StateMachine [{Name}] no definition of state [{GetStringState(State)}] "); } if (_msgInProcess.Key != timeoutMsg.Key) { Interlocked.Decrement(ref _msgCounter); //System.Diagnostics.Trace.WriteLine($"message out2: {Name} --> {_msgCounter}"); } continue; } if (!transition[State].ContainsKey(_msgInProcess.Key)) { if (_msgInProcess.Key != (int)FSM_MSG.TIMER) { LOG.Warning($"StateMachine {Name} no definition of [state={GetStringState(State)}], [message={GetStringMessage(_msgInProcess.Key)}]"); } if (_msgInProcess.Key != timeoutMsg.Key) { Interlocked.Decrement(ref _msgCounter); // System.Diagnostics.Trace.WriteLine($"message out3:{Name}--> {_msgCounter}"); } continue; } //Loop Transition //if fun is null or fun return true need change if (transition[State][_msgInProcess.Key].Item1 == null || transition[State][_msgInProcess.Key].Item1(_msgInProcess.Value)) { if (transition[State][_msgInProcess.Key].Item2 != State && transition[State][_msgInProcess.Key].Item2 != (int)FSM_STATE.SAME) { OnExitState((int)FSM_STATE.ANY); OnExitState(State); enterTime = Environment.TickCount; PrevState = State; State = transition[State][_msgInProcess.Key].Item2; OnEnterState((int)FSM_STATE.ANY); OnEnterState((int)State); TraceState(PrevState, State, "transition 过程"); } } if (_msgInProcess.Key != timeoutMsg.Key) { Interlocked.Decrement(ref _msgCounter); //System.Diagnostics.Trace.WriteLine($"message out4: {Name}--> {_msgCounter}"); } _msgInProcess = timeoutMsg; } catch (OperationCanceledException) { LOG.Info($"FSM {Name} is canceled"); } catch (Exception ex) { LOG.Error(ex.StackTrace, ex); } } } 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); } private const string PMBName = "PMB"; private const string PMAName = "PMA"; private const string TMName = "TM"; private void TraceState(int prevState, int afterState, string title) { //if (Name != null && (Name.IndexOf(PMBName) > -1 || Name.IndexOf(PMAName) > -1 || Name.IndexOf(TMName) > -1)) if (Name != null) { string preStateContent = _stringState.ContainsKey(prevState) ? _stringState[prevState] : prevState.ToString(); string postStateContent = _stringState.ContainsKey(afterState)? _stringState[afterState] : afterState.ToString(); LOG.Info($"StateMachine Name={Name} 状态转换前={preStateContent} 转换后={postStateContent} by {title}"); } } public void PostMsg(int msg, params object[] args) { Interlocked.Increment(ref _msgCounter); //lock (_lockerMsgQueue) { _msgQueue.Add(new KeyValuePair(msg, args)); } //System.Diagnostics.Trace.WriteLine($"PostMsg: {msg}--> {_msgCounter}"); } public void PostMsgWithoutLock(int msg, params object[] args) { Interlocked.Increment(ref _msgCounter); _msgQueue.Add(new KeyValuePair(msg, args)); //System.Diagnostics.Trace.WriteLine($"PostMsgWithoutLock: {msg}--> {_msgCounter}"); } #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); } } } public bool CheckExecuted(int msg) { return _msgCounter == 0; //lock (_lockerMsgQueue) //{ // foreach (var keyValuePair in _msgQueue) // { // if (keyValuePair.Key == msg) // return false; // } // if (_msgInProcess.Key == msg) // return false; //} //return true; } public bool CheckExecuted() { //System.Diagnostics.Trace.WriteLine($"CheckExecuted: --> {_msgCounter}"); return _msgCounter == 0; //return Interlocked.CompareExchange(ref _msgCounter, 0, 0) == 0; ////lock (_lockerMsgQueue) //{ // return _msgQueue.Count == 0 && _msgInProcess.Key==(int)FSM_MSG.TIMER; //} } public bool CheckExecuted(int msg, out int currentMsg, out List msgQueue) { currentMsg = 0; msgQueue = new List(); return _msgCounter == 0; //lock (_lockerMsgQueue) //{ // currentMsg = 0; // msgQueue = new List(); // foreach (var keyValuePair in _msgQueue) // { // if (keyValuePair.Key == msg) // return false; // msgQueue.Add(keyValuePair.Key); // } // if (_msgInProcess.Key == msg) // { // return false; // } // currentMsg = _msgInProcess.Key; //} //return true; } } }