123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- /*
- ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
- This file is part of ChibiOS.
- ChibiOS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- ChibiOS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /**
- * @file chvt.h
- * @brief Time and Virtual Timers module macros and structures.
- *
- * @addtogroup time
- * @{
- */
- #ifndef CHVT_H
- #define CHVT_H
- /*===========================================================================*/
- /* Module constants. */
- /*===========================================================================*/
- /*===========================================================================*/
- /* Module pre-compile time settings. */
- /*===========================================================================*/
- /*===========================================================================*/
- /* Derived constants and error checks. */
- /*===========================================================================*/
- #if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1)
- #error "invalid CH_CFG_ST_TIMEDELTA specified, must " \
- "be zero or greater than one"
- #endif
- //#if (CH_CFG_ST_TIMEDELTA > 0) && (CH_CFG_TIME_QUANTUM > 0)
- //#error "CH_CFG_TIME_QUANTUM not supported in tickless mode"
- //#endif
- #if (CH_CFG_ST_TIMEDELTA > 0) && (CH_DBG_THREADS_PROFILING == TRUE)
- #error "CH_DBG_THREADS_PROFILING not supported in tickless mode"
- #endif
- /*===========================================================================*/
- /* Module data structures and types. */
- /*===========================================================================*/
- /*===========================================================================*/
- /* Module macros. */
- /*===========================================================================*/
- /*===========================================================================*/
- /* External declarations. */
- /*===========================================================================*/
- /*
- * Virtual Timers APIs.
- */
- #ifdef __cplusplus
- extern "C" {
- #endif
- void _vt_init(void);
- void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay,
- vtfunc_t vtfunc, void *par);
- void chVTDoResetI(virtual_timer_t *vtp);
- #ifdef __cplusplus
- }
- #endif
- /*===========================================================================*/
- /* Module inline functions. */
- /*===========================================================================*/
- /**
- * @brief Initializes a @p virtual_timer_t object.
- * @note Initializing a timer object is not strictly required because
- * the function @p chVTSetI() initializes the object too. This
- * function is only useful if you need to perform a @p chVTIsArmed()
- * check before calling @p chVTSetI().
- *
- * @param[out] vtp the @p virtual_timer_t structure pointer
- *
- * @init
- */
- static inline void chVTObjectInit(virtual_timer_t *vtp) {
- vtp->func = NULL;
- }
- /**
- * @brief Current system time.
- * @details Returns the number of system ticks since the @p chSysInit()
- * invocation.
- * @note The counter can reach its maximum and then restart from zero.
- * @note This function can be called from any context but its atomicity
- * is not guaranteed on architectures whose word size is less than
- * @p systime_t size.
- *
- * @return The system time in ticks.
- *
- * @xclass
- */
- static inline systime_t chVTGetSystemTimeX(void) {
- #if CH_CFG_ST_TIMEDELTA == 0
- return ch.vtlist.systime;
- #else /* CH_CFG_ST_TIMEDELTA > 0 */
- return port_timer_get_time();
- #endif /* CH_CFG_ST_TIMEDELTA > 0 */
- }
- /**
- * @brief Current system time.
- * @details Returns the number of system ticks since the @p chSysInit()
- * invocation.
- * @note The counter can reach its maximum and then restart from zero.
- *
- * @return The system time in ticks.
- *
- * @api
- */
- static inline systime_t chVTGetSystemTime(void) {
- systime_t systime;
- chSysLock();
- systime = chVTGetSystemTimeX();
- chSysUnlock();
- return systime;
- }
- /**
- * @brief Returns the elapsed time since the specified start time.
- *
- * @param[in] start start time
- * @return The elapsed time.
- *
- * @xclass
- */
- static inline sysinterval_t chVTTimeElapsedSinceX(systime_t start) {
- return chTimeDiffX(start, chVTGetSystemTimeX());
- }
- /**
- * @brief Checks if the current system time is within the specified time
- * window.
- * @note When start==end then the function returns always true because the
- * whole time range is specified.
- *
- * @param[in] start the start of the time window (inclusive)
- * @param[in] end the end of the time window (non inclusive)
- * @retval true current time within the specified time window.
- * @retval false current time not within the specified time window.
- *
- * @xclass
- */
- static inline bool chVTIsSystemTimeWithinX(systime_t start, systime_t end) {
- return chTimeIsInRangeX(chVTGetSystemTimeX(), start, end);
- }
- /**
- * @brief Checks if the current system time is within the specified time
- * window.
- * @note When start==end then the function returns always true because the
- * whole time range is specified.
- *
- * @param[in] start the start of the time window (inclusive)
- * @param[in] end the end of the time window (non inclusive)
- * @retval true current time within the specified time window.
- * @retval false current time not within the specified time window.
- *
- * @api
- */
- static inline bool chVTIsSystemTimeWithin(systime_t start, systime_t end) {
- return chTimeIsInRangeX(chVTGetSystemTime(), start, end);
- }
- /**
- * @brief Returns the time interval until the next timer event.
- * @note The return value is not perfectly accurate and can report values
- * in excess of @p CH_CFG_ST_TIMEDELTA ticks.
- * @note The interval returned by this function is only meaningful if
- * more timers are not added to the list until the returned time.
- *
- * @param[out] timep pointer to a variable that will contain the time
- * interval until the next timer elapses. This pointer
- * can be @p NULL if the information is not required.
- * @return The time, in ticks, until next time event.
- * @retval false if the timers list is empty.
- * @retval true if the timers list contains at least one timer.
- *
- * @iclass
- */
- static inline bool chVTGetTimersStateI(sysinterval_t *timep) {
- chDbgCheckClassI();
- if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
- return false;
- }
- if (timep != NULL) {
- #if CH_CFG_ST_TIMEDELTA == 0
- *timep = ch.vtlist.next->delta;
- #else
- *timep = chTimeDiffX(chVTGetSystemTimeX(),
- chTimeAddX(ch.vtlist.lasttime,
- ch.vtlist.next->delta +
- (sysinterval_t)CH_CFG_ST_TIMEDELTA));
- #endif
- }
- return true;
- }
- /**
- * @brief Returns @p true if the specified timer is armed.
- * @pre The timer must have been initialized using @p chVTObjectInit()
- * or @p chVTDoSetI().
- *
- * @param[in] vtp the @p virtual_timer_t structure pointer
- * @return true if the timer is armed.
- *
- * @iclass
- */
- static inline bool chVTIsArmedI(const virtual_timer_t *vtp) {
- chDbgCheckClassI();
- return (bool)(vtp->func != NULL);
- }
- /**
- * @brief Returns @p true if the specified timer is armed.
- * @pre The timer must have been initialized using @p chVTObjectInit()
- * or @p chVTDoSetI().
- *
- * @param[in] vtp the @p virtual_timer_t structure pointer
- * @return true if the timer is armed.
- *
- * @api
- */
- static inline bool chVTIsArmed(const virtual_timer_t *vtp) {
- bool b;
- chSysLock();
- b = chVTIsArmedI(vtp);
- chSysUnlock();
- return b;
- }
- /**
- * @brief Disables a Virtual Timer.
- * @note The timer is first checked and disabled only if armed.
- * @pre The timer must have been initialized using @p chVTObjectInit()
- * or @p chVTDoSetI().
- *
- * @param[in] vtp the @p virtual_timer_t structure pointer
- *
- * @iclass
- */
- static inline void chVTResetI(virtual_timer_t *vtp) {
- if (chVTIsArmedI(vtp)) {
- chVTDoResetI(vtp);
- }
- }
- /**
- * @brief Disables a Virtual Timer.
- * @note The timer is first checked and disabled only if armed.
- * @pre The timer must have been initialized using @p chVTObjectInit()
- * or @p chVTDoSetI().
- *
- * @param[in] vtp the @p virtual_timer_t structure pointer
- *
- * @api
- */
- static inline void chVTReset(virtual_timer_t *vtp) {
- chSysLock();
- chVTResetI(vtp);
- chSysUnlock();
- }
- /**
- * @brief Enables a virtual timer.
- * @details If the virtual timer was already enabled then it is re-enabled
- * using the new parameters.
- * @pre The timer must have been initialized using @p chVTObjectInit()
- * or @p chVTDoSetI().
- *
- * @param[in] vtp the @p virtual_timer_t structure pointer
- * @param[in] delay the number of ticks before the operation timeouts, the
- * special values are handled as follow:
- * - @a TIME_INFINITE is allowed but interpreted as a
- * normal time specification.
- * - @a TIME_IMMEDIATE this value is not allowed.
- * .
- * @param[in] vtfunc the timer callback function. After invoking the
- * callback the timer is disabled and the structure can
- * be disposed or reused.
- * @param[in] par a parameter that will be passed to the callback
- * function
- *
- * @iclass
- */
- static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay,
- vtfunc_t vtfunc, void *par) {
- chVTResetI(vtp);
- chVTDoSetI(vtp, delay, vtfunc, par);
- }
- /**
- * @brief Enables a virtual timer.
- * @details If the virtual timer was already enabled then it is re-enabled
- * using the new parameters.
- * @pre The timer must have been initialized using @p chVTObjectInit()
- * or @p chVTDoSetI().
- *
- * @param[in] vtp the @p virtual_timer_t structure pointer
- * @param[in] delay the number of ticks before the operation timeouts, the
- * special values are handled as follow:
- * - @a TIME_INFINITE is allowed but interpreted as a
- * normal time specification.
- * - @a TIME_IMMEDIATE this value is not allowed.
- * .
- * @param[in] vtfunc the timer callback function. After invoking the
- * callback the timer is disabled and the structure can
- * be disposed or reused.
- * @param[in] par a parameter that will be passed to the callback
- * function
- *
- * @api
- */
- static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay,
- vtfunc_t vtfunc, void *par) {
- chSysLock();
- chVTSetI(vtp, delay, vtfunc, par);
- chSysUnlock();
- }
- /**
- * @brief Virtual timers ticker.
- * @note The system lock is released before entering the callback and
- * re-acquired immediately after. It is callback's responsibility
- * to acquire the lock if needed. This is done in order to reduce
- * interrupts jitter when many timers are in use.
- *
- * @iclass
- */
- static inline void chVTDoTickI(void) {
- chDbgCheckClassI();
- #if CH_CFG_ST_TIMEDELTA == 0
- ch.vtlist.systime++;
- if (&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.next) {
- /* The list is not empty, processing elements on top.*/
- --ch.vtlist.next->delta;
- while (ch.vtlist.next->delta == (sysinterval_t)0) {
- virtual_timer_t *vtp;
- vtfunc_t fn;
- vtp = ch.vtlist.next;
- fn = vtp->func;
- vtp->func = NULL;
- vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
- ch.vtlist.next = vtp->next;
- chSysUnlockFromISR();
- fn(vtp->par);
- chSysLockFromISR();
- }
- }
- #else /* CH_CFG_ST_TIMEDELTA > 0 */
- virtual_timer_t *vtp;
- systime_t now;
- sysinterval_t delta, nowdelta;
- /* Looping through timers.*/
- vtp = ch.vtlist.next;
- while (true) {
- /* Getting the system time as reference.*/
- now = chVTGetSystemTimeX();
- nowdelta = chTimeDiffX(ch.vtlist.lasttime, now);
- /* The list scan is limited by the timers header having
- "ch.vtlist.vt_delta == (sysinterval_t)-1" which is
- greater than all deltas.*/
- if (nowdelta < vtp->delta) {
- break;
- }
- /* Consuming all timers between "vtp->lasttime" and now.*/
- do {
- vtfunc_t fn;
- /* The "last time" becomes this timer's expiration time.*/
- ch.vtlist.lasttime += vtp->delta;
- nowdelta -= vtp->delta;
- vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
- ch.vtlist.next = vtp->next;
- fn = vtp->func;
- vtp->func = NULL;
- /* if the list becomes empty then the timer is stopped.*/
- if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
- port_timer_stop_alarm();
- }
- /* The callback is invoked outside the kernel critical zone.*/
- chSysUnlockFromISR();
- fn(vtp->par);
- chSysLockFromISR();
- /* Next element in the list.*/
- vtp = ch.vtlist.next;
- }
- while (vtp->delta <= nowdelta);
- }
- /* if the list is empty, nothing else to do.*/
- if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
- return;
- }
- /* The "unprocessed nowdelta" time slice is added to "last time"
- and subtracted to next timer's delta.*/
- ch.vtlist.lasttime += nowdelta;
- ch.vtlist.next->delta -= nowdelta;
- /* Recalculating the next alarm time.*/
- delta = chTimeDiffX(now, chTimeAddX(ch.vtlist.lasttime, vtp->delta));
- if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
- delta = (sysinterval_t)CH_CFG_ST_TIMEDELTA;
- }
- #if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION
- /* The delta could be too large for the physical timer to handle.*/
- else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) {
- delta = (sysinterval_t)TIME_MAX_SYSTIME;
- }
- #endif
- port_timer_set_alarm(chTimeAddX(now, delta));
- chDbgAssert(chTimeDiffX(ch.vtlist.lasttime, chVTGetSystemTimeX()) <=
- chTimeDiffX(ch.vtlist.lasttime, chTimeAddX(now, delta)),
- "exceeding delta");
- #endif /* CH_CFG_ST_TIMEDELTA > 0 */
- }
- #endif /* CHVT_H */
- /** @} */
|