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