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