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