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 /** 65 * Implements a timer. 66 * 67 */ 68 class Timer : public InstanceLocator, public LinkedListEntry<Timer> 69 { 70 friend class LinkedListEntry<Timer>; 71 72 public: 73 /** 74 * This constant defines maximum delay allowed when starting a timer. 75 * 76 */ 77 static const uint32_t kMaxDelay = (Time::kMaxDuration >> 1); 78 79 /** 80 * Defines a function reference which is invoked when the timer expires. 81 * 82 * @param[in] aTimer A reference to the expired timer instance. 83 * 84 */ 85 typedef void (&Handler)(Timer &aTimer); 86 87 /** 88 * Returns the fire time of the timer. 89 * 90 * @returns The fire time. 91 * 92 */ GetFireTime(void) const93 Time GetFireTime(void) const { return mFireTime; } 94 95 /** 96 * Indicates whether or not the timer instance is running. 97 * 98 * @retval TRUE If the timer is running. 99 * @retval FALSE If the timer is not running. 100 * 101 */ IsRunning(void) const102 bool IsRunning(void) const { return (mNext != this); } 103 104 protected: 105 class Scheduler : public InstanceLocator, private NonCopyable 106 { 107 friend class Timer; 108 109 protected: 110 struct AlarmApi 111 { 112 void (*AlarmStartAt)(otInstance *aInstance, uint32_t aT0, uint32_t aDt); 113 void (*AlarmStop)(otInstance *aInstance); 114 uint32_t (*AlarmGetNow)(void); 115 }; 116 Scheduler(Instance & aInstance)117 explicit Scheduler(Instance &aInstance) 118 : InstanceLocator(aInstance) 119 { 120 } 121 122 void Add(Timer &aTimer, const AlarmApi &aAlarmApi); 123 void Remove(Timer &aTimer, const AlarmApi &aAlarmApi); 124 void RemoveAll(const AlarmApi &aAlarmApi); 125 void ProcessTimers(const AlarmApi &aAlarmApi); 126 void SetAlarm(const AlarmApi &aAlarmApi); 127 128 LinkedList<Timer> mTimerList; 129 }; 130 Timer(Instance & aInstance,Handler aHandler)131 Timer(Instance &aInstance, Handler aHandler) 132 : InstanceLocator(aInstance) 133 , mHandler(aHandler) 134 , mNext(this) 135 { 136 } 137 138 bool DoesFireBefore(const Timer &aSecondTimer, Time aNow) const; Fired(void)139 void Fired(void) { mHandler(*this); } 140 141 Handler mHandler; 142 Time mFireTime; 143 Timer *mNext; 144 }; 145 146 extern "C" void otPlatAlarmMilliFired(otInstance *aInstance); 147 148 /** 149 * Implements the millisecond timer. 150 * 151 */ 152 class TimerMilli : public Timer 153 { 154 public: 155 /** 156 * Implements the millisecond timer scheduler. 157 * 158 */ 159 class Scheduler : private Timer::Scheduler 160 { 161 friend class TimerMilli; 162 friend void otPlatAlarmMilliFired(otInstance *aInstance); 163 164 public: 165 /** 166 * Initializes the object. 167 * 168 * @param[in] aInstance A reference to the instance object. 169 * 170 */ Scheduler(Instance & aInstance)171 explicit Scheduler(Instance &aInstance) 172 : Timer::Scheduler(aInstance) 173 { 174 } 175 176 private: Add(TimerMilli & aTimer)177 void Add(TimerMilli &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMilliApi); } Remove(TimerMilli & aTimer)178 void Remove(TimerMilli &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMilliApi); } RemoveAll(void)179 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMilliApi); } ProcessTimers(void)180 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMilliApi); } 181 182 static const AlarmApi sAlarmMilliApi; 183 }; 184 185 /** 186 * Creates a millisecond timer instance. 187 * 188 * @param[in] aInstance A reference to the OpenThread instance. 189 * @param[in] aHandler A pointer to a function that is called when the timer expires. 190 * 191 */ TimerMilli(Instance & aInstance,Handler aHandler)192 TimerMilli(Instance &aInstance, Handler aHandler) 193 : Timer(aInstance, aHandler) 194 { 195 } 196 197 /** 198 * Schedules the timer to fire after a given delay (in milliseconds) from now. 199 * 200 * @param[in] aDelay The delay in milliseconds. It must not be longer than `kMaxDelay`. 201 * 202 */ 203 void Start(uint32_t aDelay); 204 205 /** 206 * Schedules the timer to fire after a given delay (in milliseconds) from a given start time. 207 * 208 * @param[in] aStartTime The start time. 209 * @param[in] aDelay The delay in milliseconds. It must not be longer than `kMaxDelay`. 210 * 211 */ 212 void StartAt(TimeMilli aStartTime, uint32_t aDelay); 213 214 /** 215 * Schedules the timer to fire at a given fire time. 216 * 217 * @param[in] aFireTime The fire time. 218 * 219 */ 220 void FireAt(TimeMilli aFireTime); 221 222 /** 223 * This method (re-)schedules the timer with a given a fire time only if the timer is not running or the new given 224 * fire time is earlier than the current fire time. 225 * 226 * @param[in] aFireTime The fire time. 227 * 228 */ 229 void FireAtIfEarlier(TimeMilli aFireTime); 230 231 /** 232 * Stops the timer. 233 * 234 */ 235 void Stop(void); 236 237 /** 238 * Returns the current time in milliseconds. 239 * 240 * @returns The current time in milliseconds. 241 * 242 */ GetNow(void)243 static TimeMilli GetNow(void) { return TimeMilli(otPlatAlarmMilliGetNow()); } 244 245 protected: 246 static void RemoveAll(Instance &aInstance); 247 }; 248 249 /** 250 * Defines a timer owned by a specific type and using a method on owner type as the callback. 251 * 252 * @tparam Owner The type of the owner of this timer. 253 * @tparam HandleTimerPtr A pointer to a non-static member method of `Owner` to use as timer handler. 254 * 255 * The `Owner` MUST be a type that is accessible using `InstanceLocator::Get<Owner>()`. 256 * 257 */ 258 template <typename Owner, void (Owner::*HandleTimerPtr)(void)> class TimerMilliIn : public TimerMilli 259 { 260 public: 261 /** 262 * Initializes the timer. 263 * 264 * @param[in] aInstance The OpenThread instance. 265 * 266 */ TimerMilliIn(Instance & aInstance)267 explicit TimerMilliIn(Instance &aInstance) 268 : TimerMilli(aInstance, HandleTimer) 269 { 270 } 271 272 private: 273 static void HandleTimer(Timer &aTimer); // Implemented in `locator_getters.hpp` 274 }; 275 276 /** 277 * Implements a millisecond timer that also maintains a user context pointer. 278 * 279 * In typical `TimerMilli`/`TimerMicro` use, in the timer callback handler, the owner of the timer is determined using 280 * `GetOwner<Type>` method. This method works if there is a single instance of `Type` within OpenThread instance 281 * hierarchy. The `TimerMilliContext` is intended for cases where there may be multiple instances of the same class/type 282 * using a timer object. `TimerMilliContext` will store a context `void *` information. 283 * 284 */ 285 class TimerMilliContext : public TimerMilli 286 { 287 public: 288 /** 289 * Creates a millisecond timer that also maintains a user context pointer. 290 * 291 * @param[in] aInstance A reference to the OpenThread instance. 292 * @param[in] aHandler A pointer to a function that is called when the timer expires. 293 * @param[in] aContext A pointer to an arbitrary context information. 294 * 295 */ TimerMilliContext(Instance & aInstance,Handler aHandler,void * aContext)296 TimerMilliContext(Instance &aInstance, Handler aHandler, void *aContext) 297 : TimerMilli(aInstance, aHandler) 298 , mContext(aContext) 299 { 300 } 301 302 /** 303 * Returns the pointer to the arbitrary context information. 304 * 305 * @returns Pointer to the arbitrary context information. 306 * 307 */ GetContext(void)308 void *GetContext(void) { return mContext; } 309 310 private: 311 void *mContext; 312 }; 313 314 #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 315 316 extern "C" void otPlatAlarmMicroFired(otInstance *aInstance); 317 318 /** 319 * Implements the microsecond timer. 320 * 321 */ 322 class TimerMicro : public Timer 323 { 324 public: 325 /** 326 * Implements the microsecond timer scheduler. 327 * 328 */ 329 class Scheduler : private Timer::Scheduler 330 { 331 friend class TimerMicro; 332 friend void otPlatAlarmMicroFired(otInstance *aInstance); 333 334 public: 335 /** 336 * Initializes the object. 337 * 338 * @param[in] aInstance A reference to the instance object. 339 * 340 */ Scheduler(Instance & aInstance)341 explicit Scheduler(Instance &aInstance) 342 : Timer::Scheduler(aInstance) 343 { 344 } 345 346 private: Add(TimerMicro & aTimer)347 void Add(TimerMicro &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMicroApi); } Remove(TimerMicro & aTimer)348 void Remove(TimerMicro &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMicroApi); } RemoveAll(void)349 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMicroApi); } ProcessTimers(void)350 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMicroApi); } 351 352 static const AlarmApi sAlarmMicroApi; 353 }; 354 355 /** 356 * Creates a timer instance. 357 * 358 * @param[in] aInstance A reference to the OpenThread instance. 359 * @param[in] aHandler A pointer to a function that is called when the timer expires. 360 * 361 */ TimerMicro(Instance & aInstance,Handler aHandler)362 TimerMicro(Instance &aInstance, Handler aHandler) 363 : Timer(aInstance, aHandler) 364 { 365 } 366 367 /** 368 * Schedules the timer to fire after a given delay (in microseconds) from now. 369 * 370 * @param[in] aDelay The delay in microseconds. It must not be be longer than `kMaxDelay`. 371 * 372 */ 373 void Start(uint32_t aDelay); 374 375 /** 376 * Schedules the timer to fire after a given delay (in microseconds) from a given start time. 377 * 378 * @param[in] aStartTime The start time. 379 * @param[in] aDelay The delay in microseconds. It must not be longer than `kMaxDelay`. 380 * 381 */ 382 void StartAt(TimeMicro aStartTime, uint32_t aDelay); 383 384 /** 385 * Schedules the timer to fire at a given fire time. 386 * 387 * @param[in] aFireTime The fire time. 388 * 389 */ 390 void FireAt(TimeMicro aFireTime); 391 392 /** 393 * Stops the timer. 394 * 395 */ 396 void Stop(void); 397 398 /** 399 * Returns the current time in microseconds. 400 * 401 * @returns The current time in microseconds. 402 * 403 */ GetNow(void)404 static TimeMicro GetNow(void) { return Time(otPlatAlarmMicroGetNow()); } 405 406 protected: 407 static void RemoveAll(Instance &aInstance); 408 }; 409 410 /** 411 * Defines a timer owned by a specific type and using a method on owner type as the callback. 412 * 413 * @tparam Owner The type of the owner of this timer. 414 * @tparam HandleTimerPtr A pointer to a non-static member method of `Owner` to use as timer handler. 415 * 416 * The `Owner` MUST be a type that is accessible using `InstanceLocator::Get<Owner>()`. 417 * 418 */ 419 template <typename Owner, void (Owner::*HandleTimerPtr)(void)> class TimerMicroIn : public TimerMicro 420 { 421 public: 422 /** 423 * Initializes the timer. 424 * 425 * @param[in] aInstance The OpenThread instance. 426 * 427 */ TimerMicroIn(Instance & aInstance)428 explicit TimerMicroIn(Instance &aInstance) 429 : TimerMicro(aInstance, HandleTimer) 430 { 431 } 432 433 private: 434 static void HandleTimer(Timer &aTimer); // Implemented in `locator_getters.hpp` 435 }; 436 437 #endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 438 439 /** 440 * @} 441 * 442 */ 443 444 } // namespace ot 445 446 #endif // TIMER_HPP_ 447