Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

EventRouter.h

Go 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