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.");
325 TRACE(
"Yielding...");
338 TRACE(
"Did a step.");
348 TRACE(
"Is active now.");
354 TRACE(
"Is stopped now.");
359 TRACE(
"Is inactive now.");
364 TRACE(
"Is reset now.");
369 if ( current != finistate ) {
380 if (
interruptible() && ( current == initstate || current == finistate ) )
382 TRACE(
"Will enter initial state.");
387 TRACE(
"Won't enter initial state.");
396 TRACE(
"Won't enter final state.");
402 TRACE(
"Will enter final state.");
405 TRACE(
"Won't enter final state.");
410 if ( newState == current )
414 TRACE(
"Transition triggered to self: '"+current->
getName()+
"'");
416 if (transProg->
start() == false )
418 currentTrans = transProg;
420 reqstep =
stateMap.find( current )->second.begin();
430 if ( currentHandle == 0 )
436 TRACE(
"Transition triggered from '"+ (current ? current->
getName() :
"null") +
"' to '"+(newState ? newState->
getName() :
"null")+
"'.");
443 if ( transProg->
start() == false )
447 currentTrans = transProg;
453 assert( currentEntry == 0);
476 EventMap::mapped_type& hlist =
eventMap[s];
477 for (EventList::iterator eit = hlist.begin();
480 assert( get<6>(*eit).connected() == false );
481 get<6>(*eit).connect();
490 EventMap::mapped_type& hlist =
eventMap[s];
491 for (EventList::iterator eit = hlist.begin();
494 assert( get<6>(*eit).connected() == true );
495 get<6>(*eit).disconnect();
501 const std::string& ename, vector<DataSourceBase::shared_ptr> args,
504 StateInterface* elseto, boost::shared_ptr<ProgramInterface> elseprog )
506 Logger::In in(
"StateMachine::createEventTransition");
510 log(
Error) <<
"Can not receive event '"<< ename <<
"' in StateMachine : not a local operation."<< endlog();
514 if ( !( sp && guard ) ) {
515 log(
Error) <<
"Invalid arguments for event '"<< ename <<
"'. ";
517 log() <<
"Service was null. ";
519 log() <<
"Guard Condition was null. ";
541 log(
Debug) <<
"Creating Signal handler for Operation '"<< ename <<
"' from state "<< (from ? from->
getName() : string(
"(global)")) <<
" to state " << ( to ? to->
getName() : string(
"(global)") ) <<
Logger::endl;
542 #ifdef ORO_SIGNALLING_OPERATIONS 544 handle = sp->produceSignal( ename,
new CommandFunction( boost::bind( &StateMachine::eventTransition,
this, from, guard, transprog.get(), to, elseprog.get(), elseto) ), args, 0 );
546 if ( !handle.ready() ) {
554 eventMap[from].push_back( boost::make_tuple( sp, ename, args, to, guard, transprog, handle, elseto, elseprog) );
581 TRACE(
"Received Signal in state '"+ current->
getName()+
"' for transition from state '" + from->
getName() +
"' to state '" + to->
getName() +
"'");
595 " within state " + current->
getName() +
": guards failed.");
599 " within state " + current->
getName() +
": preconditions failed.");
606 " within " + current->
getName() +
": already in transition.");
609 +
" within " + current->
getName() +
": wrong state.");
628 TransList::const_iterator it, it1, it2;
629 it1 =
stateMap.find( 0 )->second.begin();
630 it2 =
stateMap.find( 0 )->second.end();
632 if ( reqstep ==
stateMap.find( current )->second.begin() )
633 for ( it= it1; it != it2; ++it)
634 get<0>(*it)->reset();
636 if ( reqstep == reqend ) {
638 for ( ; it1 != it2; ++it1 )
639 if ( get<0>(*it1)->evaluate()
643 changeState( current, get<4>(*it1).get(), stepping );
656 if ( get<0>(*reqstep)->evaluate() ) {
658 if (reqstep == reqend )
666 changeState( get<1>(*reqstep), get<4>(*reqstep).get(), stepping );
671 if ( reqstep + 1 == reqend ) {
673 for ( ; it1 != it2; ++it1 ) {
674 if ( get<0>(*it1)->evaluate() &&
checkConditions( get<1>(*it1) ) == 1 ) {
677 changeState( current, get<4>(*it1).get(), stepping );
685 reqstep =
stateMap.find( current )->second.begin();
686 evaluating = get<3>(*reqstep);
692 evaluating = get<3>(*reqstep);
694 }
while ( !stepping );
702 if ( !checking_precond || !stepping ) {
709 while ( prec_it.first != prec_it.second ) {
710 if (checking_precond ==
false && stepping ) {
711 evaluating = prec_it.first->second.second;
712 checking_precond =
true;
715 if ( prec_it.first->second.first->evaluate() == false ) {
716 checking_precond =
false;
721 if ( prec_it.first != prec_it.second )
722 evaluating = prec_it.first->second.second;
723 checking_precond =
true;
727 checking_precond =
false;
738 TransList::const_iterator it1, it2;
739 it1 =
stateMap.find( current )->second.begin();
740 it2 =
stateMap.find( current )->second.end();
742 for ( ; it1 != it2; ++it1 )
743 if ( get<0>(*it1)->evaluate() &&
checkConditions( get<1>(*it1)) == 1 ) {
748 it1 =
stateMap.find( 0 )->second.begin();
749 it2 =
stateMap.find( 0 )->second.end();
751 for ( ; it1 != it2; ++it1 )
752 if ( get<0>(*it1)->evaluate() &&
checkConditions( get<1>(*it1)) == 1 ) {
760 vector<string> result;
761 vector<StateInterface*> sl;
764 sl.erase( find(sl.begin(), sl.end(), dummy) );
777 TransitionMap::const_iterator it =
stateMap.begin();
779 if ( it->first && it->first->getName() == name )
800 if ( current == s_n )
808 TransList::iterator it, it1, it2;
809 it1 =
stateMap.find( current )->second.begin();
810 it2 =
stateMap.find( current )->second.end();
812 for ( ; it1 != it2; ++it1 )
813 if ( get<1>(*it1) == s_n
814 && get<0>(*it1)->evaluate()
823 it1 =
stateMap.find( 0 )->second.begin();
824 it2 =
stateMap.find( 0 )->second.end();
827 for ( it= it1; it != it2; ++it)
828 get<0>(*it)->reset();
831 for ( ; it1 != it2; ++it1 )
832 if ( get<1>(*it1) == s_n
833 && get<0>(*it1)->evaluate()
842 if ( finistate == s_n )
850 if ( initstate == s_n && current == finistate)
866 if ( statecopy == 0 )
887 precondMap.insert( make_pair(state, make_pair( cnd, line)) );
893 this->
transitionSet( from, to, cnd, boost::shared_ptr<ProgramInterface>(), priority, line);
898 int priority,
int line )
907 TRACE(
"Created global transition to '"+ to->
getName()+
"'");
910 TransList::iterator it;
911 for ( it=
stateMap[from].begin(); it !=
stateMap[from].end() && get<2>(*it) >= priority; ++it)
913 stateMap[from].insert(it, boost::make_tuple( cnd, to, priority, line, transprog ) );
933 currentExit->
reset();
934 if (currentExit->
start() ==
false)
945 if (currentRun->
start() ==
false)
954 if ( currentHandle ) {
955 currentHandle->
reset();
956 if (currentHandle->
start() ==
false)
967 TransList::iterator it;
968 for ( it=
stateMap.find(s)->second.begin(); it !=
stateMap.find(s)->second.end(); ++it)
969 get<0>(*it)->reset();
972 if ( currentEntry ) {
973 currentEntry->
reset();
974 if (currentEntry->
start() ==
false)
993 if ( currentEntry ) {
994 TRACE(
"Executing entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
998 TRACE(
"Finished entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1001 currentProg = currentRun;
1007 if ( currentTrans ) {
1008 TRACE(
"Executing transition program from '"+ (current ? current->
getName() :
"(null)") +
"' to '"+ ( next ? next->
getName() :
"(null)")+
"'" );
1010 if ( currentHandle ) {
1017 TRACE(
"Finished transition program from '"+ (current ? current->
getName() :
"(null)") +
"' to '"+ ( next ? next->
getName() :
"(null)")+
"'" );
1020 currentProg = currentExit ? currentExit : (currentEntry ? currentEntry : currentRun);
1026 if ( currentExit ) {
1027 TRACE(
"Executing exit program from '"+ (current ? current->
getName() :
"(null)") +
"' (going to '"+ (next ? next->
getName() :
"(null)") +
"')" );
1031 TRACE(
"Finished exit program from '"+ (current ? current->
getName() :
"(null)") +
"' (going to '"+ (next ? next->
getName() :
"(null)") +
"')" );
1034 currentProg = (currentEntry ? currentEntry : currentRun);
1041 if ( current != next ) {
1043 reqstep =
stateMap.find( next )->second.begin();
1044 reqend =
stateMap.find( next )->second.end();
1046 if ( reqstep == reqend )
1049 evaluating = get<3>(*reqstep);
1055 TRACE(
"Formally transitioning from '"+ (current ? current->
getName() :
"(null)") +
"' to '"+ (next ? next->
getName() :
"(null)") +
"'" );
1063 if ( currentEntry ) {
1064 TRACE(
"Executing entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1068 TRACE(
"Finished entry program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1071 currentProg = currentRun;
1081 if ( currentHandle ) {
1082 TRACE(
"Executing handle program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1086 TRACE(
"Finished handle program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1089 currentProg = currentRun;
1096 TRACE(
"Executing run program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1100 TRACE(
"Finished run program of '"+ (current ? current->
getName() :
"(null)") +
"'" );
1116 currentProg->
step();
1119 if ( currentProg && currentProg->
inError() ) {
1126 if ( currentProg && !currentProg->
isStopped() )
1129 cp = currentProg = 0;
1136 return ( (currentProg != 0) && (currentProg != currentRun) && (currentProg != currentHandle) ) || (current != next);
1141 return currentProg == 0 || currentProg == currentRun;
1164 TRACE(
"Won't activate: already active.");
1172 TRACE(
"Won't activate: preconditions failed.");
1179 if ( initc->
execute() == false ) {
1180 TRACE(
"Won't activate: Init Commands failed.");
1188 reqstep =
stateMap.find( next )->second.begin();
1189 reqend =
stateMap.find( next )->second.end();
1199 TRACE(
"Activated.");
1202 TRACE(
"Still activating.");
1216 TRACE(
"Won't deactivate: already inactive.");
1226 if ( currentExit && currentExit->
inError() )
1228 if ( currentTrans && currentTrans->
inError() )
1232 if ( next != 0 && current ) {
1250 TRACE(
"Deactivated.");
1253 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.
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.
virtual bool timeout()=0
Requests this Activity to wakeup and call step() + work(Timeout).
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.