OpenRTM-aist  2.1.0
StateMachine.h
[詳解]
1 // -*- C++ -*-
19 #ifndef RTC_STATEMACHINE_H
20 #define RTC_STATEMACHINE_H
21 
22 #include <mutex>
23 
24 #include <cassert>
25 #include <utility>
26 #include <vector>
27 
28 namespace RTC_Utils
29 {
56  template <class State>
57  struct StateHolder
58  {
62  };
63 
261  template <class State,
262  class Listener,
263  class States = StateHolder<State>,
264  class Callback = void (Listener::*)(const States& states)
265  >
267  {
268  public:
286  explicit StateMachine(int num_of_state)
287  : m_num(num_of_state),
288  m_listener(nullptr),
289  m_entry(m_num, (Callback)nullptr),
290  m_predo(m_num, (Callback)nullptr),
291  m_do(m_num, (Callback)nullptr),
292  m_postdo(m_num, (Callback)nullptr),
293  m_exit(m_num, (Callback)nullptr),
294  m_transit(nullptr),
295  m_selftrans(false)
296  {
297  }
298 
299  virtual ~StateMachine();
300 
302  : m_num(other.m_num),
303  m_listener(other.m_listener),
304  m_entry (other.m_entry),
305  m_predo (other.m_predo),
306  m_do (other.m_do),
307  m_postdo(other.m_postdo),
308  m_exit (other.m_exit),
309  m_transit(other.m_transit),
310  m_states(other.m_states),
311  m_selftrans(other.m_selftrans)
312  {
313  }
314 
316  {
317  StateMachine temp(other);
318  swap(temp);
319  return *this;
320  }
321 
322  void swap(StateMachine& other)
323  {
324  std::swap(m_num, other.m_num);
325  std::swap(m_listener, other.m_listener);
326  std::swap(m_entry, other.m_entry);
327  std::swap(m_predo, other.m_predo);
328  std::swap(m_do, other.m_do);
329  std::swap(m_postdo, other.m_postdo);
330  std::swap(m_exit, other.m_exit);
331  std::swap(m_transit, other.m_transit);
332  std::swap(m_states, other.m_states);
333  std::swap(m_selftrans, other.m_selftrans);
334  }
352  void setNOP(Callback call_back)
353  {
354  setNullFunc(m_entry, call_back);
355  setNullFunc(m_do, call_back);
356  setNullFunc(m_exit, call_back);
357  setNullFunc(m_predo, call_back);
358  setNullFunc(m_postdo, call_back);
359  m_transit = call_back;
360  }
361 
379  void setListener(Listener* listener)
380  {
381  assert(listener != nullptr);
382  m_listener = listener;
383  }
384 
409  bool setEntryAction(State state, Callback call_back)
410  {
411  try
412  {
413  m_entry.at(state) = call_back;
414  }
415  catch (...)
416  {
417  assert(false);
418  return false;
419  }
420  return true;
421  }
422 
446  bool setPreDoAction(State state, Callback call_back)
447  {
448  try
449  {
450  m_predo.at(state) = call_back;
451  }
452  catch (...)
453  {
454  assert(false);
455  return false;
456  }
457  return true;
458  }
459 
483  bool setDoAction(State state, Callback call_back)
484  {
485  try
486  {
487  m_do.at(state) = call_back;
488  }
489  catch (...)
490  {
491  assert(false);
492  return false;
493  }
494  return true;
495  }
496 
520  bool setPostDoAction(State state, Callback call_back)
521  {
522  try
523  {
524  m_postdo.at(state) = call_back;
525  }
526  catch (...)
527  {
528  assert(false);
529  return false;
530  }
531  return true;
532  }
533 
557  bool setExitAction(State state, Callback call_back)
558  {
559  try
560  {
561  m_exit.at(state) = call_back;
562  }
563  catch (...)
564  {
565  assert(false);
566  return false;
567  }
568  return true;
569  }
570 
594  bool setTransitionAction(Callback call_back)
595  {
596  m_transit = call_back;
597  return true;
598  }
599 
617  void setStartState(States states)
618  {
619  m_states.curr = states.curr;
620  m_states.prev = states.prev;
621  m_states.next = states.next;
622  }
623 
644  States getStates()
645  {
646  std::lock_guard<std::mutex> guard(m_mutex);
647  return m_states;
648  }
649 
668  {
669  std::lock_guard<std::mutex> guard(m_mutex);
670  return m_states.curr;
671  }
672 
694  bool isIn(State state)
695  {
696  std::lock_guard<std::mutex> guard(m_mutex);
697  return m_states.curr == state ? true : false;
698  }
699 
726  void goTo(State state)
727  {
728  std::lock_guard<std::mutex> guard(m_mutex);
729  m_states.next = state;
730  if (m_states.curr == state)
731  {
732  m_selftrans = true;
733  }
734  }
735 
736 
753  void worker()
754  {
755  States state;
756 
757  sync(state);
758 
759  if (state.curr == state.next)
760  {
761  // pre-do
762  if (m_predo[state.curr] != NULL)
763  (m_listener->*m_predo[state.curr])(state);
764 
765  if (need_trans()) return;
766 
767  // do
768  if (m_do[state.curr] != NULL)
769  (m_listener->*m_do[state.curr])(state);
770 
771  if (need_trans()) return;
772 
773  // post-do
774  if (m_postdo[state.curr] != NULL)
775  (m_listener->*m_postdo[state.curr])(state);
776  }
777  else
778  {
779  if (m_exit[state.curr] != NULL)
780  (m_listener->*m_exit[state.curr])(state);
781 
782  sync(state);
783 
784  if (state.curr != state.next)
785  {
786  state.curr = state.next;
787  if (m_entry[state.curr] != NULL)
788  (m_listener->*m_entry[state.curr])(state);
789  update_curr(state.curr);
790  }
791  }
792  }
793 
794  //============================================================
795  // divided worker functions
796  // The following divided worker functions have to be used together.
797  // - worker_pre()
798  // - worker_do()
799  // - worker_post()
800  //
801  void worker_pre()
802  {
803  States state;
804  sync(state);
805  if (state.curr == state.next)
806  {
807  if (m_predo[state.curr] != nullptr)
808  {
809  (m_listener->*m_predo[state.curr])(state);
810  }
811  return;
812  }
813 
814  // State changed
815  if (m_exit[state.curr] != nullptr)
816  {
817  (m_listener->*m_exit[state.curr])(state);
818  }
819  sync(state);
820  if (state.curr != state.next)
821  {
822  state.curr = state.next;
823  if (m_entry[state.curr] != nullptr)
824  {
825  (m_listener->*m_entry[state.curr])(state);
826  }
827  update_curr(state.curr);
828  }
829  }
830 
831  void worker_do()
832  {
833  States state;
834  sync(state);
835  if (m_do[state.curr] != nullptr)
836  {
837  (m_listener->*m_do[state.curr])(state);
838  }
839  }
840 
841  void worker_post()
842  {
843  States state;
844  sync(state);
845  if (m_postdo[state.curr] != nullptr)
846  {
847  (m_listener->*m_postdo[state.curr])(state);
848  }
849  }
850 
851  protected:
871  void setNullFunc(std::vector<Callback>& s, Callback nullfunc)
872  {
873  s.clear();
874  for (size_t i(0); i < m_num; ++i)
875  {
876  s.emplace_back(nullfunc);
877  }
878  }
879 
887  int m_num;
888 
897 
905  std::vector<Callback> m_entry;
906 
914  std::vector<Callback> m_predo;
915 
923  std::vector<Callback> m_do;
924 
932  std::vector<Callback> m_postdo;
933 
941  std::vector<Callback> m_exit;
942 
950  Callback m_transit;
951 
959  States m_states;
961  std::mutex m_mutex;
962 
963  private:
964  inline void sync(States& st)
965  {
966  std::lock_guard<std::mutex> guard(m_mutex);
967  st = m_states;
968  }
969 
970  inline bool need_trans()
971  {
972  std::lock_guard<std::mutex> guard(m_mutex);
973  return (m_states.curr != m_states.next);
974  }
975 
976  inline void update_curr(const State curr)
977  {
978  std::lock_guard<std::mutex> guard(m_mutex);
979  m_states.curr = curr;
980  }
981  };
982 
983  // No inline for gcc warning, too big
984  template <class T, class U, class V, class W>
986 
987 } // namespace RTC_Utils
988 
989 #endif // RTC_STATEMACHINE_H
状態マシンクラス
Definition: StateMachine.h:267
void setNOP(Callback call_back)
NOP関数を登録する
Definition: StateMachine.h:352
State getState()
現在の状態を取得する
Definition: StateMachine.h:667
bool setTransitionAction(Callback call_back)
State transition action 関数を登録する
Definition: StateMachine.h:594
int m_num
状態数
Definition: StateMachine.h:887
Listener * m_listener
コールバック関数用リスナー
Definition: StateMachine.h:896
States m_states
現在の状態情報
Definition: StateMachine.h:959
void worker_pre()
Definition: StateMachine.h:801
void worker_post()
Definition: StateMachine.h:841
void setNullFunc(std::vector< Callback > &s, Callback nullfunc)
NOP関数を設定
Definition: StateMachine.h:871
bool setDoAction(State state, Callback call_back)
Do action 関数を登録する
Definition: StateMachine.h:483
void goTo(State state)
状態を遷移
Definition: StateMachine.h:726
void swap(StateMachine &other)
Definition: StateMachine.h:322
std::vector< Callback > m_postdo
PostDo action 用コールバック関数
Definition: StateMachine.h:932
void setStartState(States states)
初期状態をセットする
Definition: StateMachine.h:617
StateMachine & operator=(const StateMachine &other)
Definition: StateMachine.h:315
std::mutex m_mutex
Definition: StateMachine.h:961
bool setEntryAction(State state, Callback call_back)
Entry action 関数を登録する
Definition: StateMachine.h:409
bool isIn(State state)
現在状態を確認
Definition: StateMachine.h:694
std::vector< Callback > m_exit
Exit action 用コールバック関数
Definition: StateMachine.h:941
std::vector< Callback > m_entry
Entry action 用コールバック関数
Definition: StateMachine.h:905
bool setPreDoAction(State state, Callback call_back)
PreDo action 関数を登録する
Definition: StateMachine.h:446
void worker_do()
Definition: StateMachine.h:831
StateMachine(const StateMachine &other)
Definition: StateMachine.h:301
bool m_selftrans
Definition: StateMachine.h:960
Callback m_transit
State transition action 用コールバック関数
Definition: StateMachine.h:950
std::vector< Callback > m_do
Do action 用コールバック関数
Definition: StateMachine.h:923
bool setPostDoAction(State state, Callback call_back)
PostDo action 関数を登録する
Definition: StateMachine.h:520
bool setExitAction(State state, Callback call_back)
Exit action 関数を登録する
Definition: StateMachine.h:557
StateMachine(int num_of_state)
コンストラクタ
Definition: StateMachine.h:286
std::vector< Callback > m_predo
PreDo action 用コールバック関数
Definition: StateMachine.h:914
States getStates()
状態を取得する
Definition: StateMachine.h:644
void worker()
駆動関数
Definition: StateMachine.h:753
void setListener(Listener *listener)
Listener オブジェクトを登録する
Definition: StateMachine.h:379
Alias State()
Definition: Macho.h:1574
RTコンポーネント用ユーティリティ関数
状態保持用クラス
Definition: StateMachine.h:58
State curr
Definition: StateMachine.h:59
State prev
Definition: StateMachine.h:60
State next
Definition: StateMachine.h:61