• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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