Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Transition.cc

Go to the documentation of this file.
00001 #include "Transition.h"
00002 #include "StateNode.h"
00003 #include "Wireless/Wireless.h"
00004 #include "Sound/SoundManager.h"
00005 #include "Events/EventRouter.h"
00006 #include "Shared/debuget.h"
00007 
00008 std::list<Transition*> Transition::firing;
00009 
00010 Transition::~Transition() {
00011   ASSERT(!isActive(),"Transition " << getName() << " destructing while active (forgot stop()?)");
00012   ASSERT(std::find(firing.begin(),firing.end(),this)==firing.end(),"Transition " << getName() << " still active in firing queue!");
00013   if(eventData) {
00014     delete eventData;
00015     eventData = NULL;
00016   }
00017 }
00018 
00019 void Transition::stop() {
00020   eventData = NULL;
00021   firing.remove(this);
00022   BehaviorBase::stop();
00023 }
00024 
00025 void Transition::fire() {
00026   ASSERT(eventData==NULL, getName() << " firing with event still buffered")
00027   if(std::find(firing.begin(), firing.end(), this) == firing.end())
00028     firing.push_back(this);
00029   else {
00030     std::cout << "Trying to fire " << getName() << " but it's already on the call stack." << std::endl;
00031     showFiring();
00032   }
00033   
00034   if(firing.front()==this)  // only do firing from root of call stack...
00035     fireDownCallStack();
00036 }
00037 
00038 void Transition::fire(const EventBase& ev) {
00039   ASSERT(eventData==NULL, getName() << " firing with previous event already buffered, overwriting...");
00040   if ( eventData != NULL )
00041     std::cout << "Previous=" << eventData->getName() << " @ " << event->getTimeStamp()
00042               << "    New=" << ev.getName() << " @ " << ev.getTimeStamp() << std::endl;
00043   eventData = ev.clone();
00044   if(std::find(firing.begin(), firing.end(), this) == firing.end())
00045     firing.push_back(this);
00046   else {
00047     std::cout << "Trying to fire " << getName() << " but it's already on the call stack." << std::endl;
00048     showFiring();
00049   }
00050   
00051   if(firing.front()==this)  // only do firing from root of call stack...
00052     fireDownCallStack();
00053 }
00054 
00055 void Transition::fireDownCallStack() {
00056   while(!firing.empty())
00057     firing.front()->doFire();
00058 }
00059 
00060 void Transition::doFire() {
00061   ASSERTRET(isActive(),"doFire from " << getName() << " but not active");
00062   
00063   addReference(); //just in case a side effect of this transition is to dereference the transition, we don't want to be deleted while still transitioning
00064   
00065   if(soundFile.size()!=0)
00066     sndman->playFile(soundFile);
00067 #ifdef PLATFORM_APERIOS
00068   if ( !speechText.empty() )
00069     sout->printf("Speak: %s\n",speechText.c_str());
00070 #else
00071   if ( !speechText.empty() )
00072     sndman->speak(speechText);
00073 #endif
00074   
00075   erouter->postEvent(EventBase::stateTransitionEGID,
00076                      reinterpret_cast<size_t>(this),
00077                      EventBase::activateETID,0,getName(),1);
00078   
00079   //HACK - This prevents recursive transitions from thinking they're at the top of the call stack
00080   firing.push_front(NULL);
00081   
00082   const EventBase* eventDataSave = eventData; // save on stack because Transition::stop() will clear it
00083   for(unsigned int i=0; i<srcs.size(); i++) {
00084     try {
00085       if(srcs[i]->isActive()) //It's usually a bad idea to call stop/start when it's already stopped/started...
00086         srcs[i]->stop();
00087     } catch(const std::exception& ex) {
00088       std::cout << "Exception '" << ex.what() << "' thrown during transition "
00089                 << getName() << ", deactivating source node " << srcs[i]->getName() << std::endl;
00090     } catch(...) {
00091       std::cout << "Exception thrown during transition " << getName()
00092                 << ", deactivating source node " << srcs[i]->getName() << std::endl;
00093       firing.pop_front();
00094       removeReference();
00095       throw;
00096     }
00097   }
00098   // sets BehaviorBase::event for duration of start call and then restores it
00099   for(unsigned int i=0; i<dsts.size(); i++) {
00100     const EventBase* prevEvent = dsts[i]->event; // in case of recursive events triggered by doEvent
00101     dsts[i]->event=eventDataSave;
00102     try {
00103       if(!dsts[i]->isActive())
00104         dsts[i]->start();
00105     } catch(const std::exception& ex) {
00106       std::cout << "Exception '" << ex.what() << "' thrown during transition "
00107                 << getName() << ", activating destination node " << dsts[i]->getName() << std::endl;
00108     } catch(...) {
00109       std::cout << "Exception thrown during transition " << getName()
00110                 << ", activating destination node " << dsts[i]->getName() << std::endl;
00111       firing.pop_front();
00112       removeReference();
00113       throw;
00114     }
00115     dsts[i]->event=prevEvent;
00116   }
00117 
00118   delete eventDataSave;
00119   firing.pop_front();  // get rid of the NULL blocking recursive transitions
00120   erouter->postEvent(EventBase::stateTransitionEGID,
00121                      reinterpret_cast<size_t>(this),
00122                      EventBase::deactivateETID,0,getName(),0);
00123   
00124   if ( isActive() ) {
00125     if ( firing.size()>0 ) { // might be 0 if self-transition
00126       ASSERTIF(firing.front()==this, "doFire from " << getName() << " but it's not my turn, should be " << firing.front()->getName()) {
00127         firing.pop_front();
00128       }
00129     }
00130   } else {
00131     ASSERT(std::find(firing.begin(),firing.end(),this)==firing.end(),"Transition still in firing queue following doFire, subclass overridden stop() and forgot to call Transition::stop()?");
00132   }
00133 
00134   removeReference();
00135 }
00136 
00137 void Transition::showFiring() {
00138   std::cout << "firing =";
00139   for (std::list<Transition*>::const_iterator it = firing.begin();
00140        it != firing.end(); it++) {
00141     std::cout << " ";
00142     if ( *it == NULL )
00143       std::cout << "0";
00144     else
00145       std::cout << (*it)->instanceName;
00146   }
00147   std::cout << std::endl;
00148 }
00149 
00150 std::string Transition::getName() const {
00151   if(instanceName != getClassName()) {
00152     return instanceName;
00153   } else {
00154     std::string ans;
00155     if ( srcs.size() == 1 )
00156       ans = srcs[0]->getName();
00157     else {
00158       ans = '{';
00159       for(unsigned int i=0; i<srcs.size(); i++)
00160         ans += srcs[i]->getName() + (i<srcs.size()-1?',':'}');
00161     }
00162     ans += ">==" + instanceName + "==>";
00163     if ( dsts.size() == 1 )
00164       ans += dsts[0]->getName();
00165     else {
00166       ans += '{';
00167       for(unsigned int i=0; i<dsts.size(); i++)
00168       ans += dsts[i]->getName() + (i<dsts.size()-1?',':'}');
00169     }
00170     return ans;
00171   }
00172 }
00173 
00174 /*! @file
00175  * @brief Implements Transition, represents a transition between StateNodes.
00176  * @author ejt (Creator)
00177  */
00178 

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:52 2016 by Doxygen 1.6.3