1 /********************************************************************* 2 * 3 * AUTHORIZATION TO USE AND DISTRIBUTE 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: 7 * 8 * (1) source code distributions retain this paragraph in its entirety, 9 * 10 * (2) distributions including binary code include this paragraph in 11 * its entirety in the documentation or other materials provided 12 * with the distribution, and 13 * 14 * (3) all advertising materials mentioning features or use of this 15 * software display the following acknowledgment: 16 * 17 * "This product includes software written and developed 18 * by Brian Adamson, Justin Dean, and Joe Macker of the Naval 19 * Research Laboratory (NRL)." 20 * 21 * The name of NRL, the name(s) of NRL employee(s), or any entity 22 * of the United States Government may not be used to endorse or 23 * promote products derived from this software, nor does the 24 * inclusion of the NRL written and developed software directly or 25 * indirectly suggest NRL or United States Government endorsement 26 * of this product. 27 * 28 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 29 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 31 ********************************************************************/ 32 33 34 #ifndef _PROTO_TIMER 35 #define _PROTO_TIMER 36 37 #include "protoDebug.h" 38 #include "protoDefs.h" // for ProtoSystemTime() 39 #include "protoTime.h" 40 #include <math.h> 41 42 /** 43 * @class ProtoTimer 44 * 45 * @brief This is a generic timer class which will notify a ProtoTimer::Listener upon timeout. 46 * 47 * A list of ProtoTimers is managed by the ProtoTimerMgr class after they are "activated". 48 * The ProtoDispatcher's "main loop" calls ProtoTimerMgr::OnSystemTimeout at regular intervals 49 * to determine if any timer objects have timed out. If so, the callback function 50 * associated with the ProtoTimer::Listener is invoked. 51 * 52 */ 53 class ProtoTimer 54 { 55 friend class ProtoTimerMgr; 56 57 public: 58 ProtoTimer(); 59 ~ProtoTimer(); 60 61 /** 62 * This function will define which method will be called upon a timer timing out 63 * 64 * TODO: Update text with new timer functionality 65 * 66 * Special notice should be taken of the boolean return value of this function. 67 * When returning true the number of repeats will be decremented and if below 0 68 * will deactivate the timer. If in this function you are setting/changing intervals 69 * or repetions of the timer which invoked the call, the function should return false 70 * to avoid standard exit actions. 71 72 * NOTE: For VC++ Debug builds, you _cannot_ use pre-compiled 73 * headers with this template code. Also, "/ZI" or "/Z7" compile options 74 * must NOT be specified. (or else VC++ experiences an "internal compiler error") 75 * 76 * @param theListener a pointer to the "listening" object 77 * @param timeoutHandler a pointer to the listener's callback function. 78 * 79 */ 80 81 template <class listenerType> SetListener(listenerType * theListener,bool (listenerType::* timeoutHandler)(ProtoTimer &))82 bool SetListener(listenerType* theListener, bool(listenerType::*timeoutHandler)(ProtoTimer&)) 83 { 84 if (listener) delete listener; 85 listener = theListener ? new LISTENER_TYPE<listenerType>(theListener, timeoutHandler) : NULL; 86 return theListener ? (NULL != theListener) : true; 87 } 88 89 /** 90 * This method sets the interval (in seconds) after which the 91 * timer will "fire" (i.e., the method specified by 92 * ProtoTimer::SetListener() is invoked). 93 * 94 * @param theInterval timer interval in seconds 95 */ SetInterval(double theInterval)96 void SetInterval(double theInterval) 97 {interval = (theInterval < 0.0) ? 0.0 : theInterval;} GetInterval()98 double GetInterval() const {return interval;} 99 /** 100 * Timer repetition (0 = one shot, -1 = infinite repetition) 101 * 102 * @param numRepeat number of timer repetitions 103 */ SetRepeat(int numRepeat)104 void SetRepeat(int numRepeat) 105 {repeat = numRepeat;} GetRepeat()106 int GetRepeat() const 107 {return repeat;} 108 109 110 /// Provided for "advanced" timer monitoring/control ResetRepeat()111 void ResetRepeat() 112 {repeat_count = repeat;} 113 /// Provided for "advanced" timer monitoring/control 114 DecrementRepeatCount()115 void DecrementRepeatCount() 116 { if (repeat_count > 0) repeat_count--; } 117 /// Provided for "advanced" timer monitoring/control 118 GetRepeatCount()119 int GetRepeatCount() {return repeat_count;} 120 /// Provided for "advanced" timer monitoring/control 121 122 /// This must be used with wisdom! SetRepeatCount(int repeatCount)123 void SetRepeatCount(int repeatCount) 124 {repeat_count = repeatCount;} 125 126 //double GetTimeout() {return timeout;} 127 128 // Activity status/control 129 /** 130 * Returns true if timer is associated with a ProtoTimerMgr 131 */ IsActive()132 bool IsActive() const {return (NULL != mgr);} 133 double GetTimeRemaining() const; Reset()134 void Reset() 135 { 136 ResetRepeat(); 137 if (IsActive()) Reschedule(); 138 } 139 bool Reschedule(); 140 void Scale(double factor); 141 void Deactivate(); 142 143 // Ancillary SetUserData(const void * userData)144 void SetUserData(const void* userData) {user_data = userData;} GetUserData()145 const void* GetUserData() {return user_data;} 146 147 /** 148 * Installer commands 149 */ 150 enum Command {INSTALL, MODIFY, REMOVE}; 151 152 private: 153 /** 154 * Invokes the "listener's" callback function. 155 * 156 * TODO: Update with new timer functionality. 157 * 158 * @retval Returns the result of the listener's callback function if 159 * a listener exists for the timer. 160 */ DoTimeout()161 bool DoTimeout() {return listener ? listener->on_timeout(*this) : true;} 162 /** 163 * @class Listener 164 * 165 * @brief Listener base class 166 */ 167 class Listener 168 { 169 public: 170 /// virtual destructor ~Listener()171 virtual ~Listener() {} 172 /// virtual on_timeout function 173 virtual bool on_timeout(ProtoTimer& theTimer) = 0; 174 }; 175 /** 176 * @class LISTENER_TYPE 177 * 178 * @brief Template for Listener classes. 179 */ 180 template <class listenerType> 181 class LISTENER_TYPE : public Listener 182 { 183 public: 184 /** 185 * Listener constructor 186 * 187 * @param theListener pointer to the "listening" object 188 * @param timeoutHandler *pointer to the Listener's callback function. 189 */ LISTENER_TYPE(listenerType * theListener,bool (listenerType::* timeoutHandler)(ProtoTimer &))190 LISTENER_TYPE(listenerType* theListener, bool(listenerType::*timeoutHandler)(ProtoTimer&)) 191 : listener(theListener), timeout_handler(timeoutHandler) {} 192 /** 193 * @retval Returns the result of the Listeners timeout handler. 194 */ on_timeout(ProtoTimer & theTimer)195 bool on_timeout(ProtoTimer& theTimer) 196 {return (listener->*timeout_handler)(theTimer);} 197 /** 198 * Duplicates the Listener member and returns a pointer to the new 199 * object. 200 */ duplicate()201 Listener* duplicate() 202 {return (static_cast<Listener*>(new LISTENER_TYPE<listenerType>(listener, timeout_handler)));} 203 private: 204 listenerType* listener; 205 bool (listenerType::*timeout_handler)(ProtoTimer&); 206 }; 207 Listener* listener; 208 209 double interval; 210 int repeat; 211 int repeat_count; 212 213 const void* user_data; 214 ProtoTime timeout; 215 bool is_precise; 216 class ProtoTimerMgr* mgr; 217 ProtoTimer* prev; 218 ProtoTimer* next; 219 }; // end class ProtoTimer 220 221 /** 222 * @class ProtoTimerMgr 223 * 224 * @brief This class manages ProtoTimer instances when they are "activated". 225 * The ProtoDispatcher(see below) derives from this to manage ProtoTimers 226 * for an application. (The ProtoSimAgent base class contains a ProtoTimerMgr 227 * to similarly manage timers for a simulation instance). 228 */ 229 class ProtoTimerMgr 230 { 231 friend class ProtoTimer; 232 233 public: 234 /// Default constructor 235 ProtoTimerMgr(); 236 /// Default destructor 237 virtual ~ProtoTimerMgr(); 238 239 // ProtoTimer activation/deactivation 240 virtual void ActivateTimer(ProtoTimer& theTimer); 241 virtual void DeactivateTimer(ProtoTimer& theTimer); 242 243 /** 244 * @retval Returns any time remaining for the active short timer or -1 245 */ GetTimeRemaining()246 double GetTimeRemaining() const 247 {return (short_head ? short_head->GetTimeRemaining() : -1.0);} 248 249 /// Call this when the timer mgr's one-shot system timer fires 250 void OnSystemTimeout(); 251 252 /// Special call to allow early dispatch of timeouts DoSystemTimeout()253 void DoSystemTimeout() 254 { 255 bool updateStatus = update_pending; 256 update_pending = true; 257 OnSystemTimeout(); 258 update_pending = updateStatus; 259 } 260 261 virtual void GetSystemTime(struct timeval& currentTime); 262 263 protected: 264 /// System timer association/management definitions and routines 265 virtual bool UpdateSystemTimer(ProtoTimer::Command command, 266 double delay) = 0;// {return true;} 267 268 private: 269 // Methods used internally 270 void ReactivateTimer(ProtoTimer& theTimer, const ProtoTime& now); 271 void InsertLongTimer(ProtoTimer& theTimer); 272 bool InsertLongTimerReverse(ProtoTimer& theTimer); 273 void RemoveLongTimer(ProtoTimer& theTimer); 274 void InsertShortTimer(ProtoTimer& theTimer); 275 bool InsertShortTimerReverse(ProtoTimer& theTimer); 276 void RemoveShortTimer(ProtoTimer& theTimer); 277 void Update(); 278 GetNextTimeout(ProtoTime & nextTimeout)279 bool GetNextTimeout(ProtoTime& nextTimeout) const 280 { 281 if (NULL != short_head) 282 { 283 nextTimeout = short_head->timeout; 284 return true; 285 } 286 else 287 { 288 return false; 289 } 290 } GetPulseTime(ProtoTime & pulseTime)291 void GetPulseTime(ProtoTime& pulseTime) const 292 { 293 pulseTime = pulse_mark; 294 pulseTime += (1.0 - pulse_timer.GetTimeRemaining()); 295 } 296 bool OnPulseTimeout(ProtoTimer& theTimer); 297 298 static const double PRECISION_TIME_THRESHOLD; 299 300 GetCurrentSystemTime(struct timeval & currentTime)301 void GetCurrentSystemTime(struct timeval& currentTime) 302 { 303 #if (defined(SIMULATE) && defined(NS2)) 304 GetSystemTime(currentTime); 305 #else 306 ProtoSystemTime(currentTime); 307 #endif // if/else (SIMULATE && NS2) 308 } 309 310 // We need this to support some of our SIM code so it can 311 // find its simulation context GetCurrentProtoTime(ProtoTime & currentTime)312 void GetCurrentProtoTime(ProtoTime& currentTime) 313 { 314 #if (defined(SIMULATE) && defined(NS2)) 315 GetSystemTime(currentTime.AccessTimeVal()); 316 #else 317 currentTime.GetCurrentTime(); 318 #endif // if/else (SIMULATE && NS2) 319 } 320 321 322 // Member variables 323 bool update_pending; 324 bool timeout_scheduled; 325 ProtoTime scheduled_timeout; 326 ProtoTimer pulse_timer; // one second pulse timer 327 ProtoTime pulse_mark; 328 ProtoTimer* long_head; 329 ProtoTimer* long_tail; 330 ProtoTimer* short_head; 331 ProtoTimer* short_tail; 332 }; // end class ProtoTimerMgr 333 334 #endif // _PROTO_TIMER 335