| 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 //! deprecated -- pass by reference instead; this version posts the specified event and then deletes it after processing is complete 00192 /*! moving to pass by reference instead of pass by pointer to avoid questions about who deletes the event and the event's scope, 00193 * also keeping the event on the stack is faster by avoiding unnecessary heap operations. */ 00194 void postEvent(EventBase* e) ATTR_deprecated; 00195 //! posts the specified event, but doesn't delete it at the end -- equivalent to processEvent(e) 00196 void postEvent(const EventBase& e) { processEvent(e); } 00197 00198 #ifndef PLATFORM_APERIOS 00199 //! Uses a ThreadedMessageQueue to process an event at a later time, as opposed to postEvent() which will process the event immediately. 00200 /*! If an event generator is running in a background thread (e.g. DeviceDriver or a behavior thread), it can use this function to 00201 * post events instead of grabbing the behaviorLock and calling postEvent directly. However, beware building up a backlog 00202 * of stale events, you may prefer requeueEvent() to ensure only the most up-to-date data is in the queue 00203 * The event will be processed after all current event processing is completed, similar to a 0-ms timer subscription. 00204 * The event will be deleted after processing.*/ 00205 void queueEvent(EventBase* e); 00206 00207 //! Places @a e in the same queue as queueEvent(), but removes any other events with the same generator and source first. 00208 /*! For sources only the current value is of significant interest (e.g. sensor readings) this avoids 00209 * the possibility of a backlog of stale data forming in the case the Main thread blocks and falls 00210 * behind on processing incoming data */ 00211 void requeueEvent(EventBase* e); 00212 #endif 00213 00214 //! determines if timers need to be posted, and posts them if so. 00215 /*! Call this often to ensure accurate timers. */ 00216 void processTimers(); 00217 //! sends event to its trappers & listeners, but doesn't delete the event at the end (see also postEvent()) 00218 /*! this posting method is supplied to allow an EventRouter to behave as a listener as 00219 * well -- the 'routers' really can form a sort of network, if desired. postEvent() is 00220 * probably a more memnomic interface to use in direct function calls however, 00221 * so that is the one you should call. */ 00222 void processEvent(const EventBase& e); 00223 00224 //! returns the forwarding agent for a given process/thread group (see #forwards) 00225 EventTranslator* getForwardingAgent(ProcessID::ProcessID_t proc) const { return forwards[proc]; } 00226 //! sets the forwarding agent for a given process/thread group (see #forwards) 00227 void setForwardingAgent(ProcessID::ProcessID_t proc, EventTranslator* trans); 00228 00229 #ifndef PLATFORM_APERIOS 00230 //! Returns the event queue, to be processed by a callback thread between other behavior processing 00231 /*! This is similar to the forwarding agents which handles inter-process events (e.g. from Motion to Main) 00232 * but in threaded environments (e.g. non-AIBO) we can use this more efficient mechanism. As we drop 00233 * AIBO support we can transfer #forwards to use queueEvent() instead. 00234 * 00235 * To allow future expansion, please use queueEvent() instead of calling 00236 * ThreadedMessageQueue::send directly via this accessor. */ 00237 ThreadedMessageQueue<EventBase*>& getEventQueue() { return *eventQueue; } 00238 #endif 00239 //@} 00240 00241 00242 //!@name Listener/Trapper Recall 00243 00244 //! returns true if the specified listener/trapper would receive any events that match the specified criteria 00245 bool isListeningAny(const EventListener* el, EventBase::EventGeneratorID_t egid) const { return listeners.verifyMappingAny(el,egid); } 00246 bool isListeningAny(const EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid) const { return listeners.verifyMappingAny(el,egid,sid); } 00247 bool isListeningAll(const EventListener* el, EventBase::EventGeneratorID_t egid) const { return listeners.verifyMappingAll(el,egid); } 00248 bool isListeningAll(const EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid) const { return listeners.verifyMappingAll(el,egid,sid); } 00249 bool isListening(const EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) const { return listeners.verifyMapping(el,egid,sid,etid); } 00250 bool isListening(const EventListener* el, const EventBase& e) const { return listeners.verifyMapping(el,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00251 bool isTrappingAny(const EventTrapper* el, EventBase::EventGeneratorID_t egid) const { return trappers.verifyMappingAny(el,egid); } 00252 bool isTrappingAny(const EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid) const { return trappers.verifyMappingAny(el,egid,sid); } 00253 bool isTrappingAll(const EventTrapper* el, EventBase::EventGeneratorID_t egid) const { return trappers.verifyMappingAll(el,egid); } 00254 bool isTrappingAll(const EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid) const { return trappers.verifyMappingAll(el,egid,sid); } 00255 bool isTrapping(const EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) const { return trappers.verifyMapping(el,egid,sid,etid); } 00256 bool isTrapping(const EventTrapper* el, const EventBase& e) const { return trappers.verifyMapping(el,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00257 //@} 00258 00259 00260 //!@name Listener/Trapper Detection 00261 00262 /*!@brief <b>counts both listeners and trappers</b>, so generators can tell if it even needs to bother generating an event...*/ 00263 /* Generators can also subscribe to the EventBase::erouterEGID event stream if 00264 * they wish to be notified when they gain or lose listeners (particularly the 00265 * first or last).\n 00266 * ... if a tree falls in a forest, and there's no one around to see it, does 00267 * it make a sound?\n 00268 * ... if Vision sees a ball in an image, and there's no listeners, does it 00269 * make an event? ;) */ 00270 bool hasListeners(EventBase::EventGeneratorID_t egid) { return trappers.hasMapping(egid) || listeners.hasMapping(egid); } 00271 bool hasListeners(EventBase::EventGeneratorID_t egid, size_t sid) { return trappers.hasMapping(egid,sid) || listeners.hasMapping(egid,sid); } 00272 bool hasListeners(EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) { return trappers.hasMapping(egid,sid,etid) || listeners.hasMapping(egid,sid,etid); } 00273 bool hasListeners(const EventBase& e) { return hasListeners(e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00274 //@} 00275 00276 00277 //!@name Timer Management 00278 00279 //! adds a timer if it doesn't exist, or resets the timer if it already exists. 00280 void addTimer(EventListener* el, size_t sid, unsigned int delay, bool repeat=true); 00281 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 00282 00283 //! clears all pending timers for listener @a el; see remove() 00284 void removeTimer(const EventListener* el); 00285 void removeTimer(const EventListener* el, size_t sid); //!< clears any pending timers with source id @a sid for listener @a el 00286 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 00287 void removeAllTimers(); //!< clears all timers for all listeners 00288 00289 unsigned int getNextTimer() { return (timers.size()==0 ? -1U : timers.front()->next); } //!< returns time of next timer activation 00290 00291 struct TimerEntry; 00292 //! Returns information of next timer activation (regardless of sid) for an event listener, NULL if none 00293 /*! Don't try to use this to edit the timer entry, just call addTimer() again to reset the fields */ 00294 const TimerEntry* getNextTimerInfo(const EventListener* el); 00295 //! Returns information of next activation for a specific event listener timer entry, NULL if none 00296 /*! Don't try to use this to edit the timer entry, just call addTimer() again to reset the fields */ 00297 const TimerEntry* getNextTimerInfo(const EventListener* el, size_t sid); 00298 //@} 00299 00300 00301 //!@name Listener Management 00302 00303 //! Adds a listener for all events from a given event generator 00304 void addListener(EventListener* el, EventBase::EventGeneratorID_t egid); 00305 void addListener(EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< Adds a listener for all types from a specific source and generator 00306 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 00307 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 00308 00309 #ifndef TGT_IS_DYNAMIC 00310 //!@name Remote Event/State code 00311 00312 //! Request remote events to be sent to this robot, works like the regular addListeners 00313 void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid); 00314 void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid); 00315 void addRemoteListener(EventListener* el, int host, const EventBase& e); 00316 void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); 00317 00318 //! Stop getting remote events from the given robot 00319 void removeRemoteListener(const EventListener* el, int host, EventBase::EventGeneratorID_t egid); 00320 void removeRemoteListener(const EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid); 00321 void removeRemoteListener(const EventListener* el, int host, const EventBase& e); 00322 void removeRemoteListener(const EventListener* el, int host, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); 00323 00324 //! Request remote state updates from the remote robot, every interval ms 00325 void requestRemoteStateUpdates(int host, RemoteState::StateType type, unsigned int interval = 500); 00326 00327 //! Stop getting remote state updates 00328 void stopRemoteStateUpdates(int host, RemoteState::StateType type); 00329 00330 //! This is called once on startup; it tells the EventRouter to listen for incoming requests 00331 bool serveRemoteEventRequests(); 00332 00333 //! This handles incomiung connection requests by starting a new EventProxy 00334 int processData(char *data, int bytes); 00335 00336 static const int defaultPort = 2424; 00337 00338 protected: 00339 00340 RemoteRouter &remoteRouterForHost(int host); 00341 00342 std::list<EventProxy *> proxies; 00343 00344 std::map<int, RemoteRouter *> rrouters; 00345 Socket *sck; 00346 int nextProxyPort; 00347 #endif 00348 00349 //@} 00350 public: 00351 00352 00353 //! stops sending ALL events to the listener -- does not remove pending timers however (may need to call removeTimer(el) as well); see remove() 00354 void removeListener(const EventListener* el); 00355 //! stops sending specified events from the generator to the listener. 00356 void removeListener(const EventListener* el, EventBase::EventGeneratorID_t egid); 00357 void removeListener(const EventListener* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< stops sending specified events from the generator to the listener. 00358 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. 00359 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 00360 00361 //! stops all events and timers, shorthand for removeListener(el) and removeTimer(el); Note that trappers are separate, removeTrapper() is @e not called 00362 void remove(const EventListener* el) { removeListener(el); removeTimer(el); } 00363 00364 //@} 00365 00366 00367 //!@name Trapper Management 00368 00369 //! Adds a trapper for a specific source id and type from a given event generator 00370 /*! Note that only the broadcasted timers can be trapped. The EventListener which requested the timer will receive that timer before any trapping is done. */ 00371 void addTrapper(EventTrapper* el, const EventBase& e); 00372 void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid); //!< Adds a trapper for all events from a given event generator 00373 void addTrapper(EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< Adds a trapper for all types from a specific source and generator 00374 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 00375 00376 void addTrapper(EventTrapper* el); //!< adds a trapper for ALL events 00377 00378 //! stops sending specified events from the generator to the trapper. 00379 void removeTrapper(const EventTrapper* el, const EventBase& e); 00380 void removeTrapper(const EventTrapper* el, EventBase::EventGeneratorID_t egid); //!< stops sending specified events from the generator to the trapper. 00381 void removeTrapper(const EventTrapper* el, EventBase::EventGeneratorID_t egid, size_t sid); //!< stops sending specified events from the generator to the trapper. 00382 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. 00383 00384 void removeTrapper(const EventTrapper* el); //!< stops sending ALL events to the trapper 00385 //@} 00386 00387 //! Contains all the information needed to maintain a timer by the EventRouter 00388 struct TimerEntry { 00389 //! constructs an entry using the given value for next - useful for with TimerEntryPtrCmp 00390 explicit TimerEntry(unsigned int nxt) : el(NULL), sid(0), delay(0), next(nxt), repeat(false) {} 00391 //! constructs with the given values, sets next field automatically; see next 00392 TimerEntry(EventListener* e, size_t s, unsigned int d, bool r) : el(e), sid(s), delay(d), next(get_time()+delay), repeat(r) {} 00393 //! just does the default, i'm just being explicit since there's a pointer (no deep copy!) 00394 TimerEntry(const TimerEntry& t) : el(t.el), sid(t.sid), delay(t.delay), next(t.next), repeat(t.repeat) {} 00395 //! just does the default, i'm just being explicit since there's a pointer (no deep copy!) 00396 TimerEntry& operator=(const TimerEntry& t) { el=t.el; sid=t.sid; delay=t.delay; next=t.next; repeat=t.repeat; return *this; } 00397 //! will reset timer 00398 /*! @param d the time from now when the timer should go off (in milliseconds) 00399 * @param r true if the timer should automatically repeat */ 00400 void Set(unsigned int d, bool r) { delay=d; repeat=r; next=get_time()+delay; } 00401 EventListener* el; //!< the listener to fire at 00402 size_t sid; //!< the source id to fire with 00403 unsigned int delay; //!< the delay until firing 00404 unsigned int next; //!< the time at which this timer will go off next 00405 bool repeat; //!< if true, will reset after firing, else will be deleted 00406 }; 00407 00408 protected: 00409 /*! @brief Used by STL to sort the timer list in order of activation time 00410 * @see EventRouter::timers */ 00411 class TimerEntryPtrCmp { 00412 public: 00413 //! Used by STL to sort the timer list in order of activation time; see timers 00414 /*! Since we remove NULLs before sorting, shouldn't need to check here (and I want to know if i'm wrong) 00415 * @return (a->next<b->next) */ 00416 bool operator()(const TimerEntry* const a, const TimerEntry* const b) const { return (a->next<b->next); } 00417 }; 00418 typedef std::vector<TimerEntry*>::iterator timer_it_t; //!< makes code more readable 00419 std::vector<TimerEntry*> timers; //!< the list of timer entries being maintained, kept sorted by time they go active 00420 00421 //! just for debugging 00422 void chkTimers() { 00423 unsigned int last=0; 00424 for(timer_it_t it=timers.begin(); it!=timers.end(); it++) { 00425 if(last>(*it)->next) { 00426 dispTimers(); 00427 return; 00428 } 00429 last=(*it)->next; 00430 } 00431 } 00432 //! just for debugging 00433 void dispTimers() { 00434 std::cout << "out of order timers " << get_time() << " :\t"; 00435 unsigned int last=0; 00436 for(timer_it_t it=timers.begin(); it!=timers.end(); it++) { 00437 if(last>(*it)->next) 00438 std::cout << "##"; 00439 std::cout << (last=(*it)->next) << '\t'; 00440 } 00441 std::cout << std::endl; 00442 } 00443 00444 //! Does the actual storage of the mapping between EventBase's and the EventListeners/EventTrappers who should receive them 00445 /*! Actually only stores void*'s, so it's more general than just Listeners or Trappers */ 00446 class EventMapper { 00447 public: 00448 //! constructor 00449 EventMapper(); 00450 00451 void addMapping(void* el, EventBase::EventGeneratorID_t egid) { allevents[egid].push_back(el); } //!< Adds a listener for all events from a given event generator 00452 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 00453 00454 //! Removes a listener for all events from a given event generator, returns true if something was actually removed 00455 /*! Doesn't necessarily remove the vector or mapping if this was the last listener, use clean() to do that */ 00456 bool removeMapping(const void* el, EventBase::EventGeneratorID_t egid); 00457 00458 //! Removes a listener for a specific source id and type from a given event generator, returns true if something was actually removed 00459 /*! Doesn't necessarily remove the vector or mapping if this was the last listener, use clean() to do that */ 00460 bool removeMapping(const void* el, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid); 00461 00462 void clean(); //!<removes empty data structures for all event generators 00463 void clean(EventBase::EventGeneratorID_t egid); //!< removes empty data structures associated with a single event generator 00464 void clear(); //!<Resets the mapping 00465 00466 //@{ 00467 //! so stuff can tell if it even needs to bother generating an event... 00468 /*! ... if a tree falls in a forest, and there's no one around to see it, does it make a sound?\n 00469 ... if Vision sees a ball in an image, and there's no listeners, does it make an event? ;) \n 00470 @return true if it has any listeners, false otherwise */ 00471 bool hasMapping(EventBase::EventGeneratorID_t egid) const; 00472 bool hasMapping(EventBase::EventGeneratorID_t egid, size_t sid) const; 00473 bool hasMapping(EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) const; 00474 //@} 00475 00476 //! builds a list of all listeners which should receive the event, templated to typecast the pointers for you 00477 /*! @param e the key event 00478 * @param listeners upon return, the resulting list of listeners @a e maps to\n 00479 * @a listeners is not cleared prior to building, new listeners are pushed on end\n 00480 * Results are in the order: all specific matches first, all generator listeners second, in order they were added to the EventMapper.*/ 00481 template<class T> 00482 void getMapping(const EventBase& e, std::vector<T*>& listeners) const; 00483 00484 //! Used to make sure that the specified listener exists for the given event 00485 /*! This is needed because after we call processEvent on a lister, we can't assume 00486 * that no other listeners have been modified - one listener could cause another 00487 * to turn off. If that has happened, we shouldn't send the event, even if it 00488 * was in the queue originally. */ 00489 bool verifyMapping(const void * listener, const EventBase& e) const { return verifyMapping(listener,e.getGeneratorID(),e.getSourceID(),e.getTypeID()); } 00490 //! Used to make sure that the specified listener exists for the given event 00491 /*! This is needed because after we call processEvent on a lister, we can't assume 00492 * that no other listeners have been modified - one listener could cause another 00493 * to turn off. If that has happened, we shouldn't send the event, even if it 00494 * was in the queue originally. */ 00495 bool verifyMapping(const void * listener, EventBase::EventGeneratorID_t egid, size_t sid, EventBase::EventTypeID_t etid) const; 00496 00497 //! Needed to complete EventRouter::isListening suite 00498 /*! Only checks #allevents */ 00499 bool verifyMappingAll(const void * listener, EventBase::EventGeneratorID_t egid) const; 00500 //! Needed to complete EventRouter::isListening suite 00501 /*! Checks both #allevents and #filteredevents */ 00502 bool verifyMappingAny(const void * listener, EventBase::EventGeneratorID_t egid) const; 00503 00504 //! Needed to complete EventRouter::isListening suite 00505 /*! Checks both #allevents and #filteredevents, must be found in all */ 00506 bool verifyMappingAll(const void * listener, EventBase::EventGeneratorID_t egid, size_t sid) const; 00507 //! Needed to complete EventRouter::isListening suite 00508 /*! Checks both #allevents and #filteredevents, can be found in either */ 00509 bool verifyMappingAny(const void * listener, EventBase::EventGeneratorID_t egid, size_t sid) const; 00510 00511 protected: 00512 //! a mapping from source IDs (size_t's), each to a vector of pointers to listeners 00513 /*! main use in filteredevents @see filteredevents */ 00514 typedef std::map<size_t,std::vector<void*>,std::less<size_t> > SIDtoListenerVectorMap_t; 00515 00516 //! an array of vectors of pointers to listeners... in other words, a vector of listener pointers for each generator 00517 std::vector<void*> allevents[EventBase::numEGIDs]; 00518 //! not for the faint of heart: a matrix of mappings to vectors of pointers to listeners 00519 SIDtoListenerVectorMap_t* filteredevents[EventBase::numEGIDs][EventBase::numETIDs]; 00520 00521 private: 00522 EventMapper(const EventMapper&); //!< this shouldn't be called... 00523 EventMapper& operator=(const EventMapper&); //!< this shouldn't be called... 00524 }; 00525 00526 EventMapper trappers; //!< A mapping of which EventTrapper's should get a chance to trap the event 00527 EventMapper listeners; //!< A mapping of which EventListener's should receive events 00528 00529 //! contains information regarding the progress of posting an event 00530 /*! This allows us to resume and complete the posting of the "current" event before processing a new incoming event */ 00531 class PostingStatus { 00532 public: 00533 //! constructor 00534 PostingStatus(const EventMapper& eventTrappers, const EventMapper& eventListeners, const EventBase& event) 00535 : trappers(eventTrappers), listeners(eventListeners), t(), tit(), l(), lit(), e(event) 00536 { trappers.getMapping(e,t); tit=t.begin(); listeners.getMapping(e,l); lit=l.begin(); } 00537 //! begins or resumes sending the event #e to trappers and listeners in #t and #l 00538 void process(); 00539 protected: 00540 const EventMapper& trappers; //!< the current trapper mapping, used to verify each entry in #t is still valid before processing it 00541 const EventMapper& listeners; //!< the current listener mapping, used to verify each entry in #l is still valid before processing it 00542 std::vector<EventTrapper*> t; //!< list of trappers which were subscribed when the PostingStatus instance was constructed 00543 std::vector<EventTrapper*>::const_iterator tit; //!< current position within #t 00544 std::vector<EventListener*> l; //!< list of listeners which were subscribed when the PostingStatus instance was constructed 00545 std::vector<EventListener*>::const_iterator lit; //!< current position within #l 00546 const EventBase& e; //!< the event being processed 00547 }; 00548 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. 00549 00550 //! This table will be checked on each processEvent to forward the event to some other destination 00551 /*! The main reason for including this functionality is in the uni-process model, we don't want 00552 * event postings from real time processes like Motion to block on the event queue processing. 00553 * So with this mechanism we can intercept those events, and queue them in a separate IPC 00554 * mechanism to be picked up by Main later on. 00555 * 00556 * This might also be handy for other purposes, such as remote event forwarding over the network... 00557 * 00558 * If the EventTranslator's trapEvent returns true, then further processing on the event is skipped. 00559 * (see EventTranslator::setTrapEventValue() )*/ 00560 EventTranslator* forwards[ProcessID::NumProcesses]; 00561 00562 #ifndef PLATFORM_APERIOS 00563 //! A queue of events which have been posted from background threads or otherwise desire postponed processing 00564 /*! This is a more efficient mechanism than #forwards, but only available on threaded platforms (e.g. non-AIBO). 00565 * See queueEvent() and getEventQueue() */ 00566 ThreadedMessageQueue<EventBase*>* eventQueue; 00567 00568 //! Predicate used to remove old events from the same event source from #eventQueue (see requeueEvent()) 00569 struct SameID { 00570 const EventBase* e; 00571 explicit SameID(const EventBase* event) : e(event) {} 00572 bool operator()(const EventBase* x) { return e->getGeneratorID()==x->getGeneratorID() && e->getSourceID()==x->getSourceID(); } 00573 }; 00574 #endif 00575 00576 private: 00577 EventRouter(const EventRouter&); //!< don't call this 00578 EventRouter& operator=(const EventRouter&); //!< don't call this 00579 00580 }; 00581 00582 //! 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 00583 extern EventRouter * erouter; 00584 00585 /*! @file 00586 * @brief Describes EventRouter class, for distribution and trapping of events to listeners 00587 * @author ejt (Creator) 00588 */ 00589 00590 #endif |
|
Tekkotsu v5.1CVS |
Generated Fri Mar 16 05:26:37 2012 by Doxygen 1.6.3 |