chvt.h 15 KB

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