1 /* 2 * Copyright (c) 2016, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for the multiplexed timer service. 32 */ 33 34 #ifndef TIMER_HPP_ 35 #define TIMER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include <stddef.h> 40 #include <stdint.h> 41 42 #include <openthread/platform/alarm-micro.h> 43 #include <openthread/platform/alarm-milli.h> 44 45 #include "common/debug.hpp" 46 #include "common/linked_list.hpp" 47 #include "common/locator.hpp" 48 #include "common/non_copyable.hpp" 49 #include "common/tasklet.hpp" 50 #include "common/time.hpp" 51 52 namespace ot { 53 54 /** 55 * @addtogroup core-timer 56 * 57 * @brief 58 * This module includes definitions for the multiplexed timer service. 59 * 60 * @{ 61 */ 62 63 /** 64 * Represents an object tracking the next fire time along with the current time (now). 65 */ 66 class NextFireTime 67 { 68 public: 69 /** 70 * Initializes the `NextFireTime` with a given current time. 71 * 72 * @pram[in] aNow The current time. 73 */ 74 explicit NextFireTime(Time aNow); 75 76 /** 77 * Initializes the `NextFireTime` using `TimerMilli::GetNow()` for current time. 78 */ 79 NextFireTime(void); 80 81 /** 82 * Gets the current time (now) tracked by the `NextFireTime` object. 83 * 84 * @returns The current time. 85 */ GetNow(void) const86 Time GetNow(void) const { return mNow; } 87 88 /** 89 * Updates the tracked next fire time with a new given time only if it is earlier. 90 * 91 * If the given @p aTime is in the past relative to the tracked `GetNow()`, the `GetNow()` time is used instead. 92 * This ensures that the next fire time is never scheduled before the current time. 93 * 94 * @param[in] aTime The new time. 95 */ 96 void UpdateIfEarlier(Time aTime); 97 98 /** 99 * Updates the tracked next fire time with a new given time, but only if it is earlier than the current 100 * fire time and in the future relative to `GetNow()`. 101 * 102 * If the given @p aTime is not in the future relative to `GetNow()`, it is ignored. This is unlike 103 * `UpdateIfEarlier()`, which allows all `aTime` values, including ones that are in the past (where it uses 104 * `GetNow()`). 105 * 106 * This method can be used to track the next fire time among non-expired times, ensuring the tracked next fire time 107 * will be in the future relative to `GetNow()`. 108 * 109 * @param[in] aTime The new time. 110 */ 111 void UpdateIfEarlierAndInFuture(Time aTime); 112 113 /** 114 * Indicates whether or not next fire time is set. 115 * 116 * @retval TRUE The next fire time is set. 117 * @retval FALSE The next fire time is not set. 118 */ IsSet(void) const119 bool IsSet(void) const { return (mNextTime != mNow.GetDistantFuture()); } 120 121 /** 122 * Gets the next fire time. 123 * 124 * If the next fire time is not, `GetNow().GetDistantFuture()` will be returned. 125 * 126 * @returns The next fire time. 127 */ GetNextTime(void) const128 Time GetNextTime(void) const { return mNextTime; } 129 130 private: 131 Time mNow; 132 Time mNextTime; 133 }; 134 135 /** 136 * Implements a timer. 137 */ 138 class Timer : public InstanceLocator, public LinkedListEntry<Timer> 139 { 140 friend class LinkedListEntry<Timer>; 141 142 public: 143 /** 144 * This constant defines maximum delay allowed when starting a timer. 145 */ 146 static const uint32_t kMaxDelay = (Time::kMaxDuration >> 1); 147 148 /** 149 * Defines a function reference which is invoked when the timer expires. 150 * 151 * @param[in] aTimer A reference to the expired timer instance. 152 */ 153 typedef void (&Handler)(Timer &aTimer); 154 155 /** 156 * Returns the fire time of the timer. 157 * 158 * @returns The fire time. 159 */ GetFireTime(void) const160 Time GetFireTime(void) const { return mFireTime; } 161 162 /** 163 * Indicates whether or not the timer instance is running. 164 * 165 * @retval TRUE If the timer is running. 166 * @retval FALSE If the timer is not running. 167 */ IsRunning(void) const168 bool IsRunning(void) const { return (mNext != this); } 169 170 protected: 171 class Scheduler : public InstanceLocator, private NonCopyable 172 { 173 friend class Timer; 174 175 protected: 176 struct AlarmApi 177 { 178 void (*AlarmStartAt)(otInstance *aInstance, uint32_t aT0, uint32_t aDt); 179 void (*AlarmStop)(otInstance *aInstance); 180 uint32_t (*AlarmGetNow)(void); 181 }; 182 Scheduler(Instance & aInstance)183 explicit Scheduler(Instance &aInstance) 184 : InstanceLocator(aInstance) 185 { 186 } 187 188 void Add(Timer &aTimer, const AlarmApi &aAlarmApi); 189 void Remove(Timer &aTimer, const AlarmApi &aAlarmApi); 190 void RemoveAll(const AlarmApi &aAlarmApi); 191 void ProcessTimers(const AlarmApi &aAlarmApi); 192 void SetAlarm(const AlarmApi &aAlarmApi); 193 194 LinkedList<Timer> mTimerList; 195 }; 196 Timer(Instance & aInstance,Handler aHandler)197 Timer(Instance &aInstance, Handler aHandler) 198 : InstanceLocator(aInstance) 199 , mHandler(aHandler) 200 , mNext(this) 201 { 202 } 203 204 bool DoesFireBefore(const Timer &aSecondTimer, Time aNow) const; Fired(void)205 void Fired(void) { mHandler(*this); } 206 207 Handler mHandler; 208 Time mFireTime; 209 Timer *mNext; 210 }; 211 212 extern "C" void otPlatAlarmMilliFired(otInstance *aInstance); 213 214 /** 215 * Implements the millisecond timer. 216 */ 217 class TimerMilli : public Timer 218 { 219 public: 220 /** 221 * Implements the millisecond timer scheduler. 222 */ 223 class Scheduler : private Timer::Scheduler 224 { 225 friend class TimerMilli; 226 friend void otPlatAlarmMilliFired(otInstance *aInstance); 227 228 public: 229 /** 230 * Initializes the object. 231 * 232 * @param[in] aInstance A reference to the instance object. 233 */ Scheduler(Instance & aInstance)234 explicit Scheduler(Instance &aInstance) 235 : Timer::Scheduler(aInstance) 236 { 237 } 238 239 private: Add(TimerMilli & aTimer)240 void Add(TimerMilli &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMilliApi); } Remove(TimerMilli & aTimer)241 void Remove(TimerMilli &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMilliApi); } RemoveAll(void)242 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMilliApi); } ProcessTimers(void)243 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMilliApi); } 244 245 static const AlarmApi sAlarmMilliApi; 246 }; 247 248 /** 249 * Creates a millisecond timer instance. 250 * 251 * @param[in] aInstance A reference to the OpenThread instance. 252 * @param[in] aHandler A pointer to a function that is called when the timer expires. 253 */ TimerMilli(Instance & aInstance,Handler aHandler)254 TimerMilli(Instance &aInstance, Handler aHandler) 255 : Timer(aInstance, aHandler) 256 { 257 } 258 259 /** 260 * Schedules the timer to fire after a given delay (in milliseconds) from now. 261 * 262 * @param[in] aDelay The delay in milliseconds. It must not be longer than `kMaxDelay`. 263 */ 264 void Start(uint32_t aDelay); 265 266 /** 267 * Schedules the timer to fire after a given delay (in milliseconds) from a given start time. 268 * 269 * @param[in] aStartTime The start time. 270 * @param[in] aDelay The delay in milliseconds. It must not be longer than `kMaxDelay`. 271 */ 272 void StartAt(TimeMilli aStartTime, uint32_t aDelay); 273 274 /** 275 * Schedules the timer to fire at a given fire time. 276 * 277 * @param[in] aFireTime The fire time. 278 */ 279 void FireAt(TimeMilli aFireTime); 280 281 /** 282 * Schedules the timer to fire at a given fire time. 283 * 284 * Is @p aNextFireTime is not set, the timer is stopped. 285 * 286 * @param[in] aNextFireTime The fire time. 287 */ 288 void FireAt(const NextFireTime &aNextFireTime); 289 290 /** 291 * Re-schedules the timer with a given a fire time only if the timer is not running or the new given 292 * fire time is earlier than the current fire time. 293 * 294 * @param[in] aFireTime The fire time. 295 */ 296 void FireAtIfEarlier(TimeMilli aFireTime); 297 298 /** 299 * Re-schedules the timer with a given a fire time only if the timer is not running or the new given 300 * fire time is earlier than the current fire time. 301 * 302 * @param[in] aNextFireTime The fire time. 303 */ 304 void FireAtIfEarlier(const NextFireTime &aNextFireTime); 305 306 /** 307 * Stops the timer. 308 */ 309 void Stop(void); 310 311 /** 312 * Returns the current time in milliseconds. 313 * 314 * @returns The current time in milliseconds. 315 */ GetNow(void)316 static TimeMilli GetNow(void) { return TimeMilli(otPlatAlarmMilliGetNow()); } 317 318 protected: 319 static void RemoveAll(Instance &aInstance); 320 }; 321 322 /** 323 * Defines a timer owned by a specific type and using a method on owner type as the callback. 324 * 325 * @tparam Owner The type of the owner of this timer. 326 * @tparam HandleTimerPtr A pointer to a non-static member method of `Owner` to use as timer handler. 327 * 328 * The `Owner` MUST be a type that is accessible using `InstanceLocator::Get<Owner>()`. 329 */ 330 template <typename Owner, void (Owner::*HandleTimerPtr)(void)> class TimerMilliIn : public TimerMilli 331 { 332 public: 333 /** 334 * Initializes the timer. 335 * 336 * @param[in] aInstance The OpenThread instance. 337 */ TimerMilliIn(Instance & aInstance)338 explicit TimerMilliIn(Instance &aInstance) 339 : TimerMilli(aInstance, HandleTimer) 340 { 341 } 342 343 private: 344 static void HandleTimer(Timer &aTimer); // Implemented in `instance.hpp` 345 }; 346 347 /** 348 * Implements a millisecond timer that also maintains a user context pointer. 349 * 350 * In typical `TimerMilli`/`TimerMicro` use, in the timer callback handler, the owner of the timer is determined using 351 * `GetOwner<Type>` method. This method works if there is a single instance of `Type` within OpenThread instance 352 * hierarchy. The `TimerMilliContext` is intended for cases where there may be multiple instances of the same class/type 353 * using a timer object. `TimerMilliContext` will store a context `void *` information. 354 */ 355 class TimerMilliContext : public TimerMilli 356 { 357 public: 358 /** 359 * Creates a millisecond timer that also maintains a user context pointer. 360 * 361 * @param[in] aInstance A reference to the OpenThread instance. 362 * @param[in] aHandler A pointer to a function that is called when the timer expires. 363 * @param[in] aContext A pointer to an arbitrary context information. 364 */ TimerMilliContext(Instance & aInstance,Handler aHandler,void * aContext)365 TimerMilliContext(Instance &aInstance, Handler aHandler, void *aContext) 366 : TimerMilli(aInstance, aHandler) 367 , mContext(aContext) 368 { 369 } 370 371 /** 372 * Returns the pointer to the arbitrary context information. 373 * 374 * @returns Pointer to the arbitrary context information. 375 */ GetContext(void)376 void *GetContext(void) { return mContext; } 377 378 private: 379 void *mContext; 380 }; 381 382 #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 383 384 extern "C" void otPlatAlarmMicroFired(otInstance *aInstance); 385 386 /** 387 * Implements the microsecond timer. 388 */ 389 class TimerMicro : public Timer 390 { 391 public: 392 /** 393 * Implements the microsecond timer scheduler. 394 */ 395 class Scheduler : private Timer::Scheduler 396 { 397 friend class TimerMicro; 398 friend void otPlatAlarmMicroFired(otInstance *aInstance); 399 400 public: 401 /** 402 * Initializes the object. 403 * 404 * @param[in] aInstance A reference to the instance object. 405 */ Scheduler(Instance & aInstance)406 explicit Scheduler(Instance &aInstance) 407 : Timer::Scheduler(aInstance) 408 { 409 } 410 411 private: Add(TimerMicro & aTimer)412 void Add(TimerMicro &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMicroApi); } Remove(TimerMicro & aTimer)413 void Remove(TimerMicro &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMicroApi); } RemoveAll(void)414 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMicroApi); } ProcessTimers(void)415 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMicroApi); } 416 417 static const AlarmApi sAlarmMicroApi; 418 }; 419 420 /** 421 * Creates a timer instance. 422 * 423 * @param[in] aInstance A reference to the OpenThread instance. 424 * @param[in] aHandler A pointer to a function that is called when the timer expires. 425 */ TimerMicro(Instance & aInstance,Handler aHandler)426 TimerMicro(Instance &aInstance, Handler aHandler) 427 : Timer(aInstance, aHandler) 428 { 429 } 430 431 /** 432 * Schedules the timer to fire after a given delay (in microseconds) from now. 433 * 434 * @param[in] aDelay The delay in microseconds. It must not be be longer than `kMaxDelay`. 435 */ 436 void Start(uint32_t aDelay); 437 438 /** 439 * Schedules the timer to fire after a given delay (in microseconds) from a given start time. 440 * 441 * @param[in] aStartTime The start time. 442 * @param[in] aDelay The delay in microseconds. It must not be longer than `kMaxDelay`. 443 */ 444 void StartAt(TimeMicro aStartTime, uint32_t aDelay); 445 446 /** 447 * Schedules the timer to fire at a given fire time. 448 * 449 * @param[in] aFireTime The fire time. 450 */ 451 void FireAt(TimeMicro aFireTime); 452 453 /** 454 * Stops the timer. 455 */ 456 void Stop(void); 457 458 /** 459 * Returns the current time in microseconds. 460 * 461 * @returns The current time in microseconds. 462 */ GetNow(void)463 static TimeMicro GetNow(void) { return Time(otPlatAlarmMicroGetNow()); } 464 465 protected: 466 static void RemoveAll(Instance &aInstance); 467 }; 468 469 /** 470 * Defines a timer owned by a specific type and using a method on owner type as the callback. 471 * 472 * @tparam Owner The type of the owner of this timer. 473 * @tparam HandleTimerPtr A pointer to a non-static member method of `Owner` to use as timer handler. 474 * 475 * The `Owner` MUST be a type that is accessible using `InstanceLocator::Get<Owner>()`. 476 */ 477 template <typename Owner, void (Owner::*HandleTimerPtr)(void)> class TimerMicroIn : public TimerMicro 478 { 479 public: 480 /** 481 * Initializes the timer. 482 * 483 * @param[in] aInstance The OpenThread instance. 484 */ TimerMicroIn(Instance & aInstance)485 explicit TimerMicroIn(Instance &aInstance) 486 : TimerMicro(aInstance, HandleTimer) 487 { 488 } 489 490 private: 491 static void HandleTimer(Timer &aTimer); // Implemented in `instance.hpp` 492 }; 493 494 #endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 495 496 /** 497 * @} 498 */ 499 500 } // namespace ot 501 502 #endif // TIMER_HPP_ 503