00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "StateMachine.hpp"
00038 #include "../ExecutionEngine.hpp"
00039 #include "../internal/DataSource.hpp"
00040 #include "../Service.hpp"
00041 #include "CommandFunctors.hpp"
00042 #include <Logger.hpp>
00043 #include <functional>
00044
00045 #include <assert.h>
00046 #include <boost/bind.hpp>
00047 #include <boost/tuple/tuple.hpp>
00048 #include "internal/mystd.hpp"
00049
00050 #define TRACE_INIT() Logger::In in( _name )
00051 #define TRACE(msg) if (mtrace) log(Info) << '[' << this->getStatusStr() << ']' << std::string(" ") + msg <<endlog()
00052
00053 namespace RTT {
00054 using namespace detail;
00055 using boost::tuples::get;
00056 using namespace std;
00057 using namespace boost;
00058
00059
00060 std::string StateMachine::emptyString;
00061
00062 StateMachine::StateMachine(StateMachinePtr parent, const string& name )
00063 : smpStatus(nill), _parent (parent) , _name(name), smStatus(Status::unloaded),
00064 initstate(0), finistate(0), current( 0 ), next(0), initc(0),
00065 currentProg(0), currentExit(0), currentHandle(0), currentEntry(0), currentRun(0), currentTrans(0),
00066 checking_precond(false), mstep(false), mtrace(false), evaluating(0)
00067 {
00068 this->addState(0);
00069 }
00070
00071 StateMachine::~StateMachine()
00072 {
00073 TRACE_INIT();
00074 if ( this->isLoaded() ){
00075 getEngine()->removeFunction(this);
00076 }
00077 delete initc;
00078 TRACE( "StateMachine '" + _name + "' destroyed." );
00079 }
00080
00081 void StateMachine::loading() {
00082 TRACE_INIT();
00083 TRACE( "Being Loaded in ExecutionEngine." );
00084 smStatus = Status::inactive;
00085 for(TransitionMap::iterator it=stateMap.begin(); it != stateMap.end(); ++it) {
00086
00087 if (it->first)
00088 it->first->loaded( this->getEngine() );
00089
00090 for(TransList::iterator tlit= it->second.begin(); tlit != it->second.end(); ++tlit ) {
00091 if ( get<4>(*tlit) )
00092 get<4>(*tlit)->loaded( this->getEngine() );
00093 }
00094 }
00095 for( EventMap::iterator it = eventMap.begin(); it != eventMap.end(); ++it)
00096 {
00097
00098 for(EventList::iterator tlit= it->second.begin(); tlit != it->second.end(); ++tlit ) {
00099 if ( get<5>(*tlit) )
00100 get<5>(*tlit)->loaded( this->getEngine() );
00101 }
00102 }
00103 }
00104
00105 void StateMachine::unloading() {
00106 TRACE_INIT();
00107 TRACE( "Being unloaded from ExecutionEngine." );
00108 if ( this->isActive() == false)
00109 return;
00110 if ( this->isReactive() )
00111 this->requestFinalState();
00112 if ( this->isAutomatic() )
00113 this->stop();
00114 if (this->currentState() != this->getFinalState() )
00115 this->execute();
00116 if (this->currentState() != this->getFinalState() )
00117 log(Critical) << "Failed to bring StateMachine "<< this->getName()
00118 << " into the final state. Program stalled in state '"
00119 << this->currentState()->getName()<<"' line number "
00120 << this->getLineNumber()<<endlog();
00121 }
00122
00123 StateMachine::Status::StateMachineStatus StateMachine::getStatus() const {
00124 return smStatus;
00125 }
00126
00127 string StateMachine::getStatusStr() const {
00128
00129 switch ( smStatus )
00130 {
00131 case Status::inactive:
00132 return "inactive";
00133 break;
00134 case Status::stopping:
00135 return "stopping";
00136 break;
00137 case Status::stopped:
00138 return "stopped";
00139 break;
00140 case Status::requesting:
00141 return "requesting";
00142 break;
00143 case Status::running:
00144 return "running";
00145 break;
00146 case Status::paused:
00147 return "paused";
00148 break;
00149 case Status::active:
00150 return "active";
00151 break;
00152 case Status::activating:
00153 return "activating";
00154 break;
00155 case Status::deactivating:
00156 return "deactivating";
00157 break;
00158 case Status::resetting:
00159 return "resetting";
00160 break;
00161 case Status::error:
00162 return "error";
00163 break;
00164 case Status::unloaded:
00165 return "unloaded";
00166 break;
00167 }
00168 return "na";
00169 }
00170
00171 bool StateMachine::pause()
00172 {
00173 if ( smStatus != Status::inactive && smStatus != Status::unloaded ) {
00174 TRACE_INIT();
00175 TRACE( "Will pause." );
00176 if (currentProg) {
00177 currentProg->pause();
00178 currentProg->execute();
00179 }
00180 smpStatus = pausing;
00181 return true;
00182 }
00183 TRACE( "Won't pause." );
00184 return false;
00185 }
00186
00187 bool StateMachine::step()
00188 {
00189 TRACE_INIT();
00190 if ( smStatus == Status::paused && mstep == false ) {
00191 TRACE( "Will step." );
00192 mstep = true;
00193 return true;
00194 }
00195 if ( smStatus == Status::active ) {
00196 TRACE( "Will step." );
00197 smStatus = Status::requesting;
00198 return true;
00199 }
00200 TRACE( "Won't step." );
00201 return false;
00202 }
00203
00204 bool StateMachine::start()
00205 {
00206 return this->automatic();
00207 }
00208
00209 bool StateMachine::automatic()
00210 {
00211 TRACE_INIT();
00212
00213
00214
00215 if ( smStatus != Status::inactive && smStatus != Status::unloaded && smStatus != Status::error) {
00216 TRACE( "Will start." );
00217 smStatus = Status::running;
00218 runState( current );
00219 return true;
00220 }
00221 TRACE( "Won't start." );
00222 return false;
00223 }
00224
00225 bool StateMachine::reactive()
00226 {
00227 TRACE_INIT();
00228 if ( smStatus != Status::inactive && smStatus != Status::unloaded && smStatus != Status::error ) {
00229 TRACE( "Will enter reactive mode." );
00230 smStatus = Status::active;
00231 return true;
00232 }
00233 TRACE( "Won't enter reactive mode." );
00234 return false;
00235 }
00236
00237 bool StateMachine::stop()
00238 {
00239 TRACE_INIT();
00240 if ( smStatus != Status::inactive && smStatus != Status::unloaded ) {
00241 TRACE( "Will stop." );
00242 smpStatus = gostop;
00243 return true;
00244 }
00245 TRACE( "Won't stop." );
00246 return false;
00247 }
00248
00249 bool StateMachine::reset()
00250 {
00251 TRACE_INIT();
00252
00253 if ( smStatus == Status::stopped ) {
00254 TRACE( "Will reset.");
00255 smpStatus = goreset;
00256 return true;
00257 }
00258 TRACE("Won't reset.");
00259 return false;
00260 }
00261
00262 bool StateMachine::execute()
00263 {
00264 TRACE_INIT();
00265 os::MutexLock lock(execlock);
00266
00267
00268 if (smStatus == Status::inactive || smStatus == Status::unloaded) {
00269 smpStatus = nill;
00270 return true;
00271 }
00272
00273
00274 switch (smpStatus) {
00275 case pausing:
00276 TRACE("Is paused now.");
00277 smStatus = Status::paused;
00278 smpStatus = nill;
00279 return true;
00280 break;
00281 case gostop:
00282 this->executePending();
00283 if ( this->requestFinalState() ) {
00284
00285 if ( this->inTransition() ) {
00286 smStatus = Status::stopping;
00287 } else {
00288 TRACE("Is stopped now.");
00289 smStatus = Status::stopped;
00290 }
00291 smpStatus = nill;
00292 }
00293 return true;
00294 break;
00295 case goreset:
00296 if ( this->executePending() ) {
00297 this->requestInitialState();
00298 if ( this->inTransition() ) {
00299 smStatus = Status::resetting;
00300 } else {
00301 TRACE("Is reset now.");
00302 smStatus = Status::active;
00303 }
00304 }
00305 smpStatus = nill;
00306 return true;
00307 break;
00308 case nill:
00309 break;
00310 }
00311
00312
00313 switch (smStatus) {
00314 case Status::inactive:
00315 return true;
00316 break;
00317 case Status::requesting:
00318 if ( this->executePending() ) {
00319 this->requestNextState();
00320 TRACE("Is active now.");
00321 smStatus = Status::active;
00322 }
00323 break;
00324 case Status::active:
00325 this->executePending();
00326 break;
00327 case Status::running:
00328 if ( this->executePending() == false)
00329 break;
00330
00331 this->requestNextState();
00332 break;
00333 case Status::paused:
00334 if (mstep) {
00335 if ( this->executePending(true) )
00336 this->requestNextState(true);
00337 TRACE("Did a step.");
00338 mstep = false;
00339 }
00340 break;
00341 case Status::error:
00342 case Status::unloaded:
00343 break;
00344 case Status::activating:
00345 this->executePending();
00346 if ( !this->inTransition() ) {
00347 TRACE("Is active now.");
00348 smStatus = Status::active;
00349 }
00350 break;
00351 case Status::stopping:
00352 if ( this->executePending() ) {
00353 TRACE("Is stopped now.");
00354 smStatus = Status::stopped;
00355 }break;
00356 case Status::deactivating:
00357 if ( this->executePending() ) {
00358 TRACE("Is inactive now.");
00359 smStatus = Status::inactive;
00360 }break;
00361 case Status::resetting:
00362 if ( this->executePending() ) {
00363 TRACE("Is reset now.");
00364 smStatus = Status::active;
00365 }break;
00366 case Status::stopped:
00367 this->executePending();
00368 if ( current != finistate ) {
00369 smStatus = Status::active;
00370 } break;
00371 }
00372 return true;
00373 }
00374
00375 bool StateMachine::requestInitialState()
00376 {
00377 TRACE_INIT();
00378
00379 if ( interruptible() && ( current == initstate || current == finistate ) )
00380 {
00381 TRACE("Will enter initial state.");
00382
00383 this->requestStateChange( initstate );
00384 return true;
00385 }
00386 TRACE("Won't enter initial state.");
00387 return false;
00388 }
00389
00390 bool StateMachine::requestFinalState()
00391 {
00392 TRACE_INIT();
00393
00394 if ( current == 0 || ( !inError() && !interruptible() ) ) {
00395 TRACE("Won't enter final state.");
00396 return false;
00397 }
00398
00399
00400 if ( this->requestStateChange( finistate ) ) {
00401 TRACE("Will enter final state.");
00402 return true;
00403 }
00404 TRACE("Won't enter final state.");
00405 return false;
00406 }
00407
00408 void StateMachine::changeState(StateInterface* newState, ProgramInterface* transProg, bool stepping) {
00409 TRACE_INIT();
00410 if ( newState == current )
00411 {
00412
00413 if ( transProg ) {
00414 TRACE("Transition triggered to self: '"+current->getName()+"'");
00415 transProg->reset();
00416 if (transProg->start() == false )
00417 smStatus = Status::error;
00418 currentTrans = transProg;
00419 currentProg = transProg;
00420
00421 reqstep = stateMap.find( current )->second.begin();
00422
00423
00424
00425
00426
00427 } else {
00428
00429
00430
00431 if ( currentHandle == 0 )
00432 handleState( current );
00433 }
00434 }
00435 else
00436 {
00437 TRACE("Transition triggered from '"+ (current ? current->getName() : "null") +"' to '"+(newState ? newState->getName() : "null")+"'.");
00438
00439
00440 currentRun = 0;
00441 currentHandle = 0;
00442 if ( transProg ) {
00443 transProg->reset();
00444 if ( transProg->start() == false )
00445 smStatus = Status::error;
00446
00447 }
00448 currentTrans = transProg;
00449
00450 if ( currentExit && currentExit->inError() )
00451 currentExit = 0;
00452 else
00453 leaveState( current );
00454 enterState( newState );
00455 }
00456
00457
00458
00459 if ( !stepping )
00460 this->executePending(stepping);
00461
00462
00463
00464
00465
00466 runState( newState );
00467 }
00468
00469 void StateMachine::enableGlobalEvents( )
00470 {
00471 enableEvents(0);
00472 }
00473 void StateMachine::disableGlobalEvents( )
00474 {
00475 disableEvents(0);
00476 }
00477 void StateMachine::enableEvents( StateInterface* s )
00478 {
00479
00480
00481
00482
00483
00484 EventMap::mapped_type& hlist = eventMap[s];
00485 for (EventList::iterator eit = hlist.begin();
00486 eit != hlist.end();
00487 ++eit) {
00488 get<6>(*eit).connect();
00489 }
00490 }
00491 void StateMachine::disableEvents( StateInterface* s )
00492 {
00493
00494
00495
00496
00497
00498 EventMap::mapped_type& hlist = eventMap[s];
00499 for (EventList::iterator eit = hlist.begin();
00500 eit != hlist.end();
00501 ++eit) {
00502 get<6>(*eit).disconnect();
00503 }
00504
00505 }
00506
00507 bool StateMachine::createEventTransition( ServicePtr sp,
00508 const std::string& ename, vector<DataSourceBase::shared_ptr> args,
00509 StateInterface* from, StateInterface* to,
00510 ConditionInterface* guard, boost::shared_ptr<ProgramInterface> transprog,
00511 StateInterface* elseto, boost::shared_ptr<ProgramInterface> elseprog )
00512 {
00513 Logger::In in("StateMachine::createEventTransition");
00514 if ( false ) {
00515 log(Error) << "Can not receive event '"<< ename <<"' in StateMachine for Operation not executed in OwnThread."<< endlog();
00516 return false;
00517 }
00518
00519 if ( !( sp && guard ) ) {
00520 log(Error) << "Invalid arguments for event '"<< ename <<"'. ";
00521 if (!sp)
00522 log() <<"EventService was null. ";
00523 if (!guard)
00524 log() <<"Guard Condition was null. ";
00525 log() << endlog();
00526 return false;
00527 }
00528
00529 if ( to == 0 )
00530 to = from;
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 Handle handle;
00545 log(Debug) << "Creating Signal handler for Operation '"<< ename <<"'."<<Logger::endl;
00546 handle = sp->produceSignal( ename, new CommandFunction( boost::bind( &StateMachine::eventTransition, this, from, guard, transprog.get(), to, elseprog.get(), elseto) ), args );
00547
00548 if ( !handle.ready() ) {
00549 Logger::log() << Logger::Error << "Could not setup handle for event '"<<ename<<"'."<<Logger::endl;
00550 return false;
00551 }
00552
00553
00554 eventMap[from].push_back( boost::make_tuple( sp, ename, args, to, guard, transprog, handle, elseto, elseprog) );
00555
00556 stateMap[from];
00557 stateMap[to];
00558 return true;
00559 }
00560
00561 bool StateMachine::eventTransition(StateInterface* from, ConditionInterface* c, ProgramInterface* p, StateInterface* to, ProgramInterface* elsep, StateInterface* elseto )
00562 {
00563 TRACE_INIT();
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 if ( !current)
00575 return true;
00576
00577 TRACE("Received Signal in state '"+ current->getName()+"'.");
00578 if (from == 0)
00579 from = current;
00580 if (to == 0)
00581 to = current;
00582 if ( from == current && !this->inTransition() ) {
00583 if ( c->evaluate() && checkConditions(to, false) == 1 ) {
00584 TRACE( "Valid transition from " + from->getName() +
00585 +" to "+to->getName()+".");
00586 changeState( to, p );
00587 }
00588 else {
00589 TRACE( "Rejected transition from " + from->getName() +
00590 " to " + to->getName() +
00591 " within state " + current->getName() + ": guards failed.");
00592 }
00593 }
00594 #if 1
00595 else {
00596 if (this->inTransition() ) {
00597 TRACE( "Rejected transition from " + from->getName() +
00598 " within " + current->getName() + ": in transition.");
00599 } else {
00600 TRACE( "Rejected transition from " + from->getName() +
00601 + " within " + current->getName() + ": wrong state.");
00602 }
00603 }
00604 #endif
00605 return true;
00606 }
00607
00608 StateInterface* StateMachine::requestNextState(bool stepping)
00609 {
00610 TRACE_INIT();
00611
00612 if( current == 0 )
00613 return 0;
00614
00615 if ( !interruptible() || currentTrans ) {
00616 return current;
00617 }
00618
00619
00620 TransList::const_iterator it, it1, it2;
00621 it1 = stateMap.find( 0 )->second.begin();
00622 it2 = stateMap.find( 0 )->second.end();
00623
00624 if ( reqstep == stateMap.find( current )->second.begin() )
00625 for ( it= it1; it != it2; ++it)
00626 get<0>(*it)->reset();
00627
00628 if ( reqstep == reqend ) {
00629
00630 for ( ; it1 != it2; ++it1 )
00631 if ( get<0>(*it1)->evaluate()
00632 && checkConditions( get<1>(*it1) ) == 1 ) {
00633 StateInterface* next = get<1>(*it1);
00634 if ( next == 0 )
00635 changeState( current, get<4>(*it1).get(), stepping );
00636 else
00637 changeState( next, get<4>(*it1).get(), stepping );
00638
00639 return current;
00640 }
00641
00642 changeState( current, 0, stepping );
00643 return current;
00644 }
00645
00646
00647 do {
00648 if ( get<0>(*reqstep)->evaluate() ) {
00649
00650 if (reqstep == reqend )
00651 return current;
00652
00653 int cres = checkConditions( get<1>(*reqstep), stepping );
00654 if (cres == 0) {
00655 break;
00656 }
00657 if( cres == 1) {
00658 changeState( get<1>(*reqstep), get<4>(*reqstep).get(), stepping );
00659 break;
00660 }
00661
00662 }
00663 if ( reqstep + 1 == reqend ) {
00664
00665 for ( ; it1 != it2; ++it1 ) {
00666 if ( get<0>(*it1)->evaluate() && checkConditions( get<1>(*it1) ) == 1 ) {
00667 StateInterface* next = get<1>(*it1);
00668 if ( next == 0)
00669 changeState( current, get<4>(*it1).get(), stepping );
00670 else
00671 changeState( next, get<4>(*it1).get(), stepping );
00672
00673 return current;
00674 }
00675 }
00676
00677 reqstep = stateMap.find( current )->second.begin();
00678 evaluating = get<3>(*reqstep);
00679 changeState( current, 0, stepping );
00680 break;
00681 }
00682 else {
00683 ++reqstep;
00684 evaluating = get<3>(*reqstep);
00685 }
00686 } while ( !stepping );
00687
00688 return current;
00689 }
00690
00691 int StateMachine::checkConditions( StateInterface* state, bool stepping ) {
00692
00693
00694 if ( !checking_precond || !stepping ) {
00695 prec_it = precondMap.equal_range(state);
00696 }
00697
00698
00699
00700
00701 while ( prec_it.first != prec_it.second ) {
00702 if (checking_precond == false && stepping ) {
00703 evaluating = prec_it.first->second.second;
00704 checking_precond = true;
00705 return 0;
00706 }
00707 if ( prec_it.first->second.first->evaluate() == false ) {
00708 checking_precond = false;
00709 return -1;
00710 }
00711 ++( prec_it.first );
00712 if (stepping) {
00713 if ( prec_it.first != prec_it.second )
00714 evaluating = prec_it.first->second.second;
00715 checking_precond = true;
00716 return 0;
00717 }
00718 }
00719 checking_precond = false;
00720 return 1;
00721 }
00722
00723
00724 StateInterface* StateMachine::nextState()
00725 {
00726
00727 if ( current == 0 )
00728 return 0;
00729 TransList::const_iterator it1, it2;
00730 it1 = stateMap.find( current )->second.begin();
00731 it2 = stateMap.find( current )->second.end();
00732
00733 for ( ; it1 != it2; ++it1 )
00734 if ( get<0>(*it1)->evaluate() && checkConditions( get<1>(*it1)) == 1 ) {
00735 return get<1>(*it1);
00736 }
00737
00738
00739 it1 = stateMap.find( 0 )->second.begin();
00740 it2 = stateMap.find( 0 )->second.end();
00741
00742 for ( ; it1 != it2; ++it1 )
00743 if ( get<0>(*it1)->evaluate() && checkConditions( get<1>(*it1)) == 1 ) {
00744 return get<1>(*it1);
00745 }
00746
00747 return current;
00748 }
00749
00750 std::vector<std::string> StateMachine::getStateList() const {
00751 vector<string> result;
00752 vector<StateInterface*> sl;
00753 StateInterface* dummy = 0;
00754 transform( stateMap.begin(), stateMap.end(), back_inserter(sl), select1st<TransitionMap::value_type>() );
00755 sl.erase( find(sl.begin(), sl.end(), dummy) );
00756 transform( sl.begin(), sl.end(), back_inserter(result), boost::bind( &StateInterface::getName, _1 ) );
00757 return result;
00758 }
00759
00760 void StateMachine::addState( StateInterface* s )
00761 {
00762 stateMap[s];
00763 }
00764
00765
00766 StateInterface* StateMachine::getState(const string& name) const
00767 {
00768 TransitionMap::const_iterator it = stateMap.begin();
00769 while ( it != stateMap.end() ) {
00770 if ( it->first && it->first->getName() == name )
00771 return it->first;
00772 ++it;
00773 }
00774 return 0;
00775 }
00776
00777 bool StateMachine::requestStateChange( StateInterface * s_n )
00778 {
00779
00780 if( current == 0 )
00781 return false;
00782
00783 if ( !interruptible() ) {
00784 return false;
00785 }
00786
00787
00788
00789
00790 if ( current == s_n )
00791 {
00792 changeState( s_n, 0 );
00793 return true;
00794 }
00795
00796
00797 TransList::iterator it, it1, it2;
00798 it1 = stateMap.find( current )->second.begin();
00799 it2 = stateMap.find( current )->second.end();
00800
00801 for ( ; it1 != it2; ++it1 )
00802 if ( get<1>(*it1) == s_n
00803 && get<0>(*it1)->evaluate()
00804 && checkConditions( s_n ) == 1 ) {
00805 changeState( s_n, get<4>(*it1).get() );
00806
00807 return true;
00808 }
00809
00810
00811 it1 = stateMap.find( 0 )->second.begin();
00812 it2 = stateMap.find( 0 )->second.end();
00813
00814
00815 for ( it= it1; it != it2; ++it)
00816 get<0>(*it)->reset();
00817
00818
00819 for ( ; it1 != it2; ++it1 )
00820 if ( get<1>(*it1) == s_n
00821 && get<0>(*it1)->evaluate()
00822 && checkConditions( s_n ) == 1 ) {
00823 changeState( s_n, get<4>(*it1).get() );
00824
00825 return true;
00826 }
00827
00828
00829 if ( finistate == s_n )
00830 {
00831 changeState( s_n, 0 );
00832 return true;
00833 }
00834
00835
00836 if ( initstate == s_n && current == finistate)
00837 {
00838 changeState( s_n, 0 );
00839 return true;
00840 }
00841
00842
00843 return false;
00844 }
00845
00846 int StateMachine::getLineNumber() const {
00847
00848
00849
00850 StateInterface* statecopy = current;
00851 if ( statecopy == 0 )
00852 return 1;
00853 ProgramInterface* copy = currentProg;
00854 if ( copy )
00855 return copy->getLineNumber();
00856 if ( evaluating )
00857 return evaluating;
00858
00859
00860 return statecopy->getEntryPoint();
00861 }
00862
00863 string StateMachine::getText() const {
00864 return string();
00865 }
00866
00867 void StateMachine::preconditionSet(StateInterface* state, ConditionInterface* cnd, int line )
00868 {
00869
00870 if ( current != 0)
00871 return;
00872 precondMap.insert( make_pair(state, make_pair( cnd, line)) );
00873 stateMap[state];
00874 }
00875
00876 void StateMachine::transitionSet( StateInterface* from, StateInterface* to, ConditionInterface* cnd, int priority, int line )
00877 {
00878 this->transitionSet( from, to, cnd, boost::shared_ptr<ProgramInterface>(), priority, line);
00879 }
00880
00881 void StateMachine::transitionSet( StateInterface* from, StateInterface* to,
00882 ConditionInterface* cnd, boost::shared_ptr<ProgramInterface> transprog,
00883 int priority, int line )
00884 {
00885 TRACE_INIT();
00886
00887 if ( current != 0)
00888 return;
00889
00890 if (from) {
00891 TRACE("Created transition from "+from->getName() +"' to '"+ to->getName()+"'");
00892 } else {
00893 TRACE("Created global transition to '"+ to->getName()+"'");
00894 }
00895
00896 TransList::iterator it;
00897 for ( it= stateMap[from].begin(); it != stateMap[from].end() && get<2>(*it) >= priority; ++it)
00898 ;
00899 stateMap[from].insert(it, boost::make_tuple( cnd, to, priority, line, transprog ) );
00900 stateMap[to];
00901 }
00902
00903 StateInterface* StateMachine::currentState() const
00904 {
00905 return current;
00906 }
00907
00908 ProgramInterface* StateMachine::currentProgram() const
00909 {
00910 return currentProg;
00911 }
00912
00913 void StateMachine::leaveState( StateInterface* s )
00914 {
00915 assert(s);
00916
00917
00918 disableEvents(s);
00919 currentExit = s->getExitProgram();
00920 if ( currentExit ) {
00921 currentExit->reset();
00922 if (currentExit->start() == false)
00923 smStatus = Status::error;
00924
00925 if (currentProg == 0 )
00926 currentProg = currentExit;
00927 }
00928 }
00929
00930 void StateMachine::runState( StateInterface* s )
00931 {
00932 TRACE_INIT();
00933 assert(s);
00934 currentRun = s->getRunProgram();
00935 if ( currentRun ) {
00936 currentRun->reset();
00937 if (currentRun->start() == false)
00938 smStatus = Status::error;
00939 if (currentProg == 0 )
00940 currentProg = currentRun;
00941 }
00942 }
00943
00944 void StateMachine::handleState( StateInterface* s )
00945 {
00946 assert(s);
00947 currentHandle = s->getHandleProgram();
00948 if ( currentHandle ) {
00949 currentHandle->reset();
00950 if (currentHandle->start() == false)
00951 smStatus = Status::error;
00952 if (currentProg == 0 )
00953 currentProg = currentHandle;
00954 }
00955 }
00956
00957 void StateMachine::enterState( StateInterface* s )
00958 {
00959 assert(s);
00960
00961
00962
00963
00964 TransList::iterator it;
00965 for ( it= stateMap.find(s)->second.begin(); it != stateMap.find(s)->second.end(); ++it)
00966 get<0>(*it)->reset();
00967
00968 enableEvents(s);
00969
00970 next = s;
00971 currentEntry = s->getEntryProgram();
00972 if ( currentEntry ) {
00973 currentEntry->reset();
00974 if (currentEntry->start() == false)
00975 smStatus = Status::error;
00976 if (currentProg == 0 )
00977 currentProg = currentEntry;
00978 }
00979 }
00980
00981 bool StateMachine::executePending( bool stepping )
00982 {
00983 TRACE_INIT();
00984
00985
00986
00987
00988
00989
00990
00991
00992 if ( inError() )
00993 return false;
00994
00995
00996 if ( currentTrans ) {
00997 TRACE("Executing transition program from '"+ (current ? current->getName() : "(null)") + "' to '"+ ( next ? next->getName() : "(null)")+"'" );
00998
00999 if ( currentHandle ) {
01000 if ( this->executeProgram(currentHandle, stepping) == false )
01001 return false;
01002 } else
01003 if ( this->executeProgram(currentTrans, stepping) == false )
01004 return false;
01005
01006 TRACE("Finished transition program from '"+ current->getName() + "' to '"+next->getName()+"'" );
01007
01008 if ( stepping ) {
01009 currentProg = currentExit ? currentExit : (currentEntry ? currentEntry : currentRun);
01010 return false;
01011 }
01012 }
01013
01014
01015 if ( currentExit ) {
01016 TRACE("Executing exit program from '"+ current->getName() + "' (going to '"+ (next ? next->getName() : "(null)") +"')" );
01017 if ( this->executeProgram(currentExit, stepping) == false )
01018 return false;
01019
01020 TRACE("Finished exit program from '"+ current->getName() + "' (going to '"+ (next ? next->getName() : "(null)") +"')" );
01021
01022 if ( stepping ) {
01023 currentProg = (currentEntry ? currentEntry : currentRun);
01024 return false;
01025 }
01026 }
01027
01028
01029
01030
01031 if ( current != next ) {
01032 if ( next ) {
01033 reqstep = stateMap.find( next )->second.begin();
01034 reqend = stateMap.find( next )->second.end();
01035
01036 if ( reqstep == reqend )
01037 evaluating = 0;
01038 else
01039 evaluating = get<3>(*reqstep);
01040 } else {
01041 current = 0;
01042 return true;
01043 }
01044
01045 TRACE("Formally transitioning from '"+ (current ? current->getName() : "(null)") + "' to '"+ (next ? next->getName() : "(null)") +"'" );
01046 current = next;
01047 }
01048
01049 if ( currentEntry ) {
01050 TRACE("Executing entry program of '"+ current->getName() +"'" );
01051 if ( this->executeProgram(currentEntry, stepping) == false )
01052 return false;
01053
01054 TRACE("Finished entry program of '"+ current->getName() +"'" );
01055
01056 if ( stepping ) {
01057 currentProg = currentRun;
01058 return false;
01059 }
01060 }
01061
01062
01063
01064 if ( currentHandle ) {
01065 TRACE("Executing handle program of '"+ current->getName() +"'" );
01066 if ( this->executeProgram(currentHandle, stepping) == false )
01067 return false;
01068
01069 TRACE("Finished handle program of '"+ current->getName() +"'" );
01070
01071 if ( stepping ) {
01072 currentProg = currentRun;
01073 return false;
01074 }
01075 }
01076
01077
01078 if ( currentRun ) {
01079 TRACE("Executing run program of '"+ current->getName() +"'" );
01080 if ( this->executeProgram(currentRun, stepping) == false )
01081 return false;
01082
01083 TRACE("Finished run program of '"+ current->getName() +"'" );
01084
01085 if ( stepping )
01086 return false;
01087
01088 }
01089
01090 return true;
01091 }
01092
01093 bool StateMachine::executeProgram(ProgramInterface*& cp, bool stepping)
01094 {
01095 TRACE_INIT();
01096 if ( cp == 0)
01097 return false;
01098
01099 currentProg = cp;
01100 if ( stepping )
01101 currentProg->step();
01102 else
01103 currentProg->execute();
01104 if ( currentProg->inError() ) {
01105 smStatus = Status::error;
01106 smpStatus = nill;
01107 TRACE("Encountered run-time error at line " << this->getLineNumber() );
01108 return false;
01109 }
01110
01111 if ( currentProg && !currentProg->isStopped() )
01112 return false;
01113
01114 cp = currentProg = 0;
01115 return true;
01116 }
01117
01118
01119
01120 bool StateMachine::inTransition() const {
01121 return currentProg != 0 && currentProg != currentRun && currentProg != currentHandle;
01122 }
01123
01124
01125 bool StateMachine::interruptible() const {
01126 return currentProg == 0 || currentProg == currentRun;
01127 }
01128
01129 void StateMachine::setInitialState( StateInterface* s )
01130 {
01131 initstate = s;
01132 stateMap[initstate];
01133 }
01134
01135 void StateMachine::setFinalState( StateInterface* s )
01136 {
01137 finistate = s;
01138 stateMap[finistate];
01139 }
01140
01141 void StateMachine::trace(bool t) {
01142 mtrace =t;
01143 }
01144
01145 bool StateMachine::activate()
01146 {
01147 TRACE_INIT();
01148
01149 if ( smStatus != Status::inactive ) {
01150 TRACE("Won't activate: already active.");
01151 return false;
01152 }
01153
01154 smpStatus = nill;
01155
01156 if ( this->checkConditions( getInitialState() ) != 1 ) {
01157 TRACE("Won't activate: preconditions failed.");
01158 return false;
01159 }
01160
01161 if ( initc ) {
01162 initc->reset();
01163 initc->readArguments();
01164 if ( initc->execute() == false ) {
01165 TRACE("Won't activate: Init Commands failed.");
01166 return false;
01167 }
01168 }
01169
01170
01171 enterState( getInitialState() );
01172 reqstep = stateMap.find( next )->second.begin();
01173 reqend = stateMap.find( next )->second.end();
01174
01175
01176 enableGlobalEvents();
01177
01178
01179 if ( !inError() ) {
01180 if ( this->executePending() ) {
01181 smStatus = Status::active;
01182 TRACE("Activated.");
01183 } else {
01184 if ( !inError() ) {
01185 TRACE("Still activating.");
01186 smStatus = Status::activating;
01187 }
01188 }
01189 }
01190
01191 return true;
01192 }
01193
01194
01195 bool StateMachine::deactivate()
01196 {
01197 TRACE_INIT();
01198
01199 if ( smStatus == Status::inactive) {
01200 TRACE("Won't deactivate: already inactive.");
01201 return false;
01202 }
01203 os::MutexLock lock(execlock);
01204
01205
01206 disableGlobalEvents();
01207
01208
01209
01210 if ( currentExit && currentExit->inError() )
01211 currentExit = 0;
01212 if ( currentTrans && currentTrans->inError() )
01213 currentTrans = 0;
01214
01215
01216 if ( next != 0 && current )
01217 leaveState( current );
01218 else {
01219 currentExit = 0;
01220 currentTrans = 0;
01221 }
01222
01223
01224 currentProg = 0;
01225 currentEntry = 0;
01226 currentHandle = 0;
01227 currentRun = 0;
01228 next = 0;
01229
01230
01231
01232 if ( this->executePending() ) {
01233 TRACE("Deactivated.");
01234 smStatus = Status::inactive;
01235 } else {
01236 TRACE("Still deactivating.");
01237 smStatus = Status::deactivating;
01238 }
01239
01240 return true;
01241 }
01242 }