Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

StateNode.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_StateNode_h_
00003 #define INCLUDED_StateNode_h_
00004 
00005 #include "Behaviors/BehaviorBase.h"
00006 #include "Events/DataEvent.h"
00007 #include "Events/EventRouter.h"
00008 #include <vector>
00009 #include <string>
00010 
00011 class Transition;
00012 
00013 //! Recursive data structure - both a state machine controller as well as a node within a state machine itself
00014 /*!
00015  *  Override setup() to build your own Transition and StateNode network if you want
00016  *  this node to contain a state machine.
00017  *
00018  *  Override doStart() / doStop() as you would a normal BehaviorBase subclass to
00019  *  have this node add some functionality of its own.
00020  *  
00021  *  You can override setup to create a sub-network, as well as overriding doStart and doStop, in the same class.
00022  *  
00023  *  See also the <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/state.shtml">tutorial page on State Machines</a>.
00024  *  
00025  *  There are two StateNode templates in <a href="http://cvs.tekkotsu.org/cgi/viewcvs.cgi/Tekkotsu/project/templates/"><i>project</i><tt>/templates/</tt></a>:
00026  *  - <a href="http://cvs.tekkotsu.org/cgi/viewcvs.cgi/Tekkotsu/project/templates/statenode.h?rev=HEAD&content-type=text/vnd.viewcvs-markup">statenode.h</a>
00027  *    is intended for leaf nodes, which directly implement the execution of a task.
00028  *  - <a href="http://cvs.tekkotsu.org/cgi/viewcvs.cgi/Tekkotsu/project/templates/statemachine.h?rev=HEAD&content-type=text/vnd.viewcvs-markup">statemachine.h</a>
00029  *    is intended for nodes which contain a network of transitions and subnodes, which together solve the task.
00030  */
00031 class StateNode  : public BehaviorBase {
00032   friend class Transition;
00033 public:
00034   //!constructor, class name from typeid is used as instance name
00035   StateNode()
00036     : BehaviorBase(), parent(NULL), transitions(), issetup(false), 
00037       retain(true), startedTime(0), nodes(), startnode(NULL), speechText()
00038   {}
00039   //!constructor, pass a name to use
00040   StateNode(const std::string& name)
00041     : BehaviorBase(name), parent(NULL), transitions(), issetup(false), 
00042       retain(true), startedTime(0), nodes(), startnode(NULL), speechText()
00043   {}
00044 
00045   //!destructor, removes references to its outgoing transitions (be careful of incoming ones - they're still around!), and calls removeReference() on subnodes
00046   virtual ~StateNode();
00047 
00048   //!Adds the specified StateTransition to the transition table
00049   virtual Transition* addTransition(Transition* trans);
00050 
00051   //!Returns the std::vector of transitions so you can modify them yourself if need be
00052   std::vector<Transition*>& getTransitions() { return transitions; }
00053 
00054   //!Returns the const std::vector of transitions so you can read through them if need be
00055   const std::vector<Transition*>& getTransitions() const { return transitions; }
00056 
00057   //!Adds a StateNode to #nodes so it can be automatically dereferenced later, returns what it's passed (for convenience), calls addReference() on @a node.  Also sets the node's parent to @c this if it is null.
00058   virtual StateNode* addNode(StateNode* node);
00059   //!Adds a StateNode to #nodes so it can be automatically dereferenced later, returns what it's passed (for convenience), calls addReference() on @a node.  Also sets the node's parent to @c this if it is null.
00060   template<class T> T* addNode(T* node) { addNode(dynamic_cast<StateNode*>(node)); return node; }
00061 
00062   //!Returns the std::vector of sub-nodes so you can modify them yourself if need be
00063   std::vector<StateNode*>& getNodes() { return nodes; }
00064 
00065   //!Returns the const std::vector of sub-nodes so you can read through them if need be
00066   const std::vector<StateNode*>& getNodes() const { return nodes; }
00067 
00068   //!Sets the retain flag - if not retained, will removeReference() subnodes upon stop() and recreate them on start (by calling setup()) - may be too expensive to be worth saving memory...
00069   void setRetain(bool f) { retain=f; }
00070 
00071   //!Transitions should call this when entering the state, so it can enable its transitions
00072   virtual void start();
00073 
00074   //!This is called by start() when it should setup the network of subnodes (if any)
00075   virtual void setup() {}
00076 
00077   //!Transitions should call this when leaving the state, so it can disable its transitions
00078   virtual void stop();
00079   
00080   //!This is called by stop() when you should destruct subnodes
00081   /*!Default implementation will take care of the subnodes and their
00082    * transitions, you only need to worry about any *other* memory
00083    * which may have been allocated.  If none, you may not need
00084    * implement this function at all. */
00085   virtual void teardown();
00086 
00087   //!returns pointer to #parent as a generic StateNode
00088   virtual StateNode* getParent() const { return parent; }
00089 
00090   //! returns a correctly typed pointer to ancestor of the specified type; user by $reference
00091   template<class T> T* getAncestor() const;
00092 
00093   //! returns correctly typed pointer to #parent for access to its members
00094   template<class T> T* parentAs() const { return dynamic_cast<T*>(getParent()); }
00095 
00096   //! returns node with specified name that is a child of this node
00097   virtual StateNode* getChild(const std::string& name) const;
00098 
00099   //! returns node with specified name that is a child of #parent, or of parent's parent, etc.
00100   virtual StateNode* getSibling(const std::string& name) const;
00101 
00102   //! Set text to speak on node start
00103   virtual void setSpeechText(const std::string &text) { speechText=text; }
00104 
00105   //! Extract data from a signal sent to this state via Transition::fire(const EventBase&)
00106   template<typename T>
00107   static const T extractSignal(const EventBase *ev) {
00108     const DataEvent<T> *datev = dynamic_cast<const DataEvent<T>*>(ev);
00109     if ( datev == NULL )
00110       return T();
00111     else
00112       return datev->getData();
00113   }
00114 
00115   //! Try to extract data from a signal sent to this state via Transition::fire(const EventBase&)
00116   template<typename T>
00117   static const T* tryExtractSignal(const EventBase *ev) {
00118     const DataEvent<T> *datev = dynamic_cast<const DataEvent<T>*>(ev);
00119     if ( datev == NULL )
00120       return NULL;
00121     else
00122       return &(datev->getData());
00123   }
00124 
00125   //! Values used in a SignalTrans for postStateSuccess and postStateFailure
00126   enum SuccessOrFailure { failureSignal=0, successSignal=1 };
00127 
00128 protected:
00129   //!will post an activation event through stateMachineEGID, used when doStart() is called
00130   virtual void postStateStart();
00131 
00132   //!will post an deactivation event through stateMachineEGID, used when doStop() is called
00133   /* @param duration the value to use for EventBase::duration -- nice but not generally used */
00134   virtual void postStateStop();
00135 
00136   //!will post a status event through stateMachineEGID to signal "completion" of the node
00137   /*! "completion" is defined by your subclass - will mean different things to different
00138    *  nodes depending on the actions they are performing.  So call this yourself if there
00139    *  is a natural ending point for your state.
00140    * @param magnitude the value to use for EventBase::magnitude -- generally is 1 for status events, but since this is to signal completion, 0 (the default) may be more appropriate; if your node is doing something repetitive however, 1 (or the loop count) may be better */
00141   virtual void postStateCompletion(float magnitude=0);
00142 
00143   //! posts a DataEvent<SuccessOrFailure>(failure) indicating failure of the node; meaning of failure is used-defined
00144   virtual void postStateFailure() { postStateSignal<SuccessOrFailure>(failureSignal); }
00145 
00146   //! posts a DataEvent<SuccessOrFailure>(success) indicating success of the node; meaning of success is used-defined
00147   virtual void postStateSuccess() { postStateSignal<SuccessOrFailure>(successSignal); }
00148 
00149   //! Causes the parent state machine to complete; use this to return from a nested state machine
00150   virtual void postParentCompletion() { getParent()->postStateCompletion(); }
00151 
00152   //! Causes the parent state machine to fail; use this to return failure from a nested state machine
00153   virtual void postParentFailure() { getParent()->postStateFailure(); }
00154 
00155   //! Causes the parent state machine to succeed; use this to return success from a nested state machine
00156   virtual void postParentSuccess() { getParent()->postStateSuccess(); }
00157 
00158   //! Causes the parent state machine to post a DataEvent through stateSignalEGID.  @a value is optional.
00159   template<typename T> void postParentSignal(const T& value=T()) {
00160     getParent()->postStateSignal<T>(value);
00161   }
00162 
00163   //! Posts a DataEvent through stateSignalEGID that can be picked up by a SignalTrans.  @a value is optional.
00164   template<typename T> void postStateSignal(const T& value=T()) {
00165     erouter->postEvent(DataEvent<T>(value, EventBase::stateSignalEGID,(size_t)this, EventBase::statusETID,0,getName(),0));
00166   }
00167 
00168   //Node Stuff:
00169   //! pointer to the machine that contains this node
00170   StateNode* parent;
00171   //! a vector of outgoing transitions
00172   std::vector<Transition*> transitions;
00173   
00174   //Machine Stuff:
00175   //! this is set to true if the network has been setup but not destroyed (i.e. don't need to call setupSubNodes again)
00176   bool issetup;
00177   //! this is set to true if the network should be retained between activations.  Otherwise it's dereferenced upon doStop(). (or at least removeReference() is called on subnodes)
00178   bool retain;
00179   //! the timestamp of last call to start()
00180   unsigned int startedTime;
00181   //! vector of StateNodes, just so they can be dereferenced again on doStop() (unless retained) or ~StateNode()
00182   std::vector<StateNode*> nodes;
00183   
00184   //! starting node (should be a member of @a nodes)
00185   StateNode* startnode;
00186 
00187   //! Text to speak on node start (for debugging)
00188   std::string speechText;
00189 
00190 private:
00191   StateNode(const StateNode& node); //!< don't call this
00192   StateNode operator=(const StateNode& node); //!< don't call this
00193   virtual void DoStartEvent(struct __USE_doStart_AND_CHECK_event_NOT_DoStartEvent__&) {} //!< temporary to produce warnings to help people update
00194 };
00195 
00196 template<class T> T* StateNode::getAncestor() const {
00197   const StateNode *p = this;
00198   while ( (p = p->getParent()) != NULL ) {
00199     if ( const T* ancestor = dynamic_cast<const T*>(p) )
00200       return const_cast<T*>(ancestor);
00201   }
00202   std::cerr << "StateNode::getAncestorAs() failed to find ancestor of requested type\n";
00203   return NULL;
00204 }
00205   
00206 
00207 
00208 /*! @file
00209  * @brief Describes StateNode, which is both a state machine controller as well as a node within a state machine itself
00210  * @author ejt (Creator)
00211  */
00212 
00213 #endif

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