Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
EventRouter.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_EventRouter_h 00003 #define INCLUDED_EventRouter_h 00004 00005 #include <string> 00006 #include <vector> 00007 #include <queue> 00008 #include <map> 00009 #include <list> 00010 #include <algorithm> 00011 #include "EventListener.h" 00012 #include "EventTrapper.h" 00013 #include "Shared/get_time.h" 00014 #include "Shared/debuget.h" 00015 #include "Shared/attributes.h" 00016 #include "IPC/ProcessID.h" 00017 #include <iostream> 00018 #include "Shared/RemoteState.h" 00019 00020 #include "Wireless/SocketListener.h" 00021 #include "Wireless/Socket.h" 00022 00023 class RemoteRouter; 00024 class EventTranslator; 00025 class EventProxy; 00026 00027 //! This class will handle distribution of events as well as management of timers 00028 /*! Classes must inherit from EventListener and/or EventTrapper in order to 00029 * receive events. 00030 * 00031 * Use the global ::erouter instance of EventRouter to both send (post) and receive (subscribe/listen) to 00032 * events. (except if you are posting from within a MotionCommand, in 00033 * which case you should use MotionCommand::postEvent() so that it can correctly 00034 * handle inter-process communication issues under Aperios (the Aibo's OS) -- under a 00035 * Unix-based OS, this isn't necessary.) Events posted in non-Main processes 00036 * will be forwarded to Main for processing. 00037 * 00038 * Event processing is a serialized operation, meaning only one event is ever being 00039 * processed at a time, and by one listener at a time. The EventRouter contains its own 00040 * thread lock, so if two threads post events at the same time, the EventRouter 00041 * will handle ensuring mutual exclusion. Listeners are free to spawn their own 00042 * threads to handle processing or posting events to avoid being dependent on 00043 * other listeners' processing times. (Note: threads are not available on the Aibo, 00044 * so listeners which wish to run on the Aibo are stuck with a "cooperative" 00045 * multitasking model) 00046 * 00047 * The events available for processing are listed in EventBase::EventGeneratorID_t. 00048 * Each generator ID's documentation specifies how to interpret the source ID field, and whether 00049 * you can expect events with that generator ID to be of a subclass of EventBase, 00050 * such as TextMsgEvent or LocomotionEvent. Many generators send plain 00051 * EventBase instances. 00052 * 00053 * When multiple listeners are subscribed, the order in which an event is 00054 * distributed among them is: 00055 * -# "Specific" listeners: any listener which specifies a particular source id. 00056 * (doesn't matter if they specified type id as well) 00057 * - older listeners get events before more recently added listeners ("FIFO") 00058 * -# "General" listeners: those that subscribe to an entire generator 00059 * - older listeners get events before more recently added listeners ("FIFO") 00060 * 00061 * ...but if you're relying on that ordering, there probably should be a cleaner 00062 * way to do whatever you're doing. 00063 * 00064 * TimerEvents are generally only sent to the generator which requested them. So if 00065 * EventListener @e A requests a timer (see addTimer()) with ID 0 at two second intervals, 00066 * and @e B requests a timer with ID 0 at three second intervals, 00067 * each will still only receive the timers they requested - no cross talk. 00068 * The timer generator is unique in this regard, which is why it is built in 00069 * as an integral component of the EventRouter. However, EventListener @e A 00070 * <b>can</b> receive @e B's timers if it specifically wants to, via addListener(). See "Timers" below. 00071 * 00072 * If an EventListener/EventTrapper subscribes to the same event source multiple 00073 * times, it will receive multiple copies of the event. However, the first call 00074 * to removeListener for a source will remove all subscriptions to that source.\n 00075 * Example: EventListener @e A subscribes to (buttonEGID,*,*), and twice to 00076 * (buttonEGID,0,*). 00077 * - If button 0 is pressed, @e A will get three copies of the event. 00078 * - If button 1 is pressed, @e A will get one copy. 00079 * - If removeListener(&A,buttonEGID) is called, the (buttonEGID,*,*) is 00080 * removed, <em>as well as</em> both of (buttonEGID,0,*). 00081 * - If removeListener(&A,buttonEGID,0) is called, both of (buttonEGID,0,*) 00082 * are removed, but (buttonEGID,*,*) would be untouched. 00083 * 00084 * <h3>Timers</h3> 00085 * addTimer() allows you to request an TimerEvent to be sent at some later point in time, 00086 * possibly on a repeating basis. Timers are specific to the behavior which requests 00087 * them, and you @e do @e not (and usually should not) call addListener() in order to receive a timer 00088 * event. 00089 * 00090 * There is an important different between addTimer() and #addListener(timerEGID,...)! 00091 * addTimer will "create" the timer, and will send the timer to the listener 00092 * which created it when the timer expires. This means that as long as the listener in 00093 * question does @e not call addListener(timerEGID), it will @e only receive its own timers. 00094 * In other words, with this usage there is no confusion with timer cross-talk between 00095 * listeners, because each listener is only receiving its own timers. 00096 * 00097 * However, if a listener calls addListener(timerEGID), it will begin receiving @e all timer events 00098 * from throughout the system. This allows you to have one behavior "eavesdrop" on 00099 * another's timers. In order to determine which listener requested/created the timer, 00100 * you can use the TimerEvent::getTarget() value. 00101 * 00102 * So beware that if you call both addTimer() and addListener(foo,timerEGID), 'foo' will get 00103 * two calls to processEvent() for its own timers, and one call for all other timers, and will 00104 * have to know to call TimerEvent::getTarget() to distinguish its timers from other 00105 * listener's timers (if it cares about the difference...) 00106 * 00107 * Timers are sent to the requesting listener before being broadcast -- EventTrappers cannot 00108 * filter a listener's own timers, but can prevent the timer from being broadcast to other listeners. 00109 * 00110 * <h3>Event processing examples:</h3> 00111 * 00112 * Posting events: 00113 * @codeEventProxy 00114 * //method A: basic event posting (EventBase instance is sent) 00115 * erouter->postEvent(EventBase::aiEGID, 1234, EventBase::statusETID); 00116 * 00117 * //method B: specific event instance is posted (have to use this style to post a subclass) 00118 * TextMsgEvent txt("hello world"); 00119 * erouter->postEvent(txt); 00120 * // or can be done in one line: 00121 * erouter->postEvent(TextMsgEvent("hello world")) 00122 * @endcode 00123 * 00124 * Receiving events: 00125 * @code 00126 * //given an EventListener subclass: 00127 * class YourListener : public EventListener { 00128 * public: 00129 * virtual void processEvent(const EventBase& e) { 00130 * std::cout << "Got: " << e.getName() << std::endl; 00131 * } 00132 * }; 00133 * 00134 * YourListener yourList; 00135 * 00136 * // subscribes it to all EventBase::aiEGID events: 00137 * erouter->addListener(&yourList, EventBase::aiEGID); 00138 * 00139 * // subscribes only to button activity from the head, but not other buttons: 00140 * erouter->addListener(&yourList, EventBase::buttonEGID, ERS7Info::HeadButOffset); 00141 * @endcode 00142 * Typically in a BehaviorBase subclass, you would just specify 'this' instead of '&yourList'. 00143 * 00144 * <h3>Timer processing examples:</h3> 00145 * 00146 * Requesting/Creating timers: 00147 * @code 00148 * YourListener yourList; // (any EventListener subclass) 00149 * 00150 * // sends a timer with source ID 123 every 5 seconds to yourList: 00151 * erouter->addTimer(&yourList, 123, 5000); 00152 * 00153 * // sends a timer with ID 456 after 1 second, *no repeat, one time only* 00154 * erouter->addTimer(&yourList, 456, 1000, false); 00155 * 00156 * // cancels the first timer 00157 * erouter->removeTimer(&yourList, 123); 00158 * 00159 * // postpone/update the second timer's settings (*doesn't* create two timers with the same ID) 00160 * erouter->addTimer(&yourList, 456, 2500, false); 00161 * 00162 * @endcode 00163 * Again, typically in a BehaviorBase subclass, you would just specify 'this' instead of '&yourList'. 00164 * 00165 * @see EventBase::EventGeneratorID_t for a complete listing of all generators, 00166 * as well as instructions on how to add new generators. 00167 * @see Tutorials: 00168 * - <a href="../FirstBehavior2.html">Steps 3, 4, & 5 of Tekkotsu's First Behavior Tutorial</a> 00169 * - <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/events.shtml">David Touretzky's Events Chapter</a> 00170 * - <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/behaviors.pdf">CMU's Cognitive Robotics course slides</a> 00171 */ 00172 class EventRouter : public EventListener, public SocketListener { 00173 public: 00174 EventRouter(); //!< Constructs the router 00175 virtual ~EventRouter(); //!< just calls reset and removeAllTimers() 00176 00177 void reset() { listeners.clear(); trappers.clear(); removeAllTimers(); } //!< erases all listeners, trappers and timers, resets EventRouter 00178 00179 00180 //!@name Posting/Processing Events 00181 00182 /*!@brief recommended to create and post an event using current buffer setting */ 00183 void postEvent(EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid, unsigned int dur=0) { processEvent(EventBase(egid,sid,etid,dur)); } 00184 void postEvent(EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid, unsigned int dur, const std::string& n, float m) { processEvent(EventBase(egid,sid,etid,dur,n,m)); } 00185 //! deprecated -- pass by reference instead; this version posts the specified event and then deletes it after processing is complete 00186 /*! moving to pass by reference instead of pass by pointer to avoid questions about who deletes the event and the event's scope, 00187 * also keeping the event on the stack is faster by avoiding unnecessary heap operations. */ 00188 void postEvent(EventBase* e) ATTR_deprecated; 00189 //! posts the specified event, but doesn't delete it at the end -- equivalent to processEvent(e) 00190 void postEvent(const EventBase& e) { processEvent(e); } 00191 00192 //! determines if timers need to be posted, and posts them if so. 00193 /*! Call this often to ensure accurate timers. */ 00194 void processTimers(); 00195 //! sends event to its trappers & listeners, but doesn't delete the event at the end (see also postEvent()) 00196 /*! this posting method is supplied to allow an EventRouter to behave as a listener as 00197 * well -- the 'routers' really can form a sort of network, if desired. postEvent() is 00198 * probably a more memnomic interface to use in direct function calls however, 00199 * so that is the one you should call. */ 00200 void processEvent(const EventBase& e); 00201 00202 //! returns the forwarding agent for a given process/thread group (see #forwards) 00203 EventTranslator* getForwardingAgent(ProcessID::ProcessID_t proc) const { return forwards[proc]; } 00204 //! sets the forwarding agent for a given process/thread group (see #forwards) 00205 void setForwardingAgent(ProcessID::ProcessID_t proc, EventTranslator* trans); 00206 //@} 00207 00208 00209 //!@name Listener/Trapper Recall 00210 00211 //! returns true if the specified listener/trapper would receive any events that match the specified criteria 00212 bool isListeningAny(EventListener* el, EventBase::EventGeneratorID_t egid) { return listeners.verifyMappingAny(el,egid); } 00213 bool isListeningAny(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid) { return listeners.verifyMappingAny(el,egid,sid); } 00214 bool isListeningAll(EventListener* el, EventBase::EventGeneratorID_t egid) { return listeners.verifyMappingAll(el,egid); } 00215 bool isListeningAll(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid) { return listeners.verifyMappingAll(el,egid,sid); } 00216 bool isListening(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) { return listeners.verifyMapping(el,egid,sid,etid); } 00217 bool isListening(EventListener* el, const EventBase& e) { return listeners.verifyMapping(el,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00218 bool isTrappingAny(EventTrapper* el, EventBase::EventGeneratorID_t egid) { return trappers.verifyMappingAny(el,egid); } 00219 bool isTrappingAny(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid) { return trappers.verifyMappingAny(el,egid,sid); } 00220 bool isTrappingAll(EventTrapper* el, EventBase::EventGeneratorID_t egid) { return trappers.verifyMappingAll(el,egid); } 00221 bool isTrappingAll(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid) { return trappers.verifyMappingAll(el,egid,sid); } 00222 bool isTrapping(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) { return trappers.verifyMapping(el,egid,sid,etid); } 00223 bool isTrapping(EventTrapper* el, const EventBase& e) { return trappers.verifyMapping(el,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00224 //@} 00225 00226 00227 //!@name Listener/Trapper Detection 00228 00229 /*!@brief <b>counts both listeners and trappers</b>, so generators can tell if it even needs to bother generating an event...*/ 00230 /* Generators can also subscribe to the EventBase::erouterEGID event stream if 00231 * they wish to be notified when they gain or lose listeners (particularly the 00232 * first or last).\n 00233 * ... if a tree falls in a forest, and there's no one around to see it, does 00234 * it make a sound?\n 00235 * ... if Vision sees a ball in an image, and there's no listeners, does it 00236 * make an event? ;) */ 00237 bool hasListeners(EventBase::EventGeneratorID_t egid) { return trappers.hasMapping(egid) || listeners.hasMapping(egid); } 00238 bool hasListeners(EventBase::EventGeneratorID_t egid, size_t sid) { return trappers.hasMapping(egid,sid) || listeners.hasMapping(egid,sid); } 00239 bool hasListeners(EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) { return trappers.hasMapping(egid,sid,etid) || listeners.hasMapping(egid,sid,etid); } 00240 bool hasListeners(const EventBase& e) { return hasListeners(e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00241 //@} 00242 00243 00244 //!@name Timer Management 00245 00246 //! adds a timer if it doesn't exist, or resets the timer if it already exists. 00247 void addTimer(EventListener* el, size_t sid, unsigned int delay, bool repeat=true); 00248 void addTimer(EventListener* el, const EventBase& e, bool repeat=true) { addTimer(el,e.getSourceID(),e.getDuration(),repeat); } //!< calls the other addTimer() with the event's source id and duration, doesn't check to see if the generator is timerEGID 00249 00250 //! clears all pending timers for listener @a el; see remove() 00251 void removeTimer(EventListener* el); 00252 void removeTimer(EventListener* el, size_t sid); //!< clears any pending timers with source id @a sid for listener @a el 00253 void removeTimer(EventListener* el, EventBase& e) { if(e.getGeneratorID()==EventBase::timerEGID) removeTimer(el,e.getSourceID()); } //!< clears any pending timers with source id matching that of @a e, but only if @a e has generator timerEGID 00254 void removeAllTimers(); //!< clears all timers for all listeners 00255 unsigned int getNextTimer() { return (timers.size()==0 ? -1U : timers.front()->next); } //!< returns time of next timer activation 00256 //@} 00257 00258 00259 //!@name Listener Management 00260 00261 //! Adds a listener for all events from a given event generator 00262 void addListener(EventListener* el, EventBase::EventGeneratorID_t egid); 00263 void addListener(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< Adds a listener for all types from a specific source and generator 00264 void addListener(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); //!< Adds a listener for a specific source id and type from a given event generator 00265 void addListener(EventListener* el, const EventBase& e); //!< Uses the generator, source, and type fields of @a e to add a listener for that specific tuple 00266 00267 00268 //!@name Remote Event/State code 00269 00270 //! Converts a int representation of an IP to a string 00271 static std::string intToStringIP(int ip); 00272 //! Converts a string representation of an IP to an int 00273 static int stringToIntIP(std::string ip); 00274 00275 //! Request remote events to be sent to this dog, works like the regular addListeners 00276 void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid); 00277 void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid); 00278 void addRemoteListener(EventListener* el, int host, const EventBase& e); 00279 void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); 00280 00281 //! Stop getting remote events from the given dog 00282 void removeRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid); 00283 void removeRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid); 00284 void removeRemoteListener(EventListener* el, int host, const EventBase& e); 00285 void removeRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); 00286 00287 00288 //! Request remote state updates from the remote dog, every interval ms 00289 void requestRemoteStateUpdates(int host, RemoteState::StateType type, unsigned int interval = 500); 00290 00291 //! Stop getting remote state updates 00292 void stopRemoteStateUpdates(int host, RemoteState::StateType type); 00293 00294 //! This is called once on startup; it tells the EventRouter to listen for incoming requests 00295 bool serveRemoteEventRequests(); 00296 00297 //! This handles incomiung connection requests by starting a new EventProxy 00298 int processData(char *data, int bytes); 00299 00300 static const int defaultPort = 2424; 00301 00302 protected: 00303 00304 RemoteRouter &remoteRouterForHost(int host); 00305 00306 std::list<EventProxy *> proxies; 00307 00308 std::map<int, RemoteRouter *> rrouters; 00309 Socket *sck; 00310 int nextProxyPort; 00311 00312 //!} 00313 public: 00314 00315 00316 //! stops sending ALL events to the listener -- does not remove pending timers however (may need to call removeTimer(el) as well); see remove() 00317 void removeListener(EventListener* el); 00318 //! stops sending specified events from the generator to the listener. 00319 void removeListener(EventListener* el, EventBase::EventGeneratorID_t egid); 00320 void removeListener(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< stops sending specified events from the generator to the listener. 00321 void removeListener(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); //!< stops sending specified events from the generator to the listener. 00322 void removeListener(EventListener* el, const EventBase& e); //!< Uses the generator, source, and type fields of @a e to remove a listener for that specific tuple 00323 00324 //! stops all events and timers, shorthand for removeListener(el) and removeTimer(el); Note that trappers are separate, removeTrapper() is @e not called 00325 void remove(EventListener* el) { removeListener(el); removeTimer(el); } 00326 00327 //@} 00328 00329 00330 //!@name Trapper Management 00331 00332 //! Adds a trapper for a specific source id and type from a given event generator 00333 /*! Note that only the broadcasted timers can be trapped. The EventListener which requested the timer will receive that timer before any trapping is done. */ 00334 void addTrapper(EventTrapper* el, const EventBase& e); 00335 void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid); //!< Adds a trapper for all events from a given event generator 00336 void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< Adds a trapper for all types from a specific source and generator 00337 void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); //!< Adds a trapper for a specific source id and type from a given event generator 00338 00339 void addTrapper(EventTrapper* el); //!< adds a trapper for ALL events 00340 00341 //! stops sending specified events from the generator to the trapper. 00342 void removeTrapper(EventTrapper* el, const EventBase& e); 00343 void removeTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid); //!< stops sending specified events from the generator to the trapper. 00344 void removeTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< stops sending specified events from the generator to the trapper. 00345 void removeTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); //!< stops sending specified events from the generator to the trapper. 00346 00347 void removeTrapper(EventTrapper* el); //!< stops sending ALL events to the trapper 00348 //@} 00349 00350 protected: 00351 00352 //! Contains all the information needed to maintain a timer by the EventRouter 00353 struct TimerEntry { 00354 //! constructs an entry using the given value for next - useful for with TimerEntryPtrCmp 00355 explicit TimerEntry(unsigned int nxt) : el(NULL), sid(0), delay(0), next(nxt), repeat(false) {} 00356 //! constructs with the given values, sets next field automatically; see next 00357 TimerEntry(EventListener* e, size_t s, unsigned int d, bool r) : el(e), sid(s), delay(d), next(get_time()+delay), repeat(r) {} 00358 //! just does the default, i'm just being explicit since there's a pointer (no deep copy!) 00359 TimerEntry(const TimerEntry& t) : el(t.el), sid(t.sid), delay(t.delay), next(t.next), repeat(t.repeat) {} 00360 //! just does the default, i'm just being explicit since there's a pointer (no deep copy!) 00361 TimerEntry& operator=(const TimerEntry& t) { el=t.el; sid=t.sid; delay=t.delay; next=t.next; repeat=t.repeat; return *this; } 00362 //! will reset timer 00363 /*! @param d the time from now when the timer should go off (in milliseconds) 00364 * @param r true if the timer should automatically repeat */ 00365 void Set(unsigned int d, bool r) { delay=d; repeat=r; next=get_time()+delay; } 00366 EventListener* el; //!< the listener to fire at 00367 size_t sid; //!< the source id to fire with 00368 unsigned int delay; //!< the delay until firing 00369 unsigned int next; //!< the time at which this timer will go off next 00370 bool repeat; //!< if true, will reset after firing, else will be deleted 00371 }; 00372 /*! @brief Used by STL to sort the timer list in order of activation time 00373 * @see EventRouter::timers */ 00374 class TimerEntryPtrCmp { 00375 public: 00376 //! Used by STL to sort the timer list in order of activation time; see timers 00377 /*! Since we remove NULLs before sorting, shouldn't need to check here (and I want to know if i'm wrong) 00378 * @return (a->next<b->next) */ 00379 bool operator()(const TimerEntry* const a, const TimerEntry* const b) const { return (a->next<b->next); } 00380 }; 00381 typedef std::vector<TimerEntry*>::iterator timer_it_t; //!< makes code more readable 00382 std::vector<TimerEntry*> timers; //!< the list of timer entries being maintained, kept sorted by time they go active 00383 00384 //! just for debugging 00385 void chkTimers() { 00386 unsigned int last=0; 00387 for(timer_it_t it=timers.begin(); it!=timers.end(); it++) { 00388 if(last>(*it)->next) { 00389 dispTimers(); 00390 return; 00391 } 00392 last=(*it)->next; 00393 } 00394 } 00395 //! just for debugging 00396 void dispTimers() { 00397 std::cout << "out of order timers " << get_time() << " :\t"; 00398 unsigned int last=0; 00399 for(timer_it_t it=timers.begin(); it!=timers.end(); it++) { 00400 if(last>(*it)->next) 00401 std::cout << "##"; 00402 std::cout << (last=(*it)->next) << '\t'; 00403 } 00404 std::cout << std::endl; 00405 } 00406 00407 //! Does the actual storage of the mapping between EventBase's and the EventListeners/EventTrappers who should receive them 00408 /*! Actually only stores void*'s, so it's more general than just Listeners or Trappers */ 00409 class EventMapper { 00410 public: 00411 //! constructor 00412 EventMapper(); 00413 00414 void addMapping(void* el, EventBase::EventGeneratorID_t egid) { allevents[egid].push_back(el); } //!< Adds a listener for all events from a given event generator 00415 void addMapping(void* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); //!< Adds a listener for a specific source id and type from a given event generator 00416 00417 //! Removes a listener for all events from a given event generator, returns true if something was actually removed 00418 /*! Doesn't necessarily remove the vector or mapping if this was the last listener, use clean() to do that */ 00419 bool removeMapping(void* el, EventBase::EventGeneratorID_t egid); 00420 00421 //! Removes a listener for a specific source id and type from a given event generator, returns true if something was actually removed 00422 /*! Doesn't necessarily remove the vector or mapping if this was the last listener, use clean() to do that */ 00423 bool removeMapping(void* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); 00424 00425 void clean(); //!<removes empty data structures for all event generators 00426 void clean(EventBase::EventGeneratorID_t egid); //!< removes empty data structures associated with a single event generator 00427 void clear(); //!<Resets the mapping 00428 00429 //@{ 00430 //! so stuff can tell if it even needs to bother generating an event... 00431 /*! ... if a tree falls in a forest, and there's no one around to see it, does it make a sound?\n 00432 ... if Vision sees a ball in an image, and there's no listeners, does it make an event? ;) \n 00433 @return true if it has any listeners, false otherwise */ 00434 bool hasMapping(EventBase::EventGeneratorID_t egid) const; 00435 bool hasMapping(EventBase::EventGeneratorID_t egid, size_t sid) const; 00436 bool hasMapping(EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) const; 00437 //@} 00438 00439 //! builds a list of all listeners which should receive the event, templated to typecast the pointers for you 00440 /*! @param e the key event 00441 * @param listeners upon return, the resulting list of listeners @a e maps to\n 00442 * @a listeners is not cleared prior to building, new listeners are pushed on end\n 00443 * Results are in the order: all specific matches first, all generator listeners second, in order they were added to the EventMapper.*/ 00444 template<class T> 00445 void getMapping(const EventBase& e, std::vector<T*>& listeners) const; 00446 00447 //! Used to make sure that the specified listener exists for the given event 00448 /*! This is needed because after we call processEvent on a lister, we can't assume 00449 * that no other listeners have been modified - one listener could cause another 00450 * to turn off. If that has happened, we shouldn't send the event, even if it 00451 * was in the queue originally. */ 00452 bool verifyMapping(void * listener, const EventBase& e) const { return verifyMapping(listener,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00453 //! Used to make sure that the specified listener exists for the given event 00454 /*! This is needed because after we call processEvent on a lister, we can't assume 00455 * that no other listeners have been modified - one listener could cause another 00456 * to turn off. If that has happened, we shouldn't send the event, even if it 00457 * was in the queue originally. */ 00458 bool verifyMapping(void * listener, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) const; 00459 00460 //! Needed to complete EventRouter::isListening suite 00461 /*! Only checks #allevents */ 00462 bool verifyMappingAll(void * listener, EventBase::EventGeneratorID_t egid) const; 00463 //! Needed to complete EventRouter::isListening suite 00464 /*! Checks both #allevents and #filteredevents */ 00465 bool verifyMappingAny(void * listener, EventBase::EventGeneratorID_t egid) const; 00466 00467 //! Needed to complete EventRouter::isListening suite 00468 /*! Checks both #allevents and #filteredevents, must be found in all */ 00469 bool verifyMappingAll(void * listener, EventBase::EventGeneratorID_t egid, size_t sid) const; 00470 //! Needed to complete EventRouter::isListening suite 00471 /*! Checks both #allevents and #filteredevents, can be found in either */ 00472 bool verifyMappingAny(void * listener, EventBase::EventGeneratorID_t egid, size_t sid) const; 00473 00474 protected: 00475 //! a mapping from source IDs (size_t's), each to a vector of pointers to listeners 00476 /*! main use in filteredevents @see filteredevents */ 00477 typedef std::map<size_t,std::vector<void*>,std::less<size_t> > SIDtoListenerVectorMap_t; 00478 00479 //! an array of vectors of pointers to listeners... in other words, a vector of listener pointers for each generator 00480 std::vector<void*> allevents[EventBase::numEGIDs]; 00481 //! not for the faint of heart: a matrix of mappings to vectors of pointers to listeners 00482 SIDtoListenerVectorMap_t* filteredevents[EventBase::numEGIDs][EventBase::numETIDs]; 00483 00484 private: 00485 EventMapper(const EventMapper&); //!< this shouldn't be called... 00486 EventMapper& operator=(const EventMapper&); //!< this shouldn't be called... 00487 }; 00488 00489 EventMapper trappers; //!< A mapping of which EventTrapper's should get a chance to trap the event 00490 EventMapper listeners; //!< A mapping of which EventListener's should receive events 00491 00492 //! contains information regarding the progress of posting an event 00493 /*! This allows us to resume and complete the posting of the "current" event before processing a new incoming event */ 00494 class PostingStatus { 00495 public: 00496 //! constructor 00497 PostingStatus(const EventMapper& eventTrappers, const EventMapper& eventListeners, const EventBase& event) 00498 : trappers(eventTrappers), listeners(eventListeners), t(), tit(), l(), lit(), e(event) 00499 { trappers.getMapping(e,t); tit=t.begin(); listeners.getMapping(e,l); lit=l.begin(); } 00500 //! begins or resumes sending the event #e to trappers and listeners in #t and #l 00501 void process(); 00502 protected: 00503 const EventMapper& trappers; //!< the current trapper mapping, used to verify each entry in #t is still valid before processing it 00504 const EventMapper& listeners; //!< the current listener mapping, used to verify each entry in #l is still valid before processing it 00505 std::vector<EventTrapper*> t; //!< list of trappers which were subscribed when the PostingStatus instance was constructed 00506 std::vector<EventTrapper*>::const_iterator tit; //!< current position within #t 00507 std::vector<EventListener*> l; //!< list of listeners which were subscribed when the PostingStatus instance was constructed 00508 std::vector<EventListener*>::const_iterator lit; //!< current position within #l 00509 const EventBase& e; //!< the event being processed 00510 }; 00511 std::queue<PostingStatus*> postings; //!< stores calls to post() currently in progress -- may grow if one postEvent() triggers another; this allows us to finish processing of the original postEvent() before starting the second. 00512 00513 //! This table will be checked on each processEvent to forward the event to some other destination 00514 /*! The main reason for including this functionality is in the uni-process model, we don't want 00515 * event postings from real time processes like Motion to block on the event queue processing. 00516 * So with this mechanism we can intercept those events, and queue them in a separate IPC 00517 * mechanism to be picked up by Main later on. 00518 * 00519 * This might also be handy for other purposes, such as remote event forwarding over the network... 00520 * 00521 * If the EventTranslator's trapEvent returns true, then further processing on the event is skipped. 00522 * (see EventTranslator::setTrapEventValue() )*/ 00523 EventTranslator* forwards[ProcessID::NumProcesses]; 00524 private: 00525 EventRouter(const EventRouter&); //!< don't call this 00526 EventRouter& operator=(const EventRouter&); //!< don't call this 00527 00528 }; 00529 00530 //! a global router for cross communication, probably the most common usage, although perhaps there may be times you'd rather have multiple event routers for smaller sections 00531 extern EventRouter * erouter; 00532 00533 /*! @file 00534 * @brief Describes EventRouter class, for distribution and trapping of events to listeners 00535 * @author ejt (Creator) 00536 * 00537 * $Author: ejt $ 00538 * $Name: tekkotsu-4_0 $ 00539 * $Revision: 1.42 $ 00540 * $State: Exp $ 00541 * $Date: 2007/11/13 04:16:02 $ 00542 */ 00543 00544 #endif |
Tekkotsu v4.0 |
Generated Thu Nov 22 00:54:53 2007 by Doxygen 1.5.4 |