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
00546 log(Debug) << "Creating Signal handler for Operation '"<< ename <<"'."<<Logger::endl;
00547 #ifdef ORO_SIGNALLING_OPERATIONS
00548 handle = sp->produceSignal( ename, new CommandFunction( boost::bind( &StateMachine::eventTransition, this, from, guard, transprog.get(), to, elseprog.get(), elseto) ), args );
00549 #endif
00550 if ( !handle.ready() ) {
00551 Logger::log() << Logger::Error << "Could not setup handle for event '"<<ename<<"'."<<Logger::endl;
00552 return false;
00553 }
00554
00555
00556 eventMap[from].push_back( boost::make_tuple( sp, ename, args, to, guard, transprog, handle, elseto, elseprog) );
00557
00558 stateMap[from];
00559 stateMap[to];
00560 return true;
00561 }
00562
00563 bool StateMachine::eventTransition(StateInterface* from, ConditionInterface* c, ProgramInterface* p, StateInterface* to, ProgramInterface* elsep, StateInterface* elseto )
00564 {
00565 TRACE_INIT();
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 if ( !current)
00577 return true;
00578
00579 TRACE("Received Signal in state '"+ current->getName()+"'.");
00580 if (from == 0)
00581 from = current;
00582 if (to == 0)
00583 to = current;
00584 if ( from == current && !this->inTransition() ) {
00585 if ( c->evaluate() && checkConditions(to, false) == 1 ) {
00586 TRACE( "Valid transition from " + from->getName() +
00587 +" to "+to->getName()+".");
00588 changeState( to, p );
00589 }
00590 else {
00591 TRACE( "Rejected transition from " + from->getName() +
00592 " to " + to->getName() +
00593 " within state " + current->getName() + ": guards failed.");
00594 }
00595 }
00596 #if 1
00597 else {
00598 if (this->inTransition() ) {
00599 TRACE( "Rejected transition from " + from->getName() +
00600 " within " + current->getName() + ": in transition.");
00601 } else {
00602 TRACE( "Rejected transition from " + from->getName() +
00603 + " within " + current->getName() + ": wrong state.");
00604 }
00605 }
00606 #endif
00607 return true;
00608 }
00609
00610 StateInterface* StateMachine::requestNextState(bool stepping)
00611 {
00612 TRACE_INIT();
00613
00614 if( current == 0 )
00615 return 0;
00616
00617 if ( !interruptible() || currentTrans ) {
00618 return current;
00619 }
00620
00621
00622 TransList::const_iterator it, it1, it2;
00623 it1 = stateMap.find( 0 )->second.begin();
00624 it2 = stateMap.find( 0 )->second.end();
00625
00626 if ( reqstep == stateMap.find( current )->second.begin() )
00627 for ( it= it1; it != it2; ++it)
00628 get<0>(*it)->reset();
00629
00630 if ( reqstep == reqend ) {
00631
00632 for ( ; it1 != it2; ++it1 )
00633 if ( get<0>(*it1)->evaluate()
00634 && checkConditions( get<1>(*it1) ) == 1 ) {
00635 StateInterface* next = get<1>(*it1);
00636 if ( next == 0 )
00637 changeState( current, get<4>(*it1).get(), stepping );
00638 else
00639 changeState( next, get<4>(*it1).get(), stepping );
00640
00641 return current;
00642 }
00643
00644 changeState( current, 0, stepping );
00645 return current;
00646 }
00647
00648
00649 do {
00650 if ( get<0>(*reqstep)->evaluate() ) {
00651
00652 if (reqstep == reqend )
00653 return current;
00654
00655 int cres = checkConditions( get<1>(*reqstep), stepping );
00656 if (cres == 0) {
00657 break;
00658 }
00659 if( cres == 1) {
00660 changeState( get<1>(*reqstep), get<4>(*reqstep).get(), stepping );
00661 break;
00662 }
00663
00664 }
00665 if ( reqstep + 1 == reqend ) {
00666
00667 for ( ; it1 != it2; ++it1 ) {
00668 if ( get<0>(*it1)->evaluate() && checkConditions( get<1>(*it1) ) == 1 ) {
00669 StateInterface* next = get<1>(*it1);
00670 if ( next == 0)
00671 changeState( current, get<4>(*it1).get(), stepping );
00672 else
00673 changeState( next, get<4>(*it1).get(), stepping );
00674
00675 return current;
00676 }
00677 }
00678
00679 reqstep = stateMap.find( current )->second.begin();
00680 evaluating = get<3>(*reqstep);
00681 changeState( current, 0, stepping );
00682 break;
00683 }
00684 else {
00685 ++reqstep;
00686 evaluating = get<3>(*reqstep);
00687 }
00688 } while ( !stepping );
00689
00690 return current;
00691 }
00692
00693 int StateMachine::checkConditions( StateInterface* state, bool stepping ) {
00694
00695
00696 if ( !checking_precond || !stepping ) {
00697 prec_it = precondMap.equal_range(state);
00698 }
00699
00700
00701
00702
00703 while ( prec_it.first != prec_it.second ) {
00704 if (checking_precond == false && stepping ) {
00705 evaluating = prec_it.first->second.second;
00706 checking_precond = true;
00707 return 0;
00708 }
00709 if ( prec_it.first->second.first->evaluate() == false ) {
00710 checking_precond = false;
00711 return -1;
00712 }
00713 ++( prec_it.first );
00714 if (stepping) {
00715 if ( prec_it.first != prec_it.second )
00716 evaluating = prec_it.first->second.second;
00717 checking_precond = true;
00718 return 0;
00719 }
00720 }
00721 checking_precond = false;
00722 return 1;
00723 }
00724
00725
00726 StateInterface* StateMachine::nextState()
00727 {
00728
00729 if ( current == 0 )
00730 return 0;
00731 TransList::const_iterator it1, it2;
00732 it1 = stateMap.find( current )->second.begin();
00733 it2 = stateMap.find( current )->second.end();
00734
00735 for ( ; it1 != it2; ++it1 )
00736 if ( get<0>(*it1)->evaluate() && checkConditions( get<1>(*it1)) == 1 ) {
00737 return get<1>(*it1);
00738 }
00739
00740
00741 it1 = stateMap.find( 0 )->second.begin();
00742 it2 = stateMap.find( 0 )->second.end();
00743
00744 for ( ; it1 != it2; ++it1 )
00745 if ( get<0>(*it1)->evaluate() && checkConditions( get<1>(*it1)) == 1 ) {
00746 return get<1>(*it1);
00747 }
00748
00749 return current;
00750 }
00751
00752 std::vector<std::string> StateMachine::getStateList() const {
00753 vector<string> result;
00754 vector<StateInterface*> sl;
00755 StateInterface* dummy = 0;
00756 transform( stateMap.begin(), stateMap.end(), back_inserter(sl), select1st<TransitionMap::value_type>() );
00757 sl.erase( find(sl.begin(), sl.end(), dummy) );
00758 transform( sl.begin(), sl.end(), back_inserter(result), boost::bind( &StateInterface::getName, _1 ) );
00759 return result;
00760 }
00761
00762 void StateMachine::addState( StateInterface* s )
00763 {
00764 stateMap[s];
00765 }
00766
00767
00768 StateInterface* StateMachine::getState(const string& name) const
00769 {
00770 TransitionMap::const_iterator it = stateMap.begin();
00771 while ( it != stateMap.end() ) {
00772 if ( it->first && it->first->getName() == name )
00773 return it->first;
00774 ++it;
00775 }
00776 return 0;
00777 }
00778
00779 bool StateMachine::requestStateChange( StateInterface * s_n )
00780 {
00781
00782 if( current == 0 )
00783 return false;
00784
00785 if ( !interruptible() ) {
00786 return false;
00787 }
00788
00789
00790
00791
00792 if ( current == s_n )
00793 {
00794 changeState( s_n, 0 );
00795 return true;
00796 }
00797
00798
00799 TransList::iterator it, it1, it2;
00800 it1 = stateMap.find( current )->second.begin();
00801 it2 = stateMap.find( current )->second.end();
00802
00803 for ( ; it1 != it2; ++it1 )
00804 if ( get<1>(*it1) == s_n
00805 && get<0>(*it1)->evaluate()
00806 && checkConditions( s_n ) == 1 ) {
00807 changeState( s_n, get<4>(*it1).get() );
00808
00809 return true;
00810 }
00811
00812
00813 it1 = stateMap.find( 0 )->second.begin();
00814 it2 = stateMap.find( 0 )->second.end();
00815
00816
00817 for ( it= it1; it != it2; ++it)
00818 get<0>(*it)->reset();
00819
00820
00821 for ( ; it1 != it2; ++it1 )
00822 if ( get<1>(*it1) == s_n
00823 && get<0>(*it1)->evaluate()
00824 && checkConditions( s_n ) == 1 ) {
00825 changeState( s_n, get<4>(*it1).get() );
00826
00827 return true;
00828 }
00829
00830
00831 if ( finistate == s_n )
00832 {
00833 changeState( s_n, 0 );
00834 return true;
00835 }
00836
00837
00838 if ( initstate == s_n && current == finistate)
00839 {
00840 changeState( s_n, 0 );
00841 return true;
00842 }
00843
00844
00845 return false;
00846 }
00847
00848 int StateMachine::getLineNumber() const {
00849
00850
00851
00852 StateInterface* statecopy = current;
00853 if ( statecopy == 0 )
00854 return 1;
00855 ProgramInterface* copy = currentProg;
00856 if ( copy )
00857 return copy->getLineNumber();
00858 if ( evaluating )
00859 return evaluating;
00860
00861
00862 return statecopy->getEntryPoint();
00863 }
00864
00865 string StateMachine::getText() const {
00866 return string();
00867 }
00868
00869 void StateMachine::preconditionSet(StateInterface* state, ConditionInterface* cnd, int line )
00870 {
00871
00872 if ( current != 0)
00873 return;
00874 precondMap.insert( make_pair(state, make_pair( cnd, line)) );
00875 stateMap[state];
00876 }
00877
00878 void StateMachine::transitionSet( StateInterface* from, StateInterface* to, ConditionInterface* cnd, int priority, int line )
00879 {
00880 this->transitionSet( from, to, cnd, boost::shared_ptr<ProgramInterface>(), priority, line);
00881 }
00882
00883 void StateMachine::transitionSet( StateInterface* from, StateInterface* to,
00884 ConditionInterface* cnd, boost::shared_ptr<ProgramInterface> transprog,
00885 int priority, int line )
00886 {
00887 TRACE_INIT();
00888
00889 if ( current != 0)
00890 return;
00891
00892 if (from) {
00893 TRACE("Created transition from "+from->getName() +"' to '"+ to->getName()+"'");
00894 } else {
00895 TRACE("Created global transition to '"+ to->getName()+"'");
00896 }
00897
00898 TransList::iterator it;
00899 for ( it= stateMap[from].begin(); it != stateMap[from].end() && get<2>(*it) >= priority; ++it)
00900 ;
00901 stateMap[from].insert(it, boost::make_tuple( cnd, to, priority, line, transprog ) );
00902 stateMap[to];
00903 }
00904
00905 StateInterface* StateMachine::currentState() const
00906 {
00907 return current;
00908 }
00909
00910 ProgramInterface* StateMachine::currentProgram() const
00911 {
00912 return currentProg;
00913 }
00914
00915 void StateMachine::leaveState( StateInterface* s )
00916 {
00917 assert(s);
00918
00919
00920 disableEvents(s);
00921 currentExit = s->getExitProgram();
00922 if ( currentExit ) {
00923 currentExit->reset();
00924 if (currentExit->start() == false)
00925 smStatus = Status::error;
00926
00927 if (currentProg == 0 )
00928 currentProg = currentExit;
00929 }
00930 }
00931
00932 void StateMachine::runState( StateInterface* s )
00933 {
00934 TRACE_INIT();
00935 assert(s);
00936 currentRun = s->getRunProgram();
00937 if ( currentRun ) {
00938 currentRun->reset();
00939 if (currentRun->start() == false)
00940 smStatus = Status::error;
00941 if (currentProg == 0 )
00942 currentProg = currentRun;
00943 }
00944 }
00945
00946 void StateMachine::handleState( StateInterface* s )
00947 {
00948 assert(s);
00949 currentHandle = s->getHandleProgram();
00950 if ( currentHandle ) {
00951 currentHandle->reset();
00952 if (currentHandle->start() == false)
00953 smStatus = Status::error;
00954 if (currentProg == 0 )
00955 currentProg = currentHandle;
00956 }
00957 }
00958
00959 void StateMachine::enterState( StateInterface* s )
00960 {
00961 assert(s);
00962
00963
00964
00965
00966 TransList::iterator it;
00967 for ( it= stateMap.find(s)->second.begin(); it != stateMap.find(s)->second.end(); ++it)
00968 get<0>(*it)->reset();
00969
00970 enableEvents(s);
00971
00972 next = s;
00973 currentEntry = s->getEntryProgram();
00974 if ( currentEntry ) {
00975 currentEntry->reset();
00976 if (currentEntry->start() == false)
00977 smStatus = Status::error;
00978 if (currentProg == 0 )
00979 currentProg = currentEntry;
00980 }
00981 }
00982
00983 bool StateMachine::executePending( bool stepping )
00984 {
00985 TRACE_INIT();
00986
00987
00988
00989
00990
00991
00992
00993
00994 if ( inError() )
00995 return false;
00996
00997
00998 if ( currentTrans ) {
00999 TRACE("Executing transition program from '"+ (current ? current->getName() : "(null)") + "' to '"+ ( next ? next->getName() : "(null)")+"'" );
01000
01001 if ( currentHandle ) {
01002 if ( this->executeProgram(currentHandle, stepping) == false )
01003 return false;
01004 } else
01005 if ( this->executeProgram(currentTrans, stepping) == false )
01006 return false;
01007
01008 TRACE("Finished transition program from '"+ current->getName() + "' to '"+next->getName()+"'" );
01009
01010 if ( stepping ) {
01011 currentProg = currentExit ? currentExit : (currentEntry ? currentEntry : currentRun);
01012 return false;
01013 }
01014 }
01015
01016
01017 if ( currentExit ) {
01018 TRACE("Executing exit program from '"+ current->getName() + "' (going to '"+ (next ? next->getName() : "(null)") +"')" );
01019 if ( this->executeProgram(currentExit, stepping) == false )
01020 return false;
01021
01022 TRACE("Finished exit program from '"+ current->getName() + "' (going to '"+ (next ? next->getName() : "(null)") +"')" );
01023
01024 if ( stepping ) {
01025 currentProg = (currentEntry ? currentEntry : currentRun);
01026 return false;
01027 }
01028 }
01029
01030
01031
01032
01033 if ( current != next ) {
01034 if ( next ) {
01035 reqstep = stateMap.find( next )->second.begin();
01036 reqend = stateMap.find( next )->second.end();
01037
01038 if ( reqstep == reqend )
01039 evaluating = 0;
01040 else
01041 evaluating = get<3>(*reqstep);
01042 } else {
01043 current = 0;
01044 return true;
01045 }
01046
01047 TRACE("Formally transitioning from '"+ (current ? current->getName() : "(null)") + "' to '"+ (next ? next->getName() : "(null)") +"'" );
01048 current = next;
01049 }
01050
01051 if ( currentEntry ) {
01052 TRACE("Executing entry program of '"+ current->getName() +"'" );
01053 if ( this->executeProgram(currentEntry, stepping) == false )
01054 return false;
01055
01056 TRACE("Finished entry program of '"+ current->getName() +"'" );
01057
01058 if ( stepping ) {
01059 currentProg = currentRun;
01060 return false;
01061 }
01062 }
01063
01064
01065
01066 if ( currentHandle ) {
01067 TRACE("Executing handle program of '"+ current->getName() +"'" );
01068 if ( this->executeProgram(currentHandle, stepping) == false )
01069 return false;
01070
01071 TRACE("Finished handle program of '"+ current->getName() +"'" );
01072
01073 if ( stepping ) {
01074 currentProg = currentRun;
01075 return false;
01076 }
01077 }
01078
01079
01080 if ( currentRun ) {
01081 TRACE("Executing run program of '"+ current->getName() +"'" );
01082 if ( this->executeProgram(currentRun, stepping) == false )
01083 return false;
01084
01085 TRACE("Finished run program of '"+ current->getName() +"'" );
01086
01087 if ( stepping )
01088 return false;
01089
01090 }
01091
01092 return true;
01093 }
01094
01095 bool StateMachine::executeProgram(ProgramInterface*& cp, bool stepping)
01096 {
01097 TRACE_INIT();
01098 if ( cp == 0)
01099 return false;
01100
01101 currentProg = cp;
01102 if ( stepping )
01103 currentProg->step();
01104 else
01105 currentProg->execute();
01106 if ( currentProg->inError() ) {
01107 smStatus = Status::error;
01108 smpStatus = nill;
01109 TRACE("Encountered run-time error at line " << this->getLineNumber() );
01110 return false;
01111 }
01112
01113 if ( currentProg && !currentProg->isStopped() )
01114 return false;
01115
01116 cp = currentProg = 0;
01117 return true;
01118 }
01119
01120
01121
01122 bool StateMachine::inTransition() const {
01123 return currentProg != 0 && currentProg != currentRun && currentProg != currentHandle;
01124 }
01125
01126
01127 bool StateMachine::interruptible() const {
01128 return currentProg == 0 || currentProg == currentRun;
01129 }
01130
01131 void StateMachine::setInitialState( StateInterface* s )
01132 {
01133 initstate = s;
01134 stateMap[initstate];
01135 }
01136
01137 void StateMachine::setFinalState( StateInterface* s )
01138 {
01139 finistate = s;
01140 stateMap[finistate];
01141 }
01142
01143 void StateMachine::trace(bool t) {
01144 mtrace =t;
01145 }
01146
01147 bool StateMachine::activate()
01148 {
01149 TRACE_INIT();
01150
01151 if ( smStatus != Status::inactive ) {
01152 TRACE("Won't activate: already active.");
01153 return false;
01154 }
01155
01156 smpStatus = nill;
01157
01158 if ( this->checkConditions( getInitialState() ) != 1 ) {
01159 TRACE("Won't activate: preconditions failed.");
01160 return false;
01161 }
01162
01163 if ( initc ) {
01164 initc->reset();
01165 initc->readArguments();
01166 if ( initc->execute() == false ) {
01167 TRACE("Won't activate: Init Commands failed.");
01168 return false;
01169 }
01170 }
01171
01172
01173 enterState( getInitialState() );
01174 reqstep = stateMap.find( next )->second.begin();
01175 reqend = stateMap.find( next )->second.end();
01176
01177
01178 enableGlobalEvents();
01179
01180
01181 if ( !inError() ) {
01182 if ( this->executePending() ) {
01183 smStatus = Status::active;
01184 TRACE("Activated.");
01185 } else {
01186 if ( !inError() ) {
01187 TRACE("Still activating.");
01188 smStatus = Status::activating;
01189 }
01190 }
01191 }
01192
01193 return true;
01194 }
01195
01196
01197 bool StateMachine::deactivate()
01198 {
01199 TRACE_INIT();
01200
01201 if ( smStatus == Status::inactive) {
01202 TRACE("Won't deactivate: already inactive.");
01203 return false;
01204 }
01205 os::MutexLock lock(execlock);
01206
01207
01208 disableGlobalEvents();
01209
01210
01211
01212 if ( currentExit && currentExit->inError() )
01213 currentExit = 0;
01214 if ( currentTrans && currentTrans->inError() )
01215 currentTrans = 0;
01216
01217
01218 if ( next != 0 && current )
01219 leaveState( current );
01220 else {
01221 currentExit = 0;
01222 currentTrans = 0;
01223 }
01224
01225
01226 currentProg = 0;
01227 currentEntry = 0;
01228 currentHandle = 0;
01229 currentRun = 0;
01230 next = 0;
01231
01232
01233
01234 if ( this->executePending() ) {
01235 TRACE("Deactivated.");
01236 smStatus = Status::inactive;
01237 } else {
01238 TRACE("Still deactivating.");
01239 smStatus = Status::deactivating;
01240 }
01241
01242 return true;
01243 }
01244 }