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