ChibiOS/RT  6.0.3
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
223 #endif
224  }
225 
226  return true;
227 }
228 
229 /**
230  * @brief Returns @p true if the specified timer is armed.
231  * @pre The timer must have been initialized using @p chVTObjectInit()
232  * or @p chVTDoSetI().
233  *
234  * @param[in] vtp the @p virtual_timer_t structure pointer
235  * @return true if the timer is armed.
236  *
237  * @iclass
238  */
239 static inline bool chVTIsArmedI(const virtual_timer_t *vtp) {
240 
242 
243  return (bool)(vtp->func != NULL);
244 }
245 
246 /**
247  * @brief Returns @p true if the specified timer is armed.
248  * @pre The timer must have been initialized using @p chVTObjectInit()
249  * or @p chVTDoSetI().
250  *
251  * @param[in] vtp the @p virtual_timer_t structure pointer
252  * @return true if the timer is armed.
253  *
254  * @api
255  */
256 static inline bool chVTIsArmed(const virtual_timer_t *vtp) {
257  bool b;
258 
259  chSysLock();
260  b = chVTIsArmedI(vtp);
261  chSysUnlock();
262 
263  return b;
264 }
265 
266 /**
267  * @brief Disables a Virtual Timer.
268  * @note The timer is first checked and disabled only if armed.
269  * @pre The timer must have been initialized using @p chVTObjectInit()
270  * or @p chVTDoSetI().
271  *
272  * @param[in] vtp the @p virtual_timer_t structure pointer
273  *
274  * @iclass
275  */
276 static inline void chVTResetI(virtual_timer_t *vtp) {
277 
278  if (chVTIsArmedI(vtp)) {
279  chVTDoResetI(vtp);
280  }
281 }
282 
283 /**
284  * @brief Disables a Virtual Timer.
285  * @note The timer is first checked and disabled only if armed.
286  * @pre The timer must have been initialized using @p chVTObjectInit()
287  * or @p chVTDoSetI().
288  *
289  * @param[in] vtp the @p virtual_timer_t structure pointer
290  *
291  * @api
292  */
293 static inline void chVTReset(virtual_timer_t *vtp) {
294 
295  chSysLock();
296  chVTResetI(vtp);
297  chSysUnlock();
298 }
299 
300 /**
301  * @brief Enables a virtual timer.
302  * @details If the virtual timer was already enabled then it is re-enabled
303  * using the new parameters.
304  * @pre The timer must have been initialized using @p chVTObjectInit()
305  * or @p chVTDoSetI().
306  *
307  * @param[in] vtp the @p virtual_timer_t structure pointer
308  * @param[in] delay the number of ticks before the operation timeouts, the
309  * special values are handled as follow:
310  * - @a TIME_INFINITE is allowed but interpreted as a
311  * normal time specification.
312  * - @a TIME_IMMEDIATE this value is not allowed.
313  * .
314  * @param[in] vtfunc the timer callback function. After invoking the
315  * callback the timer is disabled and the structure can
316  * be disposed or reused.
317  * @param[in] par a parameter that will be passed to the callback
318  * function
319  *
320  * @iclass
321  */
322 static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay,
323  vtfunc_t vtfunc, void *par) {
324 
325  chVTResetI(vtp);
326  chVTDoSetI(vtp, delay, vtfunc, par);
327 }
328 
329 /**
330  * @brief Enables a virtual timer.
331  * @details If the virtual timer was already enabled then it is re-enabled
332  * using the new parameters.
333  * @pre The timer must have been initialized using @p chVTObjectInit()
334  * or @p chVTDoSetI().
335  *
336  * @param[in] vtp the @p virtual_timer_t structure pointer
337  * @param[in] delay the number of ticks before the operation timeouts, the
338  * special values are handled as follow:
339  * - @a TIME_INFINITE is allowed but interpreted as a
340  * normal time specification.
341  * - @a TIME_IMMEDIATE this value is not allowed.
342  * .
343  * @param[in] vtfunc the timer callback function. After invoking the
344  * callback the timer is disabled and the structure can
345  * be disposed or reused.
346  * @param[in] par a parameter that will be passed to the callback
347  * function
348  *
349  * @api
350  */
351 static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay,
352  vtfunc_t vtfunc, void *par) {
353 
354  chSysLock();
355  chVTSetI(vtp, delay, vtfunc, par);
356  chSysUnlock();
357 }
358 
359 /**
360  * @brief Virtual timers ticker.
361  * @note The system lock is released before entering the callback and
362  * re-acquired immediately after. It is callback's responsibility
363  * to acquire the lock if needed. This is done in order to reduce
364  * interrupts jitter when many timers are in use.
365  *
366  * @iclass
367  */
368 static inline void chVTDoTickI(void) {
369 
371 
372 #if CH_CFG_ST_TIMEDELTA == 0
373  ch.vtlist.systime++;
375  /* The list is not empty, processing elements on top.*/
376  --ch.vtlist.next->delta;
377  while (ch.vtlist.next->delta == (sysinterval_t)0) {
378  virtual_timer_t *vtp;
379  vtfunc_t fn;
380 
381  vtp = ch.vtlist.next;
382  fn = vtp->func;
383  vtp->func = NULL;
384  vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
385  ch.vtlist.next = vtp->next;
387  fn(vtp->par);
389  }
390  }
391 #else /* CH_CFG_ST_TIMEDELTA > 0 */
392  virtual_timer_t *vtp;
393  systime_t now;
394  sysinterval_t delta, nowdelta;
395 
396  /* Looping through timers.*/
397  vtp = ch.vtlist.next;
398  while (true) {
399 
400  /* Getting the system time as reference.*/
401  now = chVTGetSystemTimeX();
402  nowdelta = chTimeDiffX(ch.vtlist.lasttime, now);
403 
404  /* The list scan is limited by the timers header having
405  "ch.vtlist.vt_delta == (sysinterval_t)-1" which is
406  greater than all deltas.*/
407  if (nowdelta < vtp->delta) {
408  break;
409  }
410 
411  /* Consuming all timers between "vtp->lasttime" and now.*/
412  do {
413  vtfunc_t fn;
414 
415  /* The "last time" becomes this timer's expiration time.*/
416  ch.vtlist.lasttime += vtp->delta;
417  nowdelta -= vtp->delta;
418 
419  vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
420  ch.vtlist.next = vtp->next;
421  fn = vtp->func;
422  vtp->func = NULL;
423 
424  /* If the list becomes empty then the timer is stopped.*/
425  if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
426  port_timer_stop_alarm();
427  }
428 
429  /* The callback is invoked outside the kernel critical zone.*/
431  fn(vtp->par);
433 
434  /* Next element in the list.*/
435  vtp = ch.vtlist.next;
436  }
437  while (vtp->delta <= nowdelta);
438  }
439 
440  /* If the list is empty, nothing else to do.*/
441  if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
442  return;
443  }
444 
445  /* The "unprocessed nowdelta" time slice is added to "last time"
446  and subtracted to next timer's delta.*/
447  ch.vtlist.lasttime += nowdelta;
448  ch.vtlist.next->delta -= nowdelta;
449 
450  /* Recalculating the next alarm time.*/
451  delta = vtp->delta - chTimeDiffX(ch.vtlist.lasttime, now);
452  if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
453  delta = (sysinterval_t)CH_CFG_ST_TIMEDELTA;
454  }
455 #if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION
456  /* The delta could be too large for the physical timer to handle.*/
457  else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) {
459  }
460 #endif
461  port_timer_set_alarm(chTimeAddX(now, delta));
462 
464  chTimeDiffX(ch.vtlist.lasttime, chTimeAddX(now, delta)),
465  "exceeding delta");
466 #endif /* CH_CFG_ST_TIMEDELTA > 0 */
467 }
468 
469 #endif /* CHVT_H */
470 
471 /** @} */
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:107
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
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:293
static sysinterval_t chTimeDiffX(systime_t start, systime_t end)
Subtracts two system times returning an interval.
Definition: chtime.h:459
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:480
#define TIME_MAX_SYSTIME
Maximum system of system time before it wraps.
Definition: chtime.h:65
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:322
static void chVTObjectInit(virtual_timer_t *vtp)
Initializes a virtual_timer_t object.
Definition: chvt.h:97
static void chVTSet(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par)
Enables a virtual timer.
Definition: chvt.h:351
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:239
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
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:256
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:276
#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
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:233
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:127
static void chVTDoTickI(void)
Virtual timers ticker.
Definition: chvt.h:368
static systime_t chTimeAddX(systime_t systime, sysinterval_t interval)
Adds an interval to a system time returning a system time.
Definition: chtime.h:440
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