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;
}
}
}