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 }