Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

StateMachine.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00019 /*
00020  * $Log: StateMachine.h,v $
00021  * Revision 1.3  2007/04/26 15:33:39  n-ando
00022  * The header include order was modified to define _REENTRANT before
00023  * including ace/config-lite.h in Linux systems.
00024  * In ace 5.4.7 or later, _REENTRANT flag should be defined explicitly.
00025  *
00026  * Revision 1.2  2007/01/09 15:26:53  n-ando
00027  * Now StateMachine does not need NOP function.
00028  * All null function pointer is checked and skipped.
00029  *
00030  * Revision 1.1  2006/10/26 08:55:53  n-ando
00031  * The first commitment.
00032  *
00033  *
00034  */
00035 
00036 #ifndef StateMachine_h
00037 #define StateMachine_h
00038 
00039 #include <rtm/RTC.h>
00040 
00041 #include <ace/Guard_T.h>
00042 #include <ace/Thread_Mutex.h>
00043 
00044 template <class State>
00045 struct StateHolder
00046 {
00047   State curr;
00048   State prev;
00049   State next;
00050 };
00051 
00144 template <class State, class Result,
00145           class Listener,
00146           class States = StateHolder<State>, 
00147           class Callback = Result (Listener::*)(const States& states)
00148           >
00149 class StateMachine
00150 {
00151 public:
00159   StateMachine(int num_of_state)
00160     : m_num(num_of_state),
00161       m_entry (new Callback[m_num]),
00162       m_predo (new Callback[m_num]),
00163       m_do    (new Callback[m_num]),
00164       m_postdo(new Callback[m_num]),
00165       m_exit  (new Callback[m_num])
00166   {
00167     setNullFunc(m_entry,  NULL);
00168     setNullFunc(m_do,     NULL);
00169     setNullFunc(m_exit,   NULL);
00170     setNullFunc(m_predo,  NULL);
00171     setNullFunc(m_postdo, NULL);
00172     m_transit = NULL;
00173   };
00174 
00175 
00183   void setNOP(Callback call_back)
00184   {
00185     setNullFunc(m_entry,  call_back);
00186     setNullFunc(m_do,     call_back);
00187     setNullFunc(m_exit,   call_back);
00188     setNullFunc(m_predo,  call_back);
00189     setNullFunc(m_postdo, call_back);
00190     m_transit = call_back;
00191   }
00192 
00193 
00201   void setListener(Listener* listener)
00202   {
00203     m_listener = listener;
00204   }
00205 
00206 
00214   bool setEntryAction(State state, Callback call_back)
00215   {
00216     m_entry[state] = call_back;
00217     return true;
00218   }
00219 
00220 
00228   bool setPreDoAction(State state, Callback call_back)
00229   {
00230     m_predo[state] = call_back;
00231     return true;
00232   }
00233 
00234 
00242   bool setDoAction(State state, Callback call_back)
00243   {
00244     m_do[state] = call_back;
00245     return true;
00246     
00247   }
00248 
00249 
00257   bool setPostDoAction(State state, Callback call_back)
00258   {
00259     m_postdo[state] = call_back;
00260     return true;
00261   }
00262 
00263 
00271   bool setExitAction(State state, Callback call_back)
00272   {
00273     m_exit[state] = call_back;
00274     return true;
00275   }
00276 
00277 
00285   bool setTransitionAction(Callback call_back)
00286   {
00287     m_transit = call_back;
00288     return true;
00289   }
00290 
00291 
00299   void setStartState(States states)
00300   {
00301     m_states.curr = states.curr;
00302     m_states.prev = states.prev;
00303     m_states.next = states.next;
00304   }
00305 
00306 
00314   States getStates()
00315   {
00316     ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00317     return m_states;
00318   }
00319   
00320   State getState()
00321   {
00322     ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00323     return m_states.curr;
00324   }
00325   
00326 
00334   bool isIn(State state)
00335   {
00336     ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00337     return m_states.curr == state ? true : false;
00338   }
00339 
00340 
00348   void goTo(State state)
00349   {
00350     ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00351     m_states.next = state;
00352     if (m_states.curr == state)
00353       {
00354         m_selftrans  = true;
00355       }
00356   }
00357 
00358 
00366   Result worker()
00367   {
00368     Result res;
00369     States state;
00370     bool selftrans;
00371 
00372     { // lock
00373       ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00374       state = m_states;
00375       selftrans = m_selftrans;
00376       m_selftrans = false;
00377     }
00378 
00379     // Entry アクション
00380     // 前回から状態が変わった
00381     // もしくは自己遷移が行われたのでEntryアクションを行う
00382     if ((state.prev != state.curr) || selftrans)
00383       {
00384         // Entry アクションを実行
00385         if (m_entry[state.curr] != NULL)
00386           res = (m_listener->*m_entry[state.curr])(state);
00387       }
00388 
00389     // この区間では状態の変更を感知しない。
00390     // ただし状態変数 m_states は外部から変更される可能性がある。
00391     // Do アクション判定にはローカル変数を使う。
00392 
00393     // Do アクション
00394     if (state.curr == state.next)
00395       {
00396         if (m_predo[state.curr] != NULL)
00397           res = (m_listener->*m_predo [state.curr])(state);
00398         if (m_do[state.curr] != NULL)
00399           res = (m_listener->*m_do    [state.curr])(state);
00400         if (m_postdo[state.curr] != NULL)
00401           res = (m_listener->*m_postdo[state.curr])(state);
00402       }
00403 
00404     // この区間では次の状態が変更されているかもしれない。
00405     // 状態は m_states.next に反映されている。
00406     // lock
00407     {
00408       ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00409       // 状態のコピー
00410       state.next = m_states.next;
00411       selftrans = m_selftrans;
00412     }
00413 
00414     // Exit アクション
00415     if ((state.curr != state.next) || selftrans)
00416       {
00417         // Exit action of pre-state
00418         if (m_exit[state.curr] != NULL)
00419           res = (m_listener->*m_exit[state.curr])(state);
00420         if (m_transit != NULL)
00421           res = (m_listener->*m_transit)(state);
00422       }
00423 
00424     {
00425       ACE_Guard<ACE_Thread_Mutex> guard(m_mutex);
00426       // 状態を更新
00427       m_states.prev = m_states.curr;
00428       m_states.curr = m_states.next;
00429     }
00430 
00431     return res;
00432   }
00433 
00434 protected:
00435   void setNullFunc(Callback* s, Callback nullfunc)
00436   {
00437     for (int i = 0; i < m_num; ++i) s[i] = nullfunc;
00438   }
00439 
00440 
00441   int m_num;
00442   Listener* m_listener;
00443   Callback* m_entry;
00444   Callback* m_predo;
00445   Callback* m_do;
00446   Callback* m_postdo;
00447   Callback* m_exit;
00448   Callback  m_transit;
00449 
00450   States m_states;
00451   bool m_selftrans;
00452   ACE_Thread_Mutex m_mutex;
00453 };
00454 
00455 #endif // StateMachine_h

Generated on Tue May 29 16:45:37 2007 for OpenRTM by  doxygen 1.4.1