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 method 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 * This method 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 * This class implements the millisecond timer. 150 * 151 */ 152 class TimerMilli : public Timer 153 { 154 public: 155 /** 156 * This class 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 * This constructor 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 * This constructor 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 * This method 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 * This method 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 * This method 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 * This method stops the timer. 233 * 234 */ 235 void Stop(void); 236 237 /** 238 * This static method 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 * This class implements a millisecond timer that also maintains a user context pointer. 251 * 252 * In typical `TimerMilli`/`TimerMicro` use, in the timer callback handler, the owner of the timer is determined using 253 * `GetOwner<Type>` method. This method works if there is a single instance of `Type` within OpenThread instance 254 * hierarchy. The `TimerMilliContext` is intended for cases where there may be multiple instances of the same class/type 255 * using a timer object. `TimerMilliContext` will store a context `void *` information. 256 * 257 */ 258 class TimerMilliContext : public TimerMilli 259 { 260 public: 261 /** 262 * This constructor creates a millisecond timer that also maintains a user context pointer. 263 * 264 * @param[in] aInstance A reference to the OpenThread instance. 265 * @param[in] aHandler A pointer to a function that is called when the timer expires. 266 * @param[in] aContext A pointer to an arbitrary context information. 267 * 268 */ TimerMilliContext(Instance & aInstance,Handler aHandler,void * aContext)269 TimerMilliContext(Instance &aInstance, Handler aHandler, void *aContext) 270 : TimerMilli(aInstance, aHandler) 271 , mContext(aContext) 272 { 273 } 274 275 /** 276 * This method returns the pointer to the arbitrary context information. 277 * 278 * @returns Pointer to the arbitrary context information. 279 * 280 */ GetContext(void)281 void *GetContext(void) { return mContext; } 282 283 private: 284 void *mContext; 285 }; 286 287 #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 288 289 extern "C" void otPlatAlarmMicroFired(otInstance *aInstance); 290 291 /** 292 * This class implements the microsecond timer. 293 * 294 */ 295 class TimerMicro : public Timer 296 { 297 public: 298 /** 299 * This class implements the microsecond timer scheduler. 300 * 301 */ 302 class Scheduler : private Timer::Scheduler 303 { 304 friend class TimerMicro; 305 friend void otPlatAlarmMicroFired(otInstance *aInstance); 306 307 public: 308 /** 309 * This constructor initializes the object. 310 * 311 * @param[in] aInstance A reference to the instance object. 312 * 313 */ Scheduler(Instance & aInstance)314 explicit Scheduler(Instance &aInstance) 315 : Timer::Scheduler(aInstance) 316 { 317 } 318 319 private: Add(TimerMicro & aTimer)320 void Add(TimerMicro &aTimer) { Timer::Scheduler::Add(aTimer, sAlarmMicroApi); } Remove(TimerMicro & aTimer)321 void Remove(TimerMicro &aTimer) { Timer::Scheduler::Remove(aTimer, sAlarmMicroApi); } RemoveAll(void)322 void RemoveAll(void) { Timer::Scheduler::RemoveAll(sAlarmMicroApi); } ProcessTimers(void)323 void ProcessTimers(void) { Timer::Scheduler::ProcessTimers(sAlarmMicroApi); } 324 325 static const AlarmApi sAlarmMicroApi; 326 }; 327 328 /** 329 * This constructor creates a timer instance. 330 * 331 * @param[in] aInstance A reference to the OpenThread instance. 332 * @param[in] aHandler A pointer to a function that is called when the timer expires. 333 * 334 */ TimerMicro(Instance & aInstance,Handler aHandler)335 TimerMicro(Instance &aInstance, Handler aHandler) 336 : Timer(aInstance, aHandler) 337 { 338 } 339 340 /** 341 * This method schedules the timer to fire after a given delay (in microseconds) from now. 342 * 343 * @param[in] aDelay The delay in microseconds. It must not be be longer than `kMaxDelay`. 344 * 345 */ 346 void Start(uint32_t aDelay); 347 348 /** 349 * This method schedules the timer to fire after a given delay (in microseconds) from a given start time. 350 * 351 * @param[in] aStartTime The start time. 352 * @param[in] aDelay The delay in microseconds. It must not be longer than `kMaxDelay`. 353 * 354 */ 355 void StartAt(TimeMicro aStartTime, uint32_t aDelay); 356 357 /** 358 * This method schedules the timer to fire at a given fire time. 359 * 360 * @param[in] aFireTime The fire time. 361 * 362 */ 363 void FireAt(TimeMicro aFireTime); 364 365 /** 366 * This method stops the timer. 367 * 368 */ 369 void Stop(void); 370 371 /** 372 * This static method returns the current time in microseconds. 373 * 374 * @returns The current time in microseconds. 375 * 376 */ GetNow(void)377 static TimeMicro GetNow(void) { return Time(otPlatAlarmMicroGetNow()); } 378 379 protected: 380 static void RemoveAll(Instance &aInstance); 381 }; 382 #endif // OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 383 384 /** 385 * @} 386 * 387 */ 388 389 } // namespace ot 390 391 #endif // TIMER_HPP_ 392