Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
StateNode.hGo 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 |