38 #include "../ExecutionEngine.hpp" 39 #include "../internal/DataSource.hpp" 40 #include "../Service.hpp" 46 #include <boost/bind.hpp> 47 #include <boost/tuple/tuple.hpp> 50 #define TRACE(msg) do { \ 53 Logger::In in( _name ); \ 54 log(Info) << '[' << this->getStatusStr() << ']' << std::string(" ") + msg <<endlog(); \ 58 using namespace detail;
59 using boost::tuples::get;
61 using namespace boost;
64 std::string StateMachine::emptyString;
67 : smpStatus(nill), _parent (parent) , _name(name), smStatus(
Status::unloaded),
68 initstate(0), finistate(0), current( 0 ), next(0), initc(0),
69 currentProg(0), currentExit(0), currentHandle(0), currentEntry(0), currentRun(0), currentTrans(0),
70 checking_precond(false), mstep(false), mtrace(false), evaluating(0)
81 TRACE(
"StateMachine '" +
_name +
"' destroyed." );
85 TRACE(
"Being Loaded in ExecutionEngine." );
87 for(TransitionMap::iterator it=
stateMap.begin(); it !=
stateMap.end(); ++it) {
92 for(TransList::iterator tlit= it->second.begin(); tlit != it->second.end(); ++tlit ) {
94 get<4>(*tlit)->loaded( this->getEngine() );
100 for(EventList::iterator tlit= it->second.begin(); tlit != it->second.end(); ++tlit ) {
102 get<5>(*tlit)->loaded( this->getEngine() );
108 TRACE(
"Being unloaded from ExecutionEngine." );
119 <<
" into the final state. Program stalled in state '" 157 return "deactivating";
175 TRACE(
"Will pause." );
177 currentProg->
pause();
183 TRACE(
"Won't pause." );
190 TRACE(
"Will step." );
195 TRACE(
"Will step." );
199 TRACE(
"Won't step." );
214 TRACE(
"Will start." );
220 TRACE(
"Won't start." );
227 TRACE(
"Will enter reactive mode." );
231 TRACE(
"Won't enter reactive mode." );
238 TRACE(
"Will stop." );
242 TRACE(
"Won't stop." );
250 TRACE(
"Will reset.");
254 TRACE(
"Won't reset.");
271 TRACE(
"Is paused now.");
283 TRACE(
"Is stopped now.");
296 TRACE(
"Is reset now.");
316 TRACE(
"Is active now.");
336 TRACE(
"Did a step.");
346 TRACE(
"Is active now.");
352 TRACE(
"Is stopped now.");
357 TRACE(
"Is inactive now.");
362 TRACE(
"Is reset now.");
367 if ( current != finistate ) {
378 if (
interruptible() && ( current == initstate || current == finistate ) )
380 TRACE(
"Will enter initial state.");
385 TRACE(
"Won't enter initial state.");
394 TRACE(
"Won't enter final state.");
400 TRACE(
"Will enter final state.");
403 TRACE(
"Won't enter final state.");
408 if ( newState == current )
412 TRACE(
"Transition triggered to self: '"+current->
getName()+
"'");
414 if (transProg->
start() == false )
416 currentTrans = transProg;
418 reqstep =
stateMap.find( current )->second.begin();
428 if ( currentHandle == 0 )
434 TRACE(
"Transition triggered from '"+ (current ? current->
getName() :
"null") +
"' to '"+(newState ? newState->
getName() :
"null")+
"'.");
441 if ( transProg->
start() == false )
446 currentTrans = transProg;
448 if ( currentExit && currentExit->
inError() )
473 EventMap::mapped_type& hlist =
eventMap[s];
474 for (EventList::iterator eit = hlist.begin();
477 assert( get<6>(*eit).connected() == false );
478 get<6>(*eit).connect();
487 EventMap::mapped_type& hlist =
eventMap[s];
488 for (EventList::iterator eit = hlist.begin();
491 assert( get<6>(*eit).connected() == true );
492 get<6>(*eit).disconnect();
498 const std::string& ename, vector<DataSourceBase::shared_ptr> args,
501 StateInterface* elseto, boost::shared_ptr<ProgramInterface> elseprog )
503 Logger::In in(
"StateMachine::createEventTransition");
507 log(
Error) <<
"Can not receive event '"<< ename <<
"' in StateMachine : not a local operation."<< endlog();
511 if ( !( sp && guard ) ) {
512 log(
Error) <<
"Invalid arguments for event '"<< ename <<
"'. ";
514 log() <<
"Service was null. ";
516 log() <<
"Guard Condition was null. ";
538 log(
Debug) <<
"Creating Signal handler for Operation '"<< ename <<
"' from state "<< (from ? from->
getName() : string(
"(global)")) <<
" to state " << ( to ? to->
getName() : string(
"(global)") ) <<
Logger::endl;
539 #ifdef ORO_SIGNALLING_OPERATIONS 541 handle = sp->produceSignal( ename,
new CommandFunction( boost::bind( &StateMachine::eventTransition,
this, from, guard, transprog.get(), to, elseprog.get(), elseto) ), args, 0 );
543 if ( !handle.ready() ) {
551 eventMap[from].push_back( boost::make_tuple( sp, ename, args, to, guard, transprog, handle, elseto, elseprog) );
578 TRACE(
"Received Signal in state '"+ current->
getName()+
"' for transition from state '" + from->
getName() +
"' to state '" + to->
getName() +
"'");
591 " within state " + current->
getName() +
": guards failed.");
598 " within " + current->
getName() +
": already in transition.");
601 +
" within " + current->
getName() +
": wrong state.");
620 TransList::const_iterator it, it1, it2;
621 it1 =
stateMap.find( 0 )->second.begin();
622 it2 =
stateMap.find( 0 )->second.end();
624 if ( reqstep ==
stateMap.find( current )->second.begin() )
625 for ( it= it1; it != it2; ++it)
626 get<0>(*it)->reset();
628 if ( reqstep == reqend ) {
630 for ( ; it1 != it2; ++it1 )
631 if ( get<0>(*it1)->evaluate()
635 changeState( current, get<4>(*it1).get(), stepping );
648 if ( get<0>(*reqstep)->evaluate() ) {
650 if (reqstep == reqend )
658 changeState( get<1>(*reqstep), get<4>(*reqstep).get(), stepping );
663 if ( reqstep + 1 == reqend ) {
665 for ( ; it1 != it2; ++it1 ) {
666 if ( get<0>(*it1)->evaluate() &&
checkConditions( get<1>(*it1) ) == 1 ) {
669 changeState( current, get<4>(*it1).get(), stepping );
677 reqstep =
stateMap.find( current )->second.begin();
678 evaluating = get<3>(*reqstep);
684 evaluating = get<3>(*reqstep);
686 }
while ( !stepping );
694 if ( !checking_precond || !stepping ) {
701 while ( prec_it.first != prec_it.second ) {
702 if (checking_precond ==
false && stepping ) {
703 evaluating = prec_it.first->second.second;
704 checking_precond =
true;
707 if ( prec_it.first->second.first->evaluate() == false ) {
708 checking_precond =
false;
713 if ( prec_it.first != prec_it.second )
714 evaluating = prec_it.first->second.second;
715 checking_precond =
true;
719 checking_precond =
false;
730 TransList::const_iterator it1, it2;
731 it1 =
stateMap.find( current )->second.begin();
732 it2 =
stateMap.find( current )->second.end();
734 for ( ; it1 != it2; ++it1 )
735 if ( get<0>(*it1)->evaluate() &&
checkConditions( get<1>(*it1)) == 1 ) {
740 it1 =
stateMap.find( 0 )->second.begin();
741 it2 =
stateMap.find( 0 )->second.end();
743 for ( ; it1 != it2; ++it1 )
744 if ( get<0>(*it1)->evaluate() &&
checkConditions( get<1>(*it1)) == 1 ) {
752 vector<string> result;
753 vector<StateInterface*> sl;
756 sl.erase( find(sl.begin(), sl.end(), dummy) );
769 TransitionMap::const_iterator it =
stateMap.begin();
771 if ( it->first && it->first->getName() == name )
792 if ( current == s_n )
800 TransList::iterator it, it1, it2;
801 it1 =
stateMap.find( current )->second.begin();
802 it2 =
stateMap.find( current )->second.end();
804 for ( ; it1 != it2; ++it1 )
805 if ( get<1>(*it1) == s_n
806 && get<0>(*it1)->evaluate()
815 it1 =
stateMap.find( 0 )->second.begin();
816 it2 =
stateMap.find( 0 )->second.end();
819 for ( it= it1; it != it2; ++it)
820 get<0>(*it)->reset();
823 for ( ; it1 != it2; ++it1 )
824 if ( get<1>(*it1) == s_n
825 && get<0>(*it1)->evaluate()
834 if ( finistate == s_n )
842 if ( initstate == s_n && current == finistate)
858 if ( statecopy == 0 )
879 precondMap.insert( make_pair(state, make_pair( cnd, line)) );
885 this->
transitionSet( from, to, cnd, boost::shared_ptr<ProgramInterface>(), priority, line);
890 int priority,
int line )
899 TRACE(
"Created global transition to '"+ to->
getName()+
"'");
902 TransList::iterator it;
903 for ( it=
stateMap[from].begin(); it !=
stateMap[from].end() && get<2>(*it) >= priority; ++it)
905 stateMap[from].insert(it, boost::make_tuple( cnd, to, priority, line, transprog ) );
925 currentExit->
reset();
926 if (currentExit->
start() ==
false)
937 if (currentRun->
start() ==
false)
946 if ( currentHandle ) {
947 currentHandle->
reset();
948 if (currentHandle->
start() ==
false)
959 TransList::iterator it;
960 for ( it=
stateMap.find(s)->second.begin(); it !=
stateMap.find(s)->second.end(); ++it)
961 get<0>(*it)->reset();
964 if ( currentEntry ) {
965 currentEntry->
reset();
966 if (currentEntry->
start() ==
false)
984 TRACE(
"executePending..." );
986 if ( currentEntry ) {
987 TRACE(
"Executing entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
991 TRACE(
"Finished entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
994 currentProg = currentRun;
1001 if ( currentTrans ) {
1002 TRACE(
"Executing transition program from '"+ (current ? current->
getName() :
"(null)") +
"' to '"+ ( next ? next->
getName() :
"(null)")+
"'" );
1004 if ( currentHandle ) {
1011 TRACE(
"Finished transition program from '"+ (current ? current->
getName() :
"(null)") +
"' to '"+ ( next ? next->
getName() :
"(null)")+
"'" );
1014 currentProg = currentExit ? currentExit : (currentEntry ? currentEntry : currentRun);
1020 if ( currentExit ) {
1021 TRACE(
"Executing exit program from '"+ (current ? current->
getName() :
"(null)") +
"' (going to '"+ (next ? next->
getName() :
"(null)") +
"')" );
1025 TRACE(
"Finished exit program from '"+ (current ? current->
getName() :
"(null)") +
"' (going to '"+ (next ? next->
getName() :
"(null)") +
"')" );
1028 currentProg = (currentEntry ? currentEntry : currentRun);
1038 if ( current != next ) {
1040 reqstep =
stateMap.find( next )->second.begin();
1041 reqend =
stateMap.find( next )->second.end();
1043 if ( reqstep == reqend )
1046 evaluating = get<3>(*reqstep);
1052 TRACE(
"Formally transitioning from '"+ (current ? current->
getName() :
"(null)") +
"' to '"+ (next ? next->
getName() :
"(null)") +
"'" );
1062 if ( currentEntry ) {
1063 TRACE(
"Executing entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1067 TRACE(
"Finished entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1070 currentProg = currentRun;
1076 if ( currentHandle ) {
1077 TRACE(
"Executing handle program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1081 TRACE(
"Finished handle program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1084 currentProg = currentRun;
1091 TRACE(
"Executing run program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1095 TRACE(
"Finished run program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1111 currentProg->
step();
1114 if ( currentProg && currentProg->
inError() ) {
1121 if ( currentProg && !currentProg->
isStopped() )
1124 cp = currentProg = 0;
1131 return ( (currentProg != 0) && (currentProg != currentRun) && (currentProg != currentHandle) ) || (current != next);
1136 return currentProg == 0 || currentProg == currentRun;
1159 TRACE(
"Won't activate: already active.");
1167 TRACE(
"Won't activate: preconditions failed.");
1174 if ( initc->
execute() == false ) {
1175 TRACE(
"Won't activate: Init Commands failed.");
1183 reqstep =
stateMap.find( next )->second.begin();
1184 reqend =
stateMap.find( next )->second.end();
1194 TRACE(
"Activated.");
1197 TRACE(
"Still activating.");
1211 TRACE(
"Won't deactivate: already inactive.");
1221 if ( currentExit && currentExit->
inError() )
1223 if ( currentTrans && currentTrans->
inError() )
1227 if ( next != 0 && current ) {
1245 TRACE(
"Deactivated.");
1248 TRACE(
"Still deactivating.");
ActivityInterface * getActivity() const
Query for the task this interface is run in.
bool executePending(bool stepping=false)
Execute any pending State (exit, entry, handle) programs.
virtual bool trigger()=0
Trigger that work has to be done.
void loading()
Informs this object that it got loaded in an ExecutionEngine.
void transitionSet(StateInterface *from, StateInterface *to, ConditionInterface *cnd, int priority, int line)
Express a possible transition from one state to another under a certain condition.
The interface class for operation callers.
virtual bool removeFunction(base::ExecutableInterface *f)
Remove a running function added with runFunction.
bool isAutomatic() const
Query if the state machine is reacting to events and evaluating transition conditions.
virtual void reset()
Reset this action.
void disableGlobalEvents()
bool isStopped() const
Returns true if the program is not executing (stopped) or not loaded.
std::vector< std::string > getStateList() const
Get a list of the names of all the present states.
void enableEvents(StateInterface *s)
bool isLoaded()
Returns true if this object is loaded in an ExecutionEngine.
virtual void reset()=0
Reset the execution point to the beginning of this program interface.
This interface represents the concept of a condition which can be evaluated and return true or false...
bool deactivate()
Stop this StateMachine.
bool interruptible() const
Inspect if the StateMachine is interruptible by events.
virtual ~StateMachine()
The destructor is virtual since ParsedStateMachine still inherits this class.
const std::string & getName() const
This method must be overloaded to get a useful hierarchy.
bool reset()
Reset the state machine from the final state to the initial state and wait for events or requests...
virtual void readArguments()=0
This is invoked some time before execute() at a time when the action may read its function arguments...
virtual int getEntryPoint() const =0
Get the beginning definition of this State.
virtual bool pause()=0
Pause or start-and-pause the execution of this program.
std::string getStatusStr() const
Get the status in a readable string format.
virtual const std::string & getName() const =0
Get the name of this state.
void setFinalState(StateInterface *s)
Set the final state of this StateMachine.
void disableEvents(StateInterface *s)
void preconditionSet(StateInterface *state, ConditionInterface *cnd, int line)
Express a precondition for entering a state.
virtual ProgramInterface * getEntryProgram() const =0
Get the entry program of this State.
boost::shared_ptr< OperationCallerInterface > shared_ptr
Use this type for shared pointer storage of an OperationCallerInterface object.
bool pause()
Pause the state machine.
An execution engine serialises (executes one after the other) the execution of all commands...
ProgramInterface * currentProgram() const
Retrieve the current program in execution.
virtual ProgramInterface * getHandleProgram() const =0
Get the handle program of this State.
StateInterface * nextState()
Search from the current state a candidate next state.
void enableGlobalEvents()
bool execute()
Used by the StateMachineProcessor to execute the next action(s) or state transitions.
int getLineNumber() const
Returns the current program line in execution,.
virtual bool start()=0
Start the execution of this program.
bool step()
Execute a single action if the state machine is paused or evaluate the transition conditions if the s...
virtual bool step()=0
Execute a single action when paused.
void handleState(StateInterface *s)
virtual bool execute()=0
Execute as much actions until the program needs to wait on a condition to become true.
bool inError() const
Get the error status of this StateMachine.
Status::StateMachineStatus getStatus() const
Get the status of this state machine.
boost::shared_ptr< Service > ServicePtr
void addState(StateInterface *s)
Add a State.
virtual bool execute()=0
Execute the functionality of this action.
virtual int getLineNumber() const =0
Return the current 'line number' of the program.
StateInterface * currentState() const
Retrieve the current state of the state machine.
Status::StateMachineStatus smStatus
static std::ostream & endl(std::ostream &__os)
void unloading()
Informs this object that it got unloaded from an ExecutionEngine.
bool executeProgram(ProgramInterface *&cp, bool stepping)
void trace(bool on_off)
Turn log(Debug) messages on or off to track state transitions.
boost::shared_ptr< StateMachine > StateMachinePtr
void changeState(StateInterface *s, ProgramInterface *tprog, bool stepping=false)
bool start()
Enter automatic mode: evaluating the transition conditions continuously.
boost::shared_ptr< DisposableInterface > shared_ptr
Use this type for shared pointer storage of an DisposableInterface object.
StateInterface * getInitialState() const
Retrieve the initial state of the state machine.
ExecutionEngine * getEngine()
Returns the ExecutionEngine this object is loaded into or null otherwise.
Enumerates all possible state machine statuses.
PreConditionMap precondMap
A map keeping track of all preconditions of a state.
virtual ProgramInterface * getExitProgram() const =0
Get the exit program of this State.
void runState(StateInterface *s)
bool requestInitialState()
Request going to the Initial State.
virtual ProgramInterface * getRunProgram() const =0
Get the run program of this State.
bool activate()
Start this StateMachine.
StateInterface * getState(const std::string &name) const
Lookup a State by name.
bool requestFinalState()
Request going to the Final State.
Notify the Logger in which 'module' the message occured.
virtual bool evaluate()=0
Evaluate the Condition and return the outcome.
static Logger & log()
As Instance(), but more userfriendly.
bool isReactive() const
Query if the state machine is currently reacting only to events.
StateInterface * requestNextState(bool stepping=false)
Search from the current state a candidate next state.
void setInitialState(StateInterface *s)
Set the initial state of this StateMachine.
int checkConditions(StateInterface *state, bool stepping=false)
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
TransitionMap stateMap
A map keeping track of all States and conditional transitions between two states. ...
A functor with the base::ActionInterface, for the case where the functor is a bool(void).
A State contains an entry, run, handle and exit program.
A Program represents a collection of instructions that can be stepwise executed.
bool requestStateChange(StateInterface *s_n)
Request a state transition to a new state.
StateInterface * getFinalState() const
Retrieve the final state of the state machine.
bool isActive() const
Returns true if the state machine is activated.
The Handle holds the information, and allows manipulation, of a connection between a internal::Signal...
bool reactive()
Switch to reactive mode from automatic mode.
bool inTransition() const
Inspect if the StateMachine is performing a state transition.
bool inError() const
Returns true if the program is in error.
StateMachine(StateMachinePtr parent, const std::string &name="Default")
Create a new StateMachine with an optional parent.
bool automatic()
Enter automatic mode: evaluating the transition conditions continuously.
EventMap eventMap
A map keeping track of all events of a state.
bool stop()
Bring the state machine to the safe final state and wait for events or requests.
void enterState(StateInterface *s)
void leaveState(StateInterface *s)
MutexLock is a scope based Monitor, protecting critical sections with a Mutex object through locking ...
bool createEventTransition(ServicePtr sp, ExecutionEngine *target_engine, const std::string &ename, std::vector< base::DataSourceBase::shared_ptr > args, StateInterface *from, StateInterface *to, ConditionInterface *guard, boost::shared_ptr< ProgramInterface > transprog, StateInterface *elseto=0, boost::shared_ptr< ProgramInterface > elseprog=boost::shared_ptr< ProgramInterface >())
Express a possible transition from one state to another when an Event is fired under a certain condit...
virtual std::string getText() const
Return the text to which getLineNumber() refers.