ofsmbase.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**@class OFSMBase
  2. * @brief base class for Orthogonal Finite State Machine
  3. *
  4. * stores current states (m_states) and transition table with possible transitions from each state
  5. * to another state via event
  6. **/
  7. class OFSMBase<Class FSMStateBase, Class FSMEventBase, Class FSMActionBase, Class FSMGuardBase>
  8. {
  9. protected ref array<ref FSMStateBase> m_States; /// current fsm state
  10. protected ref array<ref FSMStateBase> m_InitialStates; /// configurable initial state of the machine
  11. protected ref array<ref FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase>> m_Transitions; /// fsm transition table
  12. void OFSMBase ()
  13. {
  14. m_States = new array<ref FSMStateBase>;
  15. m_InitialStates = new array<ref FSMStateBase>;
  16. m_Transitions = new array<ref FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase>>;
  17. }
  18. /**@fn GetCurrentStates
  19. * @brief returns currently active state
  20. * @return current state the FSM is in (or NULL)
  21. **/
  22. array<ref FSMStateBase> GetCurrentState ()
  23. {
  24. return m_States;
  25. }
  26. /**@fn SetInitialState
  27. * @brief sets the initial_state for starting the machine
  28. **/
  29. void SetInitialStates (array<ref FSMStateBase> initial_states)
  30. {
  31. m_InitialStates = initial_states;
  32. for (int s = 0; s < initial_states.Count(); ++s)
  33. m_States.Insert(initial_states[s]);
  34. }
  35. /**@fn Start
  36. * @brief starts the state machine by entering the initial_state (using intial_event as argument to initial state's onEntry)
  37. * @param[in] e \p optional event for starting the machind
  38. **/
  39. void Start (array<ref FSMEventBase> initial_events = null)
  40. {
  41. if (LogManager.IsInventoryHFSMLogEnable()) fsmbDebugPrint("[ofsm] " + this.ToString() + "::Start(" + initial_events.ToString() + "), init_state=" + m_InitialStates.ToString());
  42. for (int s = 0; s < m_States.Count(); ++s)
  43. {
  44. m_States[s] = m_InitialStates[s];
  45. if (initial_events)
  46. m_States[s].OnEntry(initial_events[s]);
  47. else
  48. m_States[s].OnEntry(null);
  49. }
  50. }
  51. /**@fn IsRunning
  52. * @brief returns true if machine is in running state
  53. **/
  54. bool IsRunning ()
  55. {
  56. int sc = m_States.Count();
  57. if (sc)
  58. {
  59. for (int s = 0; s < sc; ++s)
  60. if (m_States[s] != null)
  61. return true;
  62. }
  63. return false;
  64. }
  65. /**@fn Terminate
  66. * @brief terminates the state machine
  67. **/
  68. void Terminate (array<ref FSMEventBase> terminal_events = null)
  69. {
  70. if (IsRunning())
  71. {
  72. for (int s = 0; s < m_States.Count(); ++s)
  73. {
  74. if (terminal_events)
  75. m_States[s].OnExit(terminal_events[s]);
  76. else
  77. m_States[s].OnExit(null);
  78. m_States[s] = null;
  79. }
  80. }
  81. }
  82. /**@fn Update
  83. * @brief if machine running, call OnUpdate() on current state
  84. **/
  85. void Update (float dt)
  86. {
  87. if (IsRunning())
  88. {
  89. for (int s = 0; s < m_States.Count(); ++s)
  90. {
  91. m_States[s].OnUpdate(dt);
  92. }
  93. }
  94. }
  95. /**@fn AddTransition
  96. * @brief adds transition into transition table
  97. **/
  98. void AddTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t)
  99. {
  100. m_Transitions.Insert(t);
  101. }
  102. /**@fn ProcessEvent
  103. * @brief instructs the state machine to process the event e
  104. * @param[in] e \p event that will be used to find suitable transition from current state
  105. * @return FSM_OK if transition found and allowed by guard (if any)
  106. **/
  107. ProcessEventResult ProcessEvent (FSMEventBase e)
  108. {
  109. int count = m_Transitions.Count();
  110. for (int i = 0; i < count; ++i)
  111. {
  112. FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> row = m_Transitions.Get(i);
  113. if (row.m_event.Type() == e.Type())
  114. {
  115. for (int s = 0; s < m_States.Count(); ++s)
  116. {
  117. if (row.m_srcState.Type() == m_States[s].Type() && row.m_event.Type() == e.Type())
  118. {
  119. FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
  120. bool hasGuard = t.m_guard != NULL;
  121. if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
  122. {
  123. ProcessLocalTransition(s, t, e); // 2) process transition allowed by guard
  124. }
  125. }
  126. }
  127. }
  128. }
  129. return ProcessEventResult.FSM_NO_TRANSITION;
  130. }
  131. /**@fn ProcessLocalTransition
  132. * @brief instructs the state machine to process the event locally - no hierarchy is crossed
  133. * @param[in] t \p the transition in m_transitions
  134. * @param[in] e \p event that will be used to process transition from current state
  135. * @return FSM_OK or FSM_TERMINATED
  136. **/
  137. protected ProcessEventResult ProcessLocalTransition (int s, FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
  138. {
  139. if (LogManager.IsInventoryHFSMLogEnable()) fsmbDebugPrint("[ofsm] (local) state=" + t.m_srcState.ToString() + "-------- event=" + e.ToString() + "[G=" + t.m_guard.ToString() +"]/A=" + t.m_action.ToString() + " --------|> dst=" + t.m_dstState.ToString());
  140. m_States[s].OnExit(e); // 1) call onExit on old state
  141. if (t.m_action)
  142. t.m_action.Action(e); // 2) execute transition action (if any)
  143. m_States[s] = t.m_dstState; // 3) change state to new
  144. if (t.m_dstState != NULL)
  145. {
  146. m_States[s].OnEntry(e); // 4a) call onEntry on new state
  147. return ProcessEventResult.FSM_OK;
  148. }
  149. else
  150. {
  151. if (LogManager.IsInventoryHFSMLogEnable()) fsmbDebugPrint("[ofsm] terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
  152. return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
  153. }
  154. }
  155. };