ChibiOS/RT  5.1.0
chvt.h
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
3 
4  This file is part of ChibiOS.
5 
6  ChibiOS is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
10 
11  ChibiOS is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /**
21  * @file chvt.h
22  * @brief Time and Virtual Timers module macros and structures.
23  *
24  * @addtogroup time
25  * @{
26  */
27 
28 #ifndef CHVT_H
29 #define CHVT_H
30 
31 /*===========================================================================*/
32 /* Module constants. */
33 /*===========================================================================*/
34 
35 /*===========================================================================*/
36 /* Module pre-compile time settings. */
37 /*===========================================================================*/
38 
39 /*===========================================================================*/
40 /* Derived constants and error checks. */
41 /*===========================================================================*/
42 
43 #if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1)
44 #error "invalid CH_CFG_ST_TIMEDELTA specified, must " \
45  "be zero or greater than one"
46 #endif
47 
48 //#if (CH_CFG_ST_TIMEDELTA > 0) && (CH_CFG_TIME_QUANTUM > 0)
49 //#error "CH_CFG_TIME_QUANTUM not supported in tickless mode"
50 //#endif
51 
52 #if (CH_CFG_ST_TIMEDELTA > 0) && (CH_DBG_THREADS_PROFILING == TRUE)
53 #error "CH_DBG_THREADS_PROFILING not supported in tickless mode"
54 #endif
55 
56 /*===========================================================================*/
57 /* Module data structures and types. */
58 /*===========================================================================*/
59 
60 /*===========================================================================*/
61 /* Module macros. */
62 /*===========================================================================*/
63 
64 /*===========================================================================*/
65 /* External declarations. */
66 /*===========================================================================*/
67 
68 /*
69  * Virtual Timers APIs.
70  */
71 #ifdef __cplusplus
72 extern "C" {
73 #endif
74  void _vt_init(void);
75  void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay,
76  vtfunc_t vtfunc, void *par);
77  void chVTDoResetI(virtual_timer_t *vtp);
78 #ifdef __cplusplus
79 }
80 #endif
81 
82 /*===========================================================================*/
83 /* Module inline functions. */
84 /*===========================================================================*/
85 
86 /**
87  * @brief Initializes a @p virtual_timer_t object.
88  * @note Initializing a timer object is not strictly required because
89  * the function @p chVTSetI() initializes the object too. This
90  * function is only useful if you need to perform a @p chVTIsArmed()
91  * check before calling @p chVTSetI().
92  *
93  * @param[out] vtp the @p virtual_timer_t structure pointer
94  *
95  * @init
96  */
97 static inline void chVTObjectInit(virtual_timer_t *vtp) {
98 
99  vtp->func = NULL;
100 }
101 
102 /**
103  * @brief Current system time.
104  * @details Returns the number of system ticks since the @p chSysInit()
105  * invocation.
106  * @note The counter can reach its maximum and then restart from zero.
107  * @note This function can be called from any context but its atomicity
108  * is not guaranteed on architectures whose word size is less than
109  * @p systime_t size.
110  *
111  * @return The system time in ticks.
112  *
113  * @xclass
114  */
115 static inline systime_t chVTGetSystemTimeX(void) {
116 
117 #if CH_CFG_ST_TIMEDELTA == 0
118  return ch.vtlist.systime;
119 #else /* CH_CFG_ST_TIMEDELTA > 0 */
120  return port_timer_get_time();
121 #endif /* CH_CFG_ST_TIMEDELTA > 0 */
122 }
123 
124 /**
125  * @brief Current system time.
126  * @details Returns the number of system ticks since the @p chSysInit()
127  * invocation.
128  * @note The counter can reach its maximum and then restart from zero.
129  *
130  * @return The system time in ticks.
131  *
132  * @api
133  */
134 static inline systime_t chVTGetSystemTime(void) {
135  systime_t systime;
136 
137  chSysLock();
138  systime = chVTGetSystemTimeX();
139  chSysUnlock();
140 
141  return systime;
142 }
143 
144 /**
145  * @brief Returns the elapsed time since the specified start time.
146  *
147  * @param[in] start start time
148  * @return The elapsed time.
149  *
150  * @xclass
151  */
153 
154  return chTimeDiffX(start, chVTGetSystemTimeX());
155 }
156 
157 /**
158  * @brief Checks if the current system time is within the specified time
159  * window.
160  * @note When start==end then the function returns always true because the
161  * whole time range is specified.
162  *
163  * @param[in] start the start of the time window (inclusive)
164  * @param[in] end the end of the time window (non inclusive)
165  * @retval true current time within the specified time window.
166  * @retval false current time not within the specified time window.
167  *
168  * @xclass
169  */
170 static inline bool chVTIsSystemTimeWithinX(systime_t start, systime_t end) {
171 
172  return chTimeIsInRangeX(chVTGetSystemTimeX(), start, end);
173 }
174 
175 /**
176  * @brief Checks if the current system time is within the specified time
177  * window.
178  * @note When start==end then the function returns always true because the
179  * whole time range is specified.
180  *
181  * @param[in] start the start of the time window (inclusive)
182  * @param[in] end the end of the time window (non inclusive)
183  * @retval true current time within the specified time window.
184  * @retval false current time not within the specified time window.
185  *
186  * @api
187  */
188 static inline bool chVTIsSystemTimeWithin(systime_t start, systime_t end) {
189 
190  return chTimeIsInRangeX(chVTGetSystemTime(), start, end);
191 }
192 
193 /**
194  * @brief Returns the time interval until the next timer event.
195  * @note The return value is not perfectly accurate and can report values
196  * in excess of @p CH_CFG_ST_TIMEDELTA ticks.
197  * @note The interval returned by this function is only meaningful if
198  * more timers are not added to the list until the returned time.
199  *
200  * @param[out] timep pointer to a variable that will contain the time
201  * interval until the next timer elapses. This pointer
202  * can be @p NULL if the information is not required.
203  * @return The time, in ticks, until next time event.
204  * @retval false if the timers list is empty.
205  * @retval true if the timers list contains at least one timer.
206  *
207  * @iclass
208  */
209 static inline bool chVTGetTimersStateI(sysinterval_t *timep) {
210 
212 
214  return false;
215  }
216 
217  if (timep != NULL) {
218 #if CH_CFG_ST_TIMEDELTA == 0
219  *timep = ch.vtlist.next->delta;
220 #else
221  *timep = chTimeDiffX(chVTGetSystemTimeX(),
223  ch.vtlist.next->delta +
225 #endif
226  }
227 
228  return true;
229 }
230 
231 /**
232  * @brief Returns @p true if the specified timer is armed.
233  * @pre The timer must have been initialized using @p chVTObjectInit()
234  * or @p chVTDoSetI().
235  *
236  * @param[in] vtp the @p virtual_timer_t structure pointer
237  * @return true if the timer is armed.
238  *
239  * @iclass
240  */
241 static inline bool chVTIsArmedI(const virtual_timer_t *vtp) {
242 
244 
245  return (bool)(vtp->func != NULL);
246 }
247 
248 /**
249  * @brief Returns @p true if the specified timer is armed.
250  * @pre The timer must have been initialized using @p chVTObjectInit()
251  * or @p chVTDoSetI().
252  *
253  * @param[in] vtp the @p virtual_timer_t structure pointer
254  * @return true if the timer is armed.
255  *
256  * @api
257  */
258 static inline bool chVTIsArmed(const virtual_timer_t *vtp) {
259  bool b;
260 
261  chSysLock();
262  b = chVTIsArmedI(vtp);
263  chSysUnlock();
264 
265  return b;
266 }
267 
268 /**
269  * @brief Disables a Virtual Timer.
270  * @note The timer is first checked and disabled only if armed.
271  * @pre The timer must have been initialized using @p chVTObjectInit()
272  * or @p chVTDoSetI().
273  *
274  * @param[in] vtp the @p virtual_timer_t structure pointer
275  *
276  * @iclass
277  */
278 static inline void chVTResetI(virtual_timer_t *vtp) {
279 
280  if (chVTIsArmedI(vtp)) {
281  chVTDoResetI(vtp);
282  }
283 }
284 
285 /**
286  * @brief Disables a Virtual Timer.
287  * @note The timer is first checked and disabled only if armed.
288  * @pre The timer must have been initialized using @p chVTObjectInit()
289  * or @p chVTDoSetI().
290  *
291  * @param[in] vtp the @p virtual_timer_t structure pointer
292  *
293  * @api
294  */
295 static inline void chVTReset(virtual_timer_t *vtp) {
296 
297  chSysLock();
298  chVTResetI(vtp);
299  chSysUnlock();
300 }
301 
302 /**
303  * @brief Enables a virtual timer.
304  * @details If the virtual timer was already enabled then it is re-enabled
305  * using the new parameters.
306  * @pre The timer must have been initialized using @p chVTObjectInit()
307  * or @p chVTDoSetI().
308  *
309  * @param[in] vtp the @p virtual_timer_t structure pointer
310  * @param[in] delay the number of ticks before the operation timeouts, the
311  * special values are handled as follow:
312  * - @a TIME_INFINITE is allowed but interpreted as a
313  * normal time specification.
314  * - @a TIME_IMMEDIATE this value is not allowed.
315  * .
316  * @param[in] vtfunc the timer callback function. After invoking the
317  * callback the timer is disabled and the structure can
318  * be disposed or reused.
319  * @param[in] par a parameter that will be passed to the callback
320  * function
321  *
322  * @iclass
323  */
324 static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay,
325  vtfunc_t vtfunc, void *par) {
326 
327  chVTResetI(vtp);
328  chVTDoSetI(vtp, delay, vtfunc, par);
329 }
330 
331 /**
332  * @brief Enables a virtual timer.
333  * @details If the virtual timer was already enabled then it is re-enabled
334  * using the new parameters.
335  * @pre The timer must have been initialized using @p chVTObjectInit()
336  * or @p chVTDoSetI().
337  *
338  * @param[in] vtp the @p virtual_timer_t structure pointer
339  * @param[in] delay the number of ticks before the operation timeouts, the
340  * special values are handled as follow:
341  * - @a TIME_INFINITE is allowed but interpreted as a
342  * normal time specification.
343  * - @a TIME_IMMEDIATE this value is not allowed.
344  * .
345  * @param[in] vtfunc the timer callback function. After invoking the
346  * callback the timer is disabled and the structure can
347  * be disposed or reused.
348  * @param[in] par a parameter that will be passed to the callback
349  * function
350  *
351  * @api
352  */
353 static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay,
354  vtfunc_t vtfunc, void *par) {
355 
356  chSysLock();
357  chVTSetI(vtp, delay, vtfunc, par);
358  chSysUnlock();
359 }
360 
361 /**
362  * @brief Virtual timers ticker.
363  * @note The system lock is released before entering the callback and
364  * re-acquired immediately after. It is callback's responsibility
365  * to acquire the lock if needed. This is done in order to reduce
366  * interrupts jitter when many timers are in use.
367  *
368  * @iclass
369  */
370 static inline void chVTDoTickI(void) {
371 
373 
374 #if CH_CFG_ST_TIMEDELTA == 0
375  ch.vtlist.systime++;
377  /* The list is not empty, processing elements on top.*/
378  --ch.vtlist.next->delta;
379  while (ch.vtlist.next->delta == (sysinterval_t)0) {
380  virtual_timer_t *vtp;
381  vtfunc_t fn;
382 
383  vtp = ch.vtlist.next;
384  fn = vtp->func;
385  vtp->func = NULL;
386  vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
387  ch.vtlist.next = vtp->next;
389  fn(vtp->par);
391  }
392  }
393 #else /* CH_CFG_ST_TIMEDELTA > 0 */
394  virtual_timer_t *vtp;
395  systime_t now;
396  sysinterval_t delta, nowdelta;
397 
398  /* Looping through timers.*/
399  vtp = ch.vtlist.next;
400  while (true) {
401 
402  /* Getting the system time as reference.*/
403  now = chVTGetSystemTimeX();
404  nowdelta = chTimeDiffX(ch.vtlist.lasttime, now);
405 
406  /* The list scan is limited by the timers header having
407  "ch.vtlist.vt_delta == (sysinterval_t)-1" which is
408  greater than all deltas.*/
409  if (nowdelta < vtp->delta) {
410  break;
411  }
412 
413  /* Consuming all timers between "vtp->lasttime" and now.*/
414  do {
415  vtfunc_t fn;
416 
417  /* The "last time" becomes this timer's expiration time.*/
418  ch.vtlist.lasttime += vtp->delta;
419  nowdelta -= vtp->delta;
420 
421  vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
422  ch.vtlist.next = vtp->next;
423  fn = vtp->func;
424  vtp->func = NULL;
425 
426  /* if the list becomes empty then the timer is stopped.*/
427  if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
428  port_timer_stop_alarm();
429  }
430 
431  /* The callback is invoked outside the kernel critical zone.*/
433  fn(vtp->par);
435 
436  /* Next element in the list.*/
437  vtp = ch.vtlist.next;
438  }
439  while (vtp->delta <= nowdelta);
440  }
441 
442  /* if the list is empty, nothing else to do.*/
443  if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
444  return;
445  }
446 
447  /* The "unprocessed nowdelta" time slice is added to "last time"
448  and subtracted to next timer's delta.*/
449  ch.vtlist.lasttime += nowdelta;
450  ch.vtlist.next->delta -= nowdelta;
451 
452  /* Recalculating the next alarm time.*/
453  delta = chTimeDiffX(now, chTimeAddX(ch.vtlist.lasttime, vtp->delta));
454  if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
455  delta = (sysinterval_t)CH_CFG_ST_TIMEDELTA;
456  }
457 #if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION
458  /* The delta could be too large for the physical timer to handle.*/
459  else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) {
461  }
462 #endif
463  port_timer_set_alarm(chTimeAddX(now, delta));
464 
466  chTimeDiffX(ch.vtlist.lasttime, chTimeAddX(now, delta)),
467  "exceeding delta");
468 #endif /* CH_CFG_ST_TIMEDELTA > 0 */
469 }
470 
471 #endif /* CHVT_H */
472 
473 /** @} */
static systime_t chVTGetSystemTimeX(void)
Current system time.
Definition: chvt.h:115
void * par
Timer callback function parameter.
Definition: chschd.h:330
uint64_t systime_t
Type of system time.
Definition: chtime.h:138
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:150
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:353
sysinterval_t delta
Time delta before timeout.
Definition: chschd.h:327
virtual_timer_t * prev
Previous timer in the list.
Definition: chschd.h:326
static void chVTReset(virtual_timer_t *vtp)
Disables a Virtual Timer.
Definition: chvt.h:295
static sysinterval_t chTimeDiffX(systime_t start, systime_t end)
Subtracts two system times returning an interval.
Definition: chtime.h:491
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:365
static bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end)
Checks if the specified time is within the specified time range.
Definition: chtime.h:512
#define TIME_MAX_SYSTIME
Maximum system of system time before it wraps.
Definition: chtime.h:63
systime_t lasttime
System time of the last tick event.
Definition: chschd.h:353
static bool chVTIsSystemTimeWithin(systime_t start, systime_t end)
Checks if the current system time is within the specified time window.
Definition: chvt.h:188
virtual_timers_list_t vtlist
Virtual timers delta list header.
Definition: chschd.h:419
static void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par)
Enables a virtual timer.
Definition: chvt.h:324
static void chVTObjectInit(virtual_timer_t *vtp)
Initializes a virtual_timer_t object.
Definition: chvt.h:97
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:235
static void chVTSet(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par)
Enables a virtual timer.
Definition: chvt.h:353
static bool chVTGetTimersStateI(sysinterval_t *timep)
Returns the time interval until the next timer event.
Definition: chvt.h:209
void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par)
Enables a virtual timer.
Definition: chvt.c:95
void(* vtfunc_t)(void *p)
Type of a Virtual Timer callback function.
Definition: chsystypes.h:81
void chVTDoResetI(virtual_timer_t *vtp)
Disables a Virtual Timer.
Definition: chvt.c:211
Virtual timers list header.
Definition: chschd.h:340
static bool chVTIsSystemTimeWithinX(systime_t start, systime_t end)
Checks if the current system time is within the specified time window.
Definition: chvt.h:170
void _vt_init(void)
Virtual Timers initialization.
Definition: chvt.c:61
static systime_t chVTGetSystemTime(void)
Current system time.
Definition: chvt.h:134
volatile systime_t systime
System Time counter.
Definition: chschd.h:347
static bool chVTIsArmedI(const virtual_timer_t *vtp)
Returns true if the specified timer is armed.
Definition: chvt.h:241
ch_system_t ch
System data structures.
Definition: chschd.c:42
static void chSysUnlockFromISR(void)
Leaves the kernel lock state from within an interrupt handler.
Definition: chsys.h:413
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:127
static void chSysLockFromISR(void)
Enters the kernel lock state from within an interrupt handler.
Definition: chsys.h:393
Virtual Timer descriptor structure.
Definition: chschd.h:324
static bool chVTIsArmed(const virtual_timer_t *vtp)
Returns true if the specified timer is armed.
Definition: chvt.h:258
virtual_timer_t * next
Next timer in the delta list.
Definition: chschd.h:341
static void chVTResetI(virtual_timer_t *vtp)
Disables a Virtual Timer.
Definition: chvt.h:278
#define CH_CFG_ST_TIMEDELTA
Time delta constant for the tick-less mode.
Definition: chconf.h:83
virtual_timer_t * next
Next timer in the list.
Definition: chschd.h:325
static void chVTDoTickI(void)
Virtual timers ticker.
Definition: chvt.h:370
static systime_t chTimeAddX(systime_t systime, sysinterval_t interval)
Adds an interval to a system time returning a system time.
Definition: chtime.h:472
static sysinterval_t chVTTimeElapsedSinceX(systime_t start)
Returns the elapsed time since the specified start time.
Definition: chvt.h:152
vtfunc_t func
Timer callback function pointer.
Definition: chschd.h:328