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   //! 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