StateMachine.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using System.Collections.Generic;
  5. using System.Collections.Concurrent;
  6. using Aitex.Core.RT.Log;
  7. using Aitex.Core.Utilities;
  8. using System.Linq;
  9. using DocumentFormat.OpenXml.Drawing;
  10. namespace Aitex.Core.RT.Fsm
  11. {
  12. /// <summary>
  13. /// FSM transition function
  14. /// 返回值: true 需要转换状态
  15. /// false 保持状态不变
  16. /// </summary>
  17. /// <param name="param"></param>
  18. /// <returns></returns>
  19. public enum FSM_MSG
  20. {
  21. TIMER = 0x0FFFFFF0,
  22. NONE,
  23. WARNING,
  24. ALARM,
  25. }
  26. public enum FSM_STATE
  27. {
  28. UNDEFINE = 0x0FFFFFF0,
  29. SAME,
  30. ANY,
  31. }
  32. public class StateMachine : StateMachine<object>
  33. {
  34. public StateMachine(string name = "FSM", int initState = (int)FSM_STATE.UNDEFINE, int interval = 100) : base(name, initState, interval)
  35. {
  36. }
  37. }
  38. public class StateMachine<T> : IStateMachine
  39. {
  40. public string Name { get; set; }
  41. public int ElapsedTime
  42. {
  43. get
  44. {
  45. int ticket = Environment.TickCount;
  46. return ticket > enterTime ? ticket - enterTime : 0x7FFFFFFF + ticket - enterTime;
  47. }
  48. }
  49. public int EnterTime { set { enterTime = value; } }
  50. public int TransitionEnterTime { set { transitionEnterTime = value; } }
  51. private int TransitionElapsedTime
  52. {
  53. get
  54. {
  55. return Environment.TickCount - transitionEnterTime;
  56. }
  57. }
  58. public int State { get; set; }
  59. public int PrevState { get; set; }
  60. public int LastMsg { get; private set; }
  61. private int enterTime;
  62. private int transitionEnterTime;
  63. public int MaxMsgInQueue { get; set; }
  64. private int interval;
  65. private bool _enableRepeatedMsg;
  66. private CancellationTokenSource cancelToken;
  67. private BlockingCollection<KeyValuePair<int, object[]>> _msgQueue;
  68. private object _lockerMsgQueue = new object();
  69. private KeyValuePair<int, object[]> timeoutMsg = new KeyValuePair<int, object[]>((int)FSM_MSG.TIMER, null);
  70. /// <summary>
  71. /// 状态迁移表 当前状态, 消息, 函数, 迁移状态
  72. /// AnyState迁移表 消息, 函数, 迁移状态
  73. /// 状态进入/退出迁移表 状态,进入函数,进入消息,退出函数,
  74. /// </summary>
  75. private Dictionary<int, Dictionary<int, Tuple<FsmFunc, int>>> transition;
  76. private Dictionary<int, Dictionary<int, Tuple<FsmFunc,FsmFunc, int>>> waitTransition;
  77. private Dictionary<int, int> waitTransitionIndex;
  78. private Dictionary<int, Tuple<FsmFunc, int>> anyStateTransition;
  79. private Dictionary<int, Tuple<FsmFunc, int, FsmFunc>> enterExitTransition;
  80. private Dictionary<int, string> _stringState = new Dictionary<int, string>();
  81. private Dictionary<int, string> _stringMessage = new Dictionary<int, string>();
  82. private KeyValuePair<int, object[]> _msgInProcess = new KeyValuePair<int, object[]>((int)FSM_MSG.TIMER, null);
  83. private long _msgCounter = 0;
  84. List<FsmFunc> fsmFuncs = new List<FsmFunc>();
  85. public StateMachine(string name, int initState = (int)FSM_STATE.UNDEFINE, int interval = 100)
  86. {
  87. Name = name + " FSM";
  88. MaxMsgInQueue = 500;
  89. this.State = initState;
  90. this.PrevState = initState;
  91. this.interval = interval;
  92. cancelToken = new CancellationTokenSource();
  93. _msgQueue = new BlockingCollection<KeyValuePair<int, object[]>>();
  94. transition = new Dictionary<int, Dictionary<int, Tuple<FsmFunc, int>>>();
  95. waitTransition = new Dictionary<int, Dictionary<int, Tuple<FsmFunc, FsmFunc, int>>>();
  96. waitTransitionIndex = new Dictionary<int, int>();
  97. anyStateTransition = new Dictionary<int, Tuple<FsmFunc, int>>();
  98. enterExitTransition = new Dictionary<int, Tuple<FsmFunc, int, FsmFunc>>();
  99. EnumLoop<FSM_STATE>.ForEach((item) =>
  100. {
  101. MapState((int)item, item.ToString());
  102. });
  103. EnumLoop<FSM_MSG>.ForEach((item) =>
  104. {
  105. MapMessage((int)item, item.ToString());
  106. });
  107. }
  108. #region Interface
  109. public void Init(int initState, int intervalTimeMs)
  110. {
  111. State = initState;
  112. interval = intervalTimeMs;
  113. }
  114. public void Start()
  115. {
  116. OnEnterState(this.State);
  117. }
  118. public void Loop()
  119. {
  120. while (!cancelToken.IsCancellationRequested)
  121. {
  122. //_msgInProcess = timeoutMsg;
  123. try
  124. {
  125. KeyValuePair<int, object[]> msg = timeoutMsg;
  126. lock (_lockerMsgQueue)
  127. {
  128. if (!_msgQueue.TryTake(out msg, interval, cancelToken.Token))
  129. _msgInProcess = timeoutMsg;
  130. else
  131. {
  132. _msgInProcess = msg;
  133. }
  134. }
  135. //Loop AnyState迁移表
  136. if (anyStateTransition.ContainsKey(_msgInProcess.Key))
  137. {
  138. //if (anyStateTransition[_msgInProcess.Key].Item3 != null && !fsmFuncs.Keys.Contains(_msgInProcess.Key))
  139. //{
  140. // fsmFuncs.Add(_msgInProcess.Key,anyStateTransition[_msgInProcess.Key].Item3);
  141. //}
  142. if (anyStateTransition[_msgInProcess.Key].Item1 != null)
  143. {
  144. if (anyStateTransition[_msgInProcess.Key].Item1(_msgInProcess.Value)) //need ChangeState
  145. {
  146. if (anyStateTransition[_msgInProcess.Key].Item2 != State && anyStateTransition[_msgInProcess.Key].Item2 != (int)FSM_STATE.SAME)
  147. {
  148. OnExitState((int)FSM_STATE.ANY);
  149. OnExitState(State);
  150. enterTime = Environment.TickCount;
  151. LastMsg = msg.Key;
  152. PrevState = State;
  153. State = anyStateTransition[_msgInProcess.Key].Item2;
  154. ///add log
  155. //if (Name == "EFEM FSM")
  156. {
  157. LOG.Write(eEvent.EV_FSM_NOTIFY, MECF.Framework.Common.Equipment.ModuleName.System, $"状态机 {Name}收到消息 {GetStringMessage(_msgInProcess.Key)}, 状态 {GetStringState(PrevState)}==>{GetStringState(State)}");
  158. }
  159. OnEnterState((int)FSM_STATE.ANY);
  160. OnEnterState((int)State);
  161. }
  162. }
  163. }
  164. if (_msgInProcess.Key != timeoutMsg.Key)
  165. {
  166. Interlocked.Decrement(ref _msgCounter);
  167. //System.Diagnostics.Trace.WriteLine($"message out1: {Name}--> {_msgCounter}");
  168. }
  169. continue;
  170. }
  171. foreach (var func in fsmFuncs)
  172. {
  173. func.Invoke(null);
  174. }
  175. if (!transition.ContainsKey(State))
  176. {
  177. if (_msgInProcess.Key != (int)FSM_MSG.TIMER)
  178. {
  179. LOG.Write(eEvent.WARN_FSM_WARN, MECF.Framework.Common.Equipment.ModuleName.System, $"StateMachine [{Name}] no definition of state [{GetStringState(State)}] ");
  180. }
  181. if (_msgInProcess.Key != timeoutMsg.Key)
  182. {
  183. Interlocked.Decrement(ref _msgCounter);
  184. //System.Diagnostics.Trace.WriteLine($"message out2: {Name} --> {_msgCounter}");
  185. }
  186. continue;
  187. }
  188. if (!transition[State].ContainsKey(_msgInProcess.Key))
  189. {
  190. if (_msgInProcess.Key != (int)FSM_MSG.TIMER)
  191. {
  192. LOG.Write(eEvent.WARN_FSM_WARN, MECF.Framework.Common.Equipment.ModuleName.System, $"StateMachine {Name} no definition of [state={GetStringState(State)}], [message={GetStringMessage(_msgInProcess.Key)}]");
  193. }
  194. if (_msgInProcess.Key != timeoutMsg.Key)
  195. {
  196. Interlocked.Decrement(ref _msgCounter);
  197. // System.Diagnostics.Trace.WriteLine($"message out3:{Name}--> {_msgCounter}");
  198. }
  199. ExecuteWaitTransition();
  200. continue;
  201. }
  202. //Loop Transition
  203. //if fun is null or fun return true need change
  204. if (transition[State][_msgInProcess.Key].Item1 == null || transition[State][_msgInProcess.Key].Item1(_msgInProcess.Value))
  205. {
  206. if (transition[State][_msgInProcess.Key].Item2 != State && transition[State][_msgInProcess.Key].Item2 != (int)FSM_STATE.SAME)
  207. {
  208. OnExitState((int)FSM_STATE.ANY);
  209. OnExitState(State);
  210. enterTime = Environment.TickCount;
  211. PrevState = State;
  212. State = transition[State][_msgInProcess.Key].Item2;
  213. ///add log
  214. //if (Name == "EFEM FSM")
  215. {
  216. LOG.Write(eEvent.EV_FSM_NOTIFY, MECF.Framework.Common.Equipment.ModuleName.System, $"状态机 {Name}收到消息 {GetStringMessage(_msgInProcess.Key)}, 状态 {GetStringState(PrevState)}==>{GetStringState(State)} 时长{TransitionElapsedTime}");
  217. }
  218. transitionEnterTime = Environment.TickCount;
  219. OnEnterState((int)FSM_STATE.ANY);
  220. OnEnterState((int)State);
  221. }
  222. }
  223. if (_msgInProcess.Key != timeoutMsg.Key)
  224. {
  225. Interlocked.Decrement(ref _msgCounter);
  226. //System.Diagnostics.Trace.WriteLine($"message out4: {Name}--> {_msgCounter}");
  227. }
  228. _msgInProcess = timeoutMsg;
  229. }
  230. catch (OperationCanceledException)
  231. {
  232. LOG.Write(eEvent.EV_FSM_NOTIFY, MECF.Framework.Common.Equipment.ModuleName.System, $"FSM {Name} is canceled");
  233. }
  234. catch (Exception ex)
  235. {
  236. LOG.Write(eEvent.EV_FSM_NOTIFY, MECF.Framework.Common.Equipment.ModuleName.System, ex.StackTrace + ex.Message);
  237. }
  238. }
  239. }
  240. private void ExecuteWaitTransition()
  241. {
  242. if (waitTransition.ContainsKey(State))
  243. {
  244. if (!waitTransition[State].ContainsKey(_msgInProcess.Key))
  245. {
  246. if (_msgInProcess.Key != (int)FSM_MSG.TIMER)
  247. {
  248. LOG.Write(eEvent.WARN_FSM_WARN, MECF.Framework.Common.Equipment.ModuleName.System, $"StateMachine {Name} no definition of [state={GetStringState(State)}], [message={GetStringMessage(_msgInProcess.Key)}]");
  249. }
  250. if (_msgInProcess.Key != timeoutMsg.Key)
  251. {
  252. Interlocked.Decrement(ref _msgCounter);
  253. // System.Diagnostics.Trace.WriteLine($"message out3:{Name}--> {_msgCounter}");
  254. }
  255. }
  256. else
  257. {
  258. bool result = false;
  259. if (waitTransitionIndex[State] == 0)
  260. {
  261. result = waitTransition[State][_msgInProcess.Key].Item1(_msgInProcess.Value);
  262. waitTransitionIndex[State] = 1;
  263. }
  264. else
  265. {
  266. result = waitTransition[State][_msgInProcess.Key].Item2(_msgInProcess.Value);
  267. waitTransitionIndex[State] = 2;
  268. }
  269. if (result && waitTransitionIndex[State]==2)
  270. {
  271. if (waitTransition[State][_msgInProcess.Key].Item3 != State && waitTransition[State][_msgInProcess.Key].Item3 != (int)FSM_STATE.SAME)
  272. {
  273. waitTransitionIndex[State] = 0;
  274. OnExitState((int)FSM_STATE.ANY);
  275. OnExitState(State);
  276. enterTime = Environment.TickCount;
  277. PrevState = State;
  278. State = waitTransition[State][_msgInProcess.Key].Item3;
  279. ///add log
  280. //if (Name == "EFEM FSM")
  281. {
  282. LOG.Write(eEvent.EV_FSM_NOTIFY, MECF.Framework.Common.Equipment.ModuleName.System, $"状态机 {Name}收到消息 {GetStringMessage(_msgInProcess.Key)}, 状态 {GetStringState(PrevState)}==>{GetStringState(State)} 时长{TransitionElapsedTime}");
  283. }
  284. transitionEnterTime = Environment.TickCount;
  285. OnEnterState((int)FSM_STATE.ANY);
  286. OnEnterState((int)State);
  287. }
  288. }
  289. }
  290. }
  291. }
  292. public void Stop()
  293. {
  294. cancelToken.Cancel();
  295. }
  296. string GetStringState(int state)
  297. {
  298. if (_stringState.ContainsKey(state))
  299. return _stringState[state];
  300. return state.ToString();
  301. }
  302. string GetStringMessage(int message)
  303. {
  304. if (_stringMessage.ContainsKey(message))
  305. return _stringMessage[message];
  306. return message.ToString();
  307. }
  308. public void MapState(int state, string stringState)
  309. {
  310. System.Diagnostics.Debug.Assert(!_stringState.ContainsKey(state));
  311. _stringState[state] = stringState;
  312. }
  313. public void MapMessage(int message, string stringMessage)
  314. {
  315. System.Diagnostics.Debug.Assert(!_stringMessage.ContainsKey(message));
  316. _stringMessage[message] = stringMessage;
  317. }
  318. public bool FindTransition(int state, int msg)
  319. {
  320. if (anyStateTransition.ContainsKey(msg))
  321. return true;
  322. if (transition.ContainsKey(state) && transition[state] != null)
  323. {
  324. Dictionary<int, Tuple<FsmFunc, int>> table = transition[state];
  325. if (table.ContainsKey(msg))
  326. return true;
  327. }
  328. return false;
  329. }
  330. public void Transition(int state, int msg, FsmFunc func, int next)
  331. {
  332. if (!transition.ContainsKey(state) || transition[state] == null)
  333. {
  334. transition[state] = new Dictionary<int, Tuple<FsmFunc, int>>();
  335. }
  336. transition[state][msg] = new Tuple<FsmFunc, int>(func, next);
  337. }
  338. public void Transition(int state,int msg,FsmFunc func,FsmFunc waitFunc,int next)
  339. {
  340. if (!transition.ContainsKey(state) || transition[state] == null)
  341. {
  342. transition[state] = new Dictionary<int, Tuple<FsmFunc, int>>();
  343. }
  344. if (msg != (int)FSM_MSG.TIMER)
  345. {
  346. transition[state][msg] = new Tuple<FsmFunc, int>(func, state);
  347. transition[state][(int)FSM_MSG.TIMER] = new Tuple<FsmFunc, int>(waitFunc, next);
  348. }
  349. else
  350. {
  351. if (!waitTransition.ContainsKey(state) || waitTransition[state]==null)
  352. {
  353. waitTransition[state] = new Dictionary<int, Tuple<FsmFunc, FsmFunc, int>>();
  354. waitTransitionIndex[state] = 0;
  355. }
  356. waitTransition[state][(int)FSM_MSG.TIMER]=new Tuple<FsmFunc, FsmFunc, int>(func,waitFunc,next);
  357. }
  358. }
  359. public void AnyStateTransition(int msg, FsmFunc func, int next)
  360. {
  361. if (msg != timeoutMsg.Key)
  362. {
  363. anyStateTransition[msg] = new Tuple<FsmFunc, int>(func, next);
  364. }
  365. else
  366. {
  367. fsmFuncs.Add(func);
  368. }
  369. }
  370. //public void AnyStateTransition(int msg, FsmFunc func, int next, FsmFunc monitorFunc)
  371. //{
  372. // anyStateTransition[msg] = new Tuple<FsmFunc, int,FsmFunc>(func, next,monitorFunc);
  373. //}
  374. public void EnterExitTransition(int state, FsmFunc enter, int msg, FsmFunc exit)
  375. {
  376. enterExitTransition[state] = new Tuple<FsmFunc, int, FsmFunc>(enter, msg, exit);
  377. }
  378. public void EnableRepeatedMsg(bool enable)
  379. {
  380. _enableRepeatedMsg = enable;
  381. }
  382. public void PostMsg(int msg, params object[] args)
  383. {
  384. Interlocked.Increment(ref _msgCounter);
  385. //lock (_lockerMsgQueue)
  386. {
  387. _msgQueue.Add(new KeyValuePair<int, object[]>(msg, args));
  388. }
  389. transitionEnterTime = Environment.TickCount;
  390. //System.Diagnostics.Trace.WriteLine($"PostMsg: {msg}--> {_msgCounter}");
  391. }
  392. public void PostMsgWithoutLock(int msg, params object[] args)
  393. {
  394. Interlocked.Increment(ref _msgCounter);
  395. _msgQueue.Add(new KeyValuePair<int, object[]>(msg, args));
  396. //System.Diagnostics.Trace.WriteLine($"PostMsgWithoutLock: {msg}--> {_msgCounter}");
  397. }
  398. #endregion
  399. private void OnEnterState(int state)
  400. {
  401. if (enterExitTransition.ContainsKey(state))
  402. {
  403. if (enterExitTransition[state].Item1 != null)
  404. {
  405. enterExitTransition[state].Item1(null);
  406. }
  407. if (enterExitTransition[state].Item2 != (int)FSM_MSG.NONE)
  408. {
  409. PostMsg(enterExitTransition[state].Item2, null);
  410. }
  411. }
  412. }
  413. private void OnExitState(int state)
  414. {
  415. if (enterExitTransition.ContainsKey(state))
  416. {
  417. if (enterExitTransition[state].Item3 != null)
  418. {
  419. enterExitTransition[state].Item3(null);
  420. }
  421. }
  422. }
  423. public bool CheckExecuted(int msg)
  424. {
  425. return _msgCounter == 0;
  426. //lock (_lockerMsgQueue)
  427. //{
  428. // foreach (var keyValuePair in _msgQueue)
  429. // {
  430. // if (keyValuePair.Key == msg)
  431. // return false;
  432. // }
  433. // if (_msgInProcess.Key == msg)
  434. // return false;
  435. //}
  436. //return true;
  437. }
  438. public bool CheckExecuted()
  439. {
  440. //System.Diagnostics.Trace.WriteLine($"CheckExecuted: --> {_msgCounter}");
  441. return _msgCounter == 0;
  442. //return Interlocked.CompareExchange(ref _msgCounter, 0, 0) == 0;
  443. ////lock (_lockerMsgQueue)
  444. //{
  445. // return _msgQueue.Count == 0 && _msgInProcess.Key==(int)FSM_MSG.TIMER;
  446. //}
  447. }
  448. public bool CheckExecuted(int msg, out int currentMsg, out List<int> msgQueue)
  449. {
  450. currentMsg = 0;
  451. msgQueue = new List<int>();
  452. return _msgCounter == 0;
  453. //lock (_lockerMsgQueue)
  454. //{
  455. // currentMsg = 0;
  456. // msgQueue = new List<int>();
  457. // foreach (var keyValuePair in _msgQueue)
  458. // {
  459. // if (keyValuePair.Key == msg)
  460. // return false;
  461. // msgQueue.Add(keyValuePair.Key);
  462. // }
  463. // if (_msgInProcess.Key == msg)
  464. // {
  465. // return false;
  466. // }
  467. // currentMsg = _msgInProcess.Key;
  468. //}
  469. //return true;
  470. }
  471. }
  472. }