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 * This class 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 * This type 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 * This constructor creates a timer instance. 89 * 90 * @param[in] aInstance A reference to the OpenThread instance. 91 * @param[in] aHandler A pointer to a function that is called when the timer expires. 92 * 93 */ Timer(Instance & aInstance,Handler aHandler)94 Timer(Instance &aInstance, Handler aHandler) 95 : InstanceLocator(aInstance) 96 , mHandler(aHandler) 97 , mFireTime() 98 , mNext(this) 99 { 100 } 101 102 /** 103 * This method returns the fire time of the timer. 104 * 105 * @returns The fire time. 106 * 107 */ GetFireTime(void) const108 Time GetFireTime(void) const { return mFireTime; } 109 110 /** 111 * This method indicates whether or not the timer instance is running. 112 * 113 * @retval TRUE If the timer is running. 114 * @retval FALSE If the timer is not running. 115 * 116 */ IsRunning(void) const117 bool IsRunning(void) const { return (mNext != this); } 118 119 protected: 120 class Scheduler : public InstanceLocator, private NonCopyable 121 { 122 friend class Timer; 123 124 protected: 125 struct AlarmApi 126 { 127 void (*AlarmStartAt)(otInstance *aInstance, uint32_t aT0, uint32_t aDt); 128 void (*AlarmStop)(otInstance *aInstance); 129 uint32_t (*AlarmGetNow)(void); 130 }; 131 Scheduler(Instance & aInstance)132 explicit Scheduler(Instance &aInstance) 133 : InstanceLocator(aInstance) 134 { 135 } 136 137 void Add(Timer &aTimer, const AlarmApi &aAlarmApi); 138 void Remove(Timer &aTimer, const AlarmApi &aAlarmApi); 139 void RemoveAll(const AlarmApi &aAlarmApi); 140 void ProcessTimers(const AlarmApi &aAlarmApi); 141 void SetAlarm(const AlarmApi &aAlarmApi); 142 143 LinkedList<Timer> mTimerList; 144 }; 145 146 bool DoesFireBefore(const Timer &aSecondTimer, Time aNow) const; Fired(void)147 void Fired(void) { mHandler(*this); } 148 149 Handler mHandler; 150 Time mFireTime; 151 Timer * mNext; 152 }; 153 154 extern "C" void otPlatAlarmMilliFired(otInstance *aInstance); 155 156 /** 157 * This class implements the millisecond timer. 158 * 159 */ 160 class TimerMilli : public Timer 161 { 162 public: 163 /** 164 * This class implements the millisecond timer scheduler. 165 * 166 */ 167 class Scheduler : private Timer::Scheduler 168 { 169 friend class TimerMilli; 170 friend void otPlatAlarmMilliFired(otInstance *aInstance); 171 172 public: 173 /** 174 * This constructor initializes the object. 175 * 176 * @param[in] aInstance A reference to the instance object. 177 * 178 */ Scheduler(Instance & aInstance)179 explicit Scheduler(Instance &aInstance) 180 : Timer::Scheduler(aInstance) 181 { 182 } 183 184 private: Add(TimerMilli & aTimer)185 void Add(TimerMilli &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMilliApi); } Remove(TimerMilli & aTimer)186 void Remove(TimerMilli &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMilliApi); } RemoveAll(void)187 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMilliApi); } ProcessTimers(void)188 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMilliApi); } 189 190 static const AlarmApi sAlarmMilliApi; 191 }; 192 193 /** 194 * This constructor creates a millisecond timer instance. 195 * 196 * @param[in] aInstance A reference to the OpenThread instance. 197 * @param[in] aHandler A pointer to a function that is called when the timer expires. 198 * 199 */ TimerMilli(Instance & aInstance,Handler aHandler)200 TimerMilli(Instance &aInstance, Handler aHandler) 201 : Timer(aInstance, aHandler) 202 { 203 } 204 205 /** 206 * This method schedules the timer to fire after a given delay (in milliseconds) from now. 207 * 208 * @param[in] aDelay The delay in milliseconds. It must not be longer than `kMaxDelay`. 209 * 210 */ 211 void Start(uint32_t aDelay); 212 213 /** 214 * This method schedules the timer to fire after a given delay (in milliseconds) from a given start time. 215 * 216 * @param[in] aStartTime The start time. 217 * @param[in] aDelay The delay in milliseconds. It must not be longer than `kMaxDelay`. 218 * 219 */ 220 void StartAt(TimeMilli aStartTime, uint32_t aDelay); 221 222 /** 223 * This method schedules the timer to fire at a given fire time. 224 * 225 * @param[in] aFireTime The fire time. 226 * 227 */ 228 void FireAt(TimeMilli aFireTime); 229 230 /** 231 * This method (re-)schedules the timer with a given a fire time only if the timer is not running or the new given 232 * fire time is earlier than the current fire time. 233 * 234 * @param[in] aFireTime The fire time. 235 * 236 */ 237 void FireAtIfEarlier(TimeMilli aFireTime); 238 239 /** 240 * This method stops the timer. 241 * 242 */ 243 void Stop(void); 244 245 /** 246 * This static method returns the current time in milliseconds. 247 * 248 * @returns The current time in milliseconds. 249 * 250 */ GetNow(void)251 static TimeMilli GetNow(void) { return TimeMilli(otPlatAlarmMilliGetNow()); } 252 253 protected: 254 static void RemoveAll(Instance &aInstance); 255 }; 256 257 /** 258 * This class implements a millisecond timer that also maintains a user context pointer. 259 * 260 * In typical `TimerMilli`/`TimerMicro` use, in the timer callback handler, the owner of the timer is determined using 261 * `GetOwner<Type>` method. This method works if there is a single instance of `Type` within OpenThread instance 262 * hierarchy. The `TimerMilliContext` is intended for cases where there may be multiple instances of the same class/type 263 * using a timer object. `TimerMilliContext` will store a context `void *` information. 264 * 265 */ 266 class TimerMilliContext : public TimerMilli 267 { 268 public: 269 /** 270 * This constructor creates a millisecond timer that also maintains a user context pointer. 271 * 272 * @param[in] aInstance A reference to the OpenThread instance. 273 * @param[in] aHandler A pointer to a function that is called when the timer expires. 274 * @param[in] aContext A pointer to an arbitrary context information. 275 * 276 */ TimerMilliContext(Instance & aInstance,Handler aHandler,void * aContext)277 TimerMilliContext(Instance &aInstance, Handler aHandler, void *aContext) 278 : TimerMilli(aInstance, aHandler) 279 , mContext(aContext) 280 { 281 } 282 283 /** 284 * This method returns the pointer to the arbitrary context information. 285 * 286 * @returns Pointer to the arbitrary context information. 287 * 288 */ GetContext(void)289 void *GetContext(void) { return mContext; } 290 291 private: 292 void *mContext; 293 }; 294 295 #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 296 297 extern "C" void otPlatAlarmMicroFired(otInstance *aInstance); 298 299 /** 300 * This class implements the microsecond timer. 301 * 302 */ 303 class TimerMicro : public Timer 304 { 305 public: 306 /** 307 * This class implements the microsecond timer scheduler. 308 * 309 */ 310 class Scheduler : private Timer::Scheduler 311 { 312 friend class TimerMicro; 313 friend void otPlatAlarmMicroFired(otInstance *aInstance); 314 315 public: 316 /** 317 * This constructor initializes the object. 318 * 319 * @param[in] aInstance A reference to the instance object. 320 * 321 */ Scheduler(Instance & aInstance)322 explicit Scheduler(Instance &aInstance) 323 : Timer::Scheduler(aInstance) 324 { 325 } 326 327 private: Add(TimerMicro & aTimer)328 void Add(TimerMicro &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMicroApi); } Remove(TimerMicro & aTimer)329 void Remove(TimerMicro &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMicroApi); } RemoveAll(void)330 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMicroApi); } ProcessTimers(void)331 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMicroApi); } 332 333 static const AlarmApi sAlarmMicroApi; 334 }; 335 336 /** 337 * This constructor creates a timer instance. 338 * 339 * @param[in] aInstance A reference to the OpenThread instance. 340 * @param[in] aHandler A pointer to a function that is called when the timer expires. 341 * 342 */ TimerMicro(Instance & aInstance,Handler aHandler)343 TimerMicro(Instance &aInstance, Handler aHandler) 344 : Timer(aInstance, aHandler) 345 { 346 } 347 348 /** 349 * This method schedules the timer to fire after a given delay (in microseconds) from now. 350 * 351 * @param[in] aDelay The delay in microseconds. It must not be be longer than `kMaxDelay`. 352 * 353 */ 354 void Start(uint32_t aDelay); 355 356 /** 357 * This method schedules the timer to fire after a given delay (in microseconds) from a given start time. 358 * 359 * @param[in] aStartTime The start time. 360 * @param[in] aDelay The delay in microseconds. It must not be longer than `kMaxDelay`. 361 * 362 */ 363 void StartAt(TimeMicro aStartTime, uint32_t aDelay); 364 365 /** 366 * This method schedules the timer to fire at a given fire time. 367 * 368 * @param[in] aFireTime The fire time. 369 * 370 */ 371 void FireAt(TimeMicro aFireTime); 372 373 /** 374 * This method stops the timer. 375 * 376 */ 377 void Stop(void); 378 379 /** 380 * This static method returns the current time in microseconds. 381 * 382 * @returns The current time in microseconds. 383 * 384 */ GetNow(void)385 static TimeMicro GetNow(void) { return Time(otPlatAlarmMicroGetNow()); } 386 387 protected: 388 static void RemoveAll(Instance &aInstance); 389 }; 390 #endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 391 392 /** 393 * @} 394 * 395 */ 396 397 } // namespace ot 398 399 #endif // TIMER_HPP_ 400