ChibiOS  21.6.0
chtime.h
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3  2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4 
5  This file is part of ChibiOS.
6 
7  ChibiOS is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation version 3 of the License.
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 rt/include/chtime.h
22  * @brief Time and intervals macros and structures.
23  *
24  * @addtogroup time_intervals
25  * @details This module is responsible for handling of system time and time
26  * intervals.
27  * @{
28  */
29 
30 #ifndef CHTIME_H
31 #define CHTIME_H
32 
33 /*===========================================================================*/
34 /* Module constants. */
35 /*===========================================================================*/
36 
37 /**
38  * @name Special time constants
39  * @{
40  */
41 /**
42  * @brief Zero interval specification for some functions with a timeout
43  * specification.
44  * @note Not all functions accept @p TIME_IMMEDIATE as timeout parameter,
45  * see the specific function documentation.
46  */
47 #define TIME_IMMEDIATE ((sysinterval_t)0)
48 
49 /**
50  * @brief Infinite interval specification for all functions with a timeout
51  * specification.
52  * @note Not all functions accept @p TIME_INFINITE as timeout parameter,
53  * see the specific function documentation.
54  */
55 #define TIME_INFINITE ((sysinterval_t)-1)
56 
57 /**
58  * @brief Maximum interval constant usable as timeout.
59  */
60 #define TIME_MAX_INTERVAL ((sysinterval_t)-2)
61 
62 /**
63  * @brief Maximum system of system time before it wraps.
64  */
65 #define TIME_MAX_SYSTIME ((systime_t)-1)
66 /** @} */
67 
68 /*===========================================================================*/
69 /* Module pre-compile time settings. */
70 /*===========================================================================*/
71 
72 /*===========================================================================*/
73 /* Derived constants and error checks. */
74 /*===========================================================================*/
75 
76 #if (CH_CFG_ST_RESOLUTION != 16) && (CH_CFG_ST_RESOLUTION != 32) && \
77  (CH_CFG_ST_RESOLUTION != 64)
78 #error "invalid CH_CFG_ST_RESOLUTION specified, must be 16, 32 or 64"
79 #endif
80 
81 #if CH_CFG_ST_FREQUENCY < 10
82 #error "invalid CH_CFG_ST_FREQUENCY specified, must be >= 10"
83 #endif
84 
85 #if (CH_CFG_INTERVALS_SIZE != 16) && (CH_CFG_INTERVALS_SIZE != 32) && \
86  (CH_CFG_INTERVALS_SIZE != 64)
87 #error "invalid CH_CFG_INTERVALS_SIZE specified, must be 16, 32 or 64"
88 #endif
89 
90 #if (CH_CFG_TIME_TYPES_SIZE != 16) && (CH_CFG_TIME_TYPES_SIZE != 32)
91 #error "invalid CH_CFG_TIME_TYPES_SIZE specified, must be 16 or 32"
92 #endif
93 
94 #if CH_CFG_INTERVALS_SIZE < CH_CFG_ST_RESOLUTION
95 #error "CH_CFG_INTERVALS_SIZE must be >= CH_CFG_ST_RESOLUTION"
96 #endif
97 
98 /*===========================================================================*/
99 /* Module data structures and types. */
100 /*===========================================================================*/
101 
102 /**
103  * @brief Type of system time.
104  * @note It is selectable in configuration between 16, 32 or 64 bits.
105  */
106 #if (CH_CFG_ST_RESOLUTION == 64) || defined(__DOXYGEN__)
107 typedef uint64_t systime_t;
108 #elif CH_CFG_ST_RESOLUTION == 32
109 typedef uint32_t systime_t;
110 #elif CH_CFG_ST_RESOLUTION == 16
111 typedef uint16_t systime_t;
112 #endif
113 
114 /**
115  * @brief Type of time interval.
116  * @note It is selectable in configuration between 16, 32 or 64 bits.
117  */
118 #if (CH_CFG_INTERVALS_SIZE == 64) || defined(__DOXYGEN__)
119 typedef uint64_t sysinterval_t;
120 #elif CH_CFG_INTERVALS_SIZE == 32
121 typedef uint32_t sysinterval_t;
122 #elif CH_CFG_INTERVALS_SIZE == 16
123 typedef uint16_t sysinterval_t;
124 #endif
125 
126 /**
127  * @brief Type of a time stamp.
128  */
129 typedef uint64_t systimestamp_t;
130 
131 #if (CH_CFG_TIME_TYPES_SIZE == 32) || defined(__DOXYGEN__)
132 /**
133  * @brief Type of seconds.
134  * @note It is selectable in configuration between 16 or 32 bits.
135  */
136 typedef uint32_t time_secs_t;
137 
138 /**
139  * @brief Type of milliseconds.
140  * @note It is selectable in configuration between 16 or 32 bits.
141  */
142 typedef uint32_t time_msecs_t;
143 
144 /**
145  * @brief Type of microseconds.
146  * @note It is selectable in configuration between 16 or 32 bits.
147  */
148 typedef uint32_t time_usecs_t;
149 
150 /**
151  * @brief Type of time conversion variable.
152  * @note This type must have double width than other time types, it is
153  * only used internally for conversions.
154  */
155 typedef uint64_t time_conv_t;
156 
157 #else
158 typedef uint16_t time_secs_t;
159 typedef uint16_t time_msecs_t;
160 typedef uint16_t time_usecs_t;
161 typedef uint32_t time_conv_t;
162 #endif
163 
164 /*===========================================================================*/
165 /* Module macros. */
166 /*===========================================================================*/
167 
168 /**
169  * @name Fast time conversion utilities
170  * @{
171  */
172 /**
173  * @brief Seconds to time interval.
174  * @details Converts from seconds to system ticks number.
175  * @note The result is rounded upward to the next tick boundary.
176  * @note Use of this macro for large values is not secure because
177  * integer overflows, make sure your value can be correctly
178  * converted.
179  *
180  * @param[in] secs number of seconds
181  * @return The number of ticks.
182  *
183  * @api
184  */
185 #define TIME_S2I(secs) \
186  ((sysinterval_t)((time_conv_t)(secs) * (time_conv_t)CH_CFG_ST_FREQUENCY))
187 
188 /**
189  * @brief Milliseconds to time interval.
190  * @details Converts from milliseconds to system ticks number.
191  * @note The result is rounded upward to the next tick boundary.
192  * @note Use of this macro for large values is not secure because
193  * integer overflows, make sure your value can be correctly
194  * converted.
195  *
196  * @param[in] msecs number of milliseconds
197  * @return The number of ticks.
198  *
199  * @api
200  */
201 #define TIME_MS2I(msecs) \
202  ((sysinterval_t)((((time_conv_t)(msecs) * \
203  (time_conv_t)CH_CFG_ST_FREQUENCY) + \
204  (time_conv_t)999) / (time_conv_t)1000))
205 
206 /**
207  * @brief Microseconds to time interval.
208  * @details Converts from microseconds to system ticks number.
209  * @note The result is rounded upward to the next tick boundary.
210  * @note Use of this macro for large values is not secure because
211  * integer overflows, make sure your value can be correctly
212  * converted.
213  *
214  * @param[in] usecs number of microseconds
215  * @return The number of ticks.
216  *
217  * @api
218  */
219 #define TIME_US2I(usecs) \
220  ((sysinterval_t)((((time_conv_t)(usecs) * \
221  (time_conv_t)CH_CFG_ST_FREQUENCY) + \
222  (time_conv_t)999999) / (time_conv_t)1000000))
223 
224 /**
225  * @brief Time interval to seconds.
226  * @details Converts from system ticks number to seconds.
227  * @note The result is rounded up to the next second boundary.
228  * @note Use of this macro for large values is not secure because
229  * integer overflows, make sure your value can be correctly
230  * converted.
231  *
232  * @param[in] interval interval in ticks
233  * @return The number of seconds.
234  *
235  * @api
236  */
237 #define TIME_I2S(interval) \
238  (time_secs_t)(((time_conv_t)(interval) + \
239  (time_conv_t)CH_CFG_ST_FREQUENCY - \
240  (time_conv_t)1) / (time_conv_t)CH_CFG_ST_FREQUENCY)
241 
242 /**
243  * @brief Time interval to milliseconds.
244  * @details Converts from system ticks number to milliseconds.
245  * @note The result is rounded up to the next millisecond boundary.
246  * @note Use of this macro for large values is not secure because
247  * integer overflows, make sure your value can be correctly
248  * converted.
249  *
250  * @param[in] interval interval in ticks
251  * @return The number of milliseconds.
252  *
253  * @api
254  */
255 #define TIME_I2MS(interval) \
256  (time_msecs_t)((((time_conv_t)(interval) * (time_conv_t)1000) + \
257  (time_conv_t)CH_CFG_ST_FREQUENCY - (time_conv_t)1) / \
258  (time_conv_t)CH_CFG_ST_FREQUENCY)
259 
260 /**
261  * @brief Time interval to microseconds.
262  * @details Converts from system ticks number to microseconds.
263  * @note The result is rounded up to the next microsecond boundary.
264  * @note Use of this macro for large values is not secure because
265  * integer overflows, make sure your value can be correctly
266  * converted.
267  *
268  * @param[in] interval interval in ticks
269  * @return The number of microseconds.
270  *
271  * @api
272  */
273 #define TIME_I2US(interval) \
274  (time_msecs_t)((((time_conv_t)(interval) * (time_conv_t)1000000) + \
275  (time_conv_t)CH_CFG_ST_FREQUENCY - (time_conv_t)1) / \
276  (time_conv_t)CH_CFG_ST_FREQUENCY)
277 /** @} */
278 
279 /*===========================================================================*/
280 /* External declarations. */
281 /*===========================================================================*/
282 
283 #ifdef __cplusplus
284 extern "C" {
285 #endif
286 
287 #ifdef __cplusplus
288 }
289 #endif
290 
291 /*===========================================================================*/
292 /* Module inline functions. */
293 /*===========================================================================*/
294 
295 /**
296  * @name Secure time conversion utilities
297  * @{
298  */
299 /**
300  * @brief Seconds to time interval.
301  * @details Converts from seconds to system ticks number.
302  * @note The result is rounded upward to the next tick boundary.
303  *
304  * @param[in] secs number of seconds
305  * @return The number of ticks.
306  *
307  * @special
308  */
309 static inline sysinterval_t chTimeS2I(time_secs_t secs) {
310  time_conv_t ticks;
311 
313 
315  "conversion overflow");
316 
317  return (sysinterval_t)ticks;
318 }
319 
320 /**
321  * @brief Milliseconds to time interval.
322  * @details Converts from milliseconds to system ticks number.
323  * @note The result is rounded upward to the next tick boundary.
324  *
325  * @param[in] msec number of milliseconds
326  * @return The number of ticks.
327  *
328  * @special
329  */
330 static inline sysinterval_t chTimeMS2I(time_msecs_t msec) {
331  time_conv_t ticks;
332 
333  ticks = (((time_conv_t)msec * (time_conv_t)CH_CFG_ST_FREQUENCY) +
334  (time_conv_t)999) / (time_conv_t)1000;
335 
337  "conversion overflow");
338 
339  return (sysinterval_t)ticks;
340 }
341 
342 /**
343  * @brief Microseconds to time interval.
344  * @details Converts from microseconds to system ticks number.
345  * @note The result is rounded upward to the next tick boundary.
346  *
347  * @param[in] usec number of microseconds
348  * @return The number of ticks.
349  *
350  * @special
351  */
352 static inline sysinterval_t chTimeUS2I(time_usecs_t usec) {
353  time_conv_t ticks;
354 
355  ticks = (((time_conv_t)usec * (time_conv_t)CH_CFG_ST_FREQUENCY) +
356  (time_conv_t)999999) / (time_conv_t)1000000;
357 
359  "conversion overflow");
360 
361  return (sysinterval_t)ticks;
362 }
363 
364 /**
365  * @brief Time interval to seconds.
366  * @details Converts from system interval to seconds.
367  * @note The result is rounded up to the next second boundary.
368  *
369  * @param[in] interval interval in ticks
370  * @return The number of seconds.
371  *
372  * @special
373  */
374 static inline time_secs_t chTimeI2S(sysinterval_t interval) {
375  time_conv_t secs;
376 
377  secs = ((time_conv_t)interval +
380 
381  chDbgAssert(secs < (time_conv_t)((time_secs_t)-1),
382  "conversion overflow");
383 
384  return (time_secs_t)secs;
385 }
386 
387 /**
388  * @brief Time interval to milliseconds.
389  * @details Converts from system interval to milliseconds.
390  * @note The result is rounded up to the next millisecond boundary.
391  *
392  * @param[in] interval interval in ticks
393  * @return The number of milliseconds.
394  *
395  * @special
396  */
397 static inline time_msecs_t chTimeI2MS(sysinterval_t interval) {
398  time_conv_t msecs;
399 
400  msecs = (((time_conv_t)interval * (time_conv_t)1000) +
403 
404  chDbgAssert(msecs < (time_conv_t)((time_msecs_t)-1),
405  "conversion overflow");
406 
407  return (time_msecs_t)msecs;
408 }
409 
410 /**
411  * @brief Time interval to microseconds.
412  * @details Converts from system interval to microseconds.
413  * @note The result is rounded up to the next microsecond boundary.
414  *
415  * @param[in] interval interval in ticks
416  * @return The number of microseconds.
417  *
418  * @special
419  */
420 static inline time_usecs_t chTimeI2US(sysinterval_t interval) {
421  time_conv_t usecs;
422 
423  usecs = (((time_conv_t)interval * (time_conv_t)1000000) +
426 
427  chDbgAssert(usecs <= (time_conv_t)((time_usecs_t)-1),
428  "conversion overflow");
429 
430  return (time_usecs_t)usecs;
431 }
432 
433 /**
434  * @brief Adds an interval to a system time returning a system time.
435  *
436  * @param[in] systime base system time
437  * @param[in] interval interval to be added
438  * @return The new system time.
439  *
440  * @xclass
441  */
442 static inline systime_t chTimeAddX(systime_t systime,
443  sysinterval_t interval) {
444 
445 #if CH_CFG_ST_RESOLUTION != CH_CFG_INTERVALS_SIZE
447 #endif
448 
449  return systime + (systime_t)interval;
450 }
451 
452 /**
453  * @brief Subtracts two system times returning an interval.
454  *
455  * @param[in] start first system time
456  * @param[in] end second system time
457  * @return The interval representing the time difference.
458  *
459  * @xclass
460  */
461 static inline sysinterval_t chTimeDiffX(systime_t start, systime_t end) {
462 
463  /*lint -save -e9033 [10.8] This cast is required by the operation, it is
464  known that the destination type can be wider.*/
465  return (sysinterval_t)((systime_t)(end - start));
466  /*lint -restore*/
467 }
468 
469 /**
470  * @brief Checks if the specified time is within the specified time range.
471  * @note When start==end then the function returns always false because the
472  * time window has zero size.
473  *
474  * @param[in] time the time to be verified
475  * @param[in] start the start of the time window (inclusive)
476  * @param[in] end the end of the time window (non inclusive)
477  * @retval true if the current time is within the specified
478  * time window.
479  * @retval false if the current time is not within the specified
480  * time window.
481  *
482  * @xclass
483  */
484 static inline bool chTimeIsInRangeX(systime_t time,
485  systime_t start,
486  systime_t end) {
487 
488  return (bool)((systime_t)((systime_t)time - (systime_t)start) <
489  (systime_t)((systime_t)end - (systime_t)start));
490 }
491 
492 /**
493  * @brief Adds an interval to a time stamp returning a time stamp.
494  *
495  * @param[in] stamp base time stamp
496  * @param[in] interval interval to be added
497  * @return The new time stamp.
498  *
499  * @xclass
500  */
502  sysinterval_t interval) {
503 
504  return stamp + (systimestamp_t)interval;
505 }
506 
507 /**
508  * @brief Subtracts two time stamps returning an interval.
509  * @note Intervals can then be used for converting in absolute time.
510  *
511  * @param[in] start first time stamp
512  * @param[in] end second time stamp
513  * @return The interval representing the time stamps difference.
514  *
515  * @xclass
516  */
518  systimestamp_t end) {
519  systimestamp_t diff;
520 
521  /* Time difference as a wide time stamp.*/
522  diff = end - start;
523 
525  "conversion overflow");
526 
527  /*lint -save -e9033 [10.8] This cast is required by the operation, it is
528  known that the destination type can be wider.*/
529  return (sysinterval_t)diff;
530  /*lint -restore*/
531 }
532 
533 /**
534  * @brief Checks if the specified time stamp is within the specified time
535  * stamps range.
536  * @note When start==end then the function returns always false because the
537  * time window has zero size.
538  *
539  * @param[in] stamp the time stamp to be verified
540  * @param[in] start the start of the time stamp window (inclusive)
541  * @param[in] end the end of the time stamp window (non inclusive)
542  * @retval true if the current time stamp is within the specified
543  * time stamp window.
544  * @retval false if the current time stamp is not within the specified
545  * time stamp window.
546  *
547  * @xclass
548  */
549 static inline bool chTimeStampIsInRangeX(systimestamp_t stamp,
550  systimestamp_t start,
551  systimestamp_t end) {
552 
553  return (bool)((systimestamp_t)((systimestamp_t)stamp - (systimestamp_t)start) <
554  (systimestamp_t)((systimestamp_t)end - (systimestamp_t)start));
555 }
556 /** @} */
557 
558 #endif /* CHTIME_H */
559 
560 /** @} */
time_secs_t
uint32_t time_secs_t
Type of seconds.
Definition: chtime.h:136
systime_t
uint64_t systime_t
Type of system time.
Definition: chtime.h:107
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:144
time_usecs_t
uint32_t time_usecs_t
Type of microseconds.
Definition: chtime.h:148
chTimeDiffX
static sysinterval_t chTimeDiffX(systime_t start, systime_t end)
Subtracts two system times returning an interval.
Definition: chtime.h:461
systimestamp_t
uint64_t systimestamp_t
Type of a time stamp.
Definition: chtime.h:129
CH_CFG_ST_FREQUENCY
#define CH_CFG_ST_FREQUENCY
System tick frequency.
Definition: rt/templates/chconf.h:75
chTimeMS2I
static sysinterval_t chTimeMS2I(time_msecs_t msec)
Milliseconds to time interval.
Definition: chtime.h:330
TIME_MAX_INTERVAL
#define TIME_MAX_INTERVAL
Maximum interval constant usable as timeout.
Definition: chtime.h:60
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:118
chTimeI2S
static time_secs_t chTimeI2S(sysinterval_t interval)
Time interval to seconds.
Definition: chtime.h:374
chTimeUS2I
static sysinterval_t chTimeUS2I(time_usecs_t usec)
Microseconds to time interval.
Definition: chtime.h:352
chTimeAddX
static systime_t chTimeAddX(systime_t systime, sysinterval_t interval)
Adds an interval to a system time returning a system time.
Definition: chtime.h:442
chTimeI2MS
static time_msecs_t chTimeI2MS(sysinterval_t interval)
Time interval to milliseconds.
Definition: chtime.h:397
chTimeI2US
static time_usecs_t chTimeI2US(sysinterval_t interval)
Time interval to microseconds.
Definition: chtime.h:420
chTimeStampDiffX
static sysinterval_t chTimeStampDiffX(systimestamp_t start, systimestamp_t end)
Subtracts two time stamps returning an interval.
Definition: chtime.h:517
time_msecs_t
uint32_t time_msecs_t
Type of milliseconds.
Definition: chtime.h:142
chTimeStampAddX
static systimestamp_t chTimeStampAddX(systimestamp_t stamp, sysinterval_t interval)
Adds an interval to a time stamp returning a time stamp.
Definition: chtime.h:501
sysinterval_t
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
TIME_MAX_SYSTIME
#define TIME_MAX_SYSTIME
Maximum system of system time before it wraps.
Definition: chtime.h:65
time_conv_t
uint64_t time_conv_t
Type of time conversion variable.
Definition: chtime.h:155
chTimeS2I
static sysinterval_t chTimeS2I(time_secs_t secs)
Seconds to time interval.
Definition: chtime.h:309
chTimeStampIsInRangeX
static bool chTimeStampIsInRangeX(systimestamp_t stamp, systimestamp_t start, systimestamp_t end)
Checks if the specified time stamp is within the specified time stamps range.
Definition: chtime.h:549
chTimeIsInRangeX
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:484