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

Tekkotsu v4.0
Generated Thu Nov 22 00:54:53 2007 by Doxygen 1.5.4