os_tmr.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * TIMER MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2013, Micrium, Weston, FL
  8. * All Rights Reserved
  9. *
  10. *
  11. * File : OS_TMR.C
  12. * By : Jean J. Labrosse
  13. * Version : V2.92.11
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. * uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
  18. * If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license
  19. * its use in your product. We provide ALL the source code for your convenience and to help you experience
  20. * uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
  21. * licensing fee.
  22. *********************************************************************************************************
  23. */
  24. #define MICRIUM_SOURCE
  25. #ifndef OS_MASTER_FILE
  26. #include <ucos_ii.h>
  27. #endif
  28. /*
  29. *********************************************************************************************************
  30. * NOTES
  31. *
  32. * 1) Your application MUST define the following #define constants:
  33. *
  34. * OS_TASK_TMR_PRIO The priority of the Timer management task
  35. * OS_TASK_TMR_STK_SIZE The size of the Timer management task's stack
  36. *
  37. * 2) You must call OSTmrSignal() to notify the Timer management task that it's time to update the timers.
  38. *********************************************************************************************************
  39. */
  40. /*
  41. *********************************************************************************************************
  42. * CONSTANTS
  43. *********************************************************************************************************
  44. */
  45. #define OS_TMR_LINK_DLY 0u
  46. #define OS_TMR_LINK_PERIODIC 1u
  47. /*
  48. *********************************************************************************************************
  49. * LOCAL PROTOTYPES
  50. *********************************************************************************************************
  51. */
  52. #if OS_TMR_EN > 0u
  53. static OS_TMR *OSTmr_Alloc (void);
  54. static void OSTmr_Free (OS_TMR *ptmr);
  55. static void OSTmr_InitTask (void);
  56. static void OSTmr_Link (OS_TMR *ptmr, INT8U type);
  57. static void OSTmr_Unlink (OS_TMR *ptmr);
  58. static void OSTmr_Task (void *p_arg);
  59. #endif
  60. /*$PAGE*/
  61. /*
  62. *********************************************************************************************************
  63. * CREATE A TIMER
  64. *
  65. * Description: This function is called by your application code to create a timer.
  66. *
  67. * Arguments : dly Initial delay.
  68. * If the timer is configured for ONE-SHOT mode, this is the timeout used.
  69. * If the timer is configured for PERIODIC mode, this is the first timeout to
  70. * wait for before the timer starts entering periodic mode.
  71. *
  72. * period The 'period' being repeated for the timer.
  73. * If you specified 'OS_TMR_OPT_PERIODIC' as an option, when the timer
  74. * expires, it will automatically restart with the same period.
  75. *
  76. * opt Specifies either:
  77. * OS_TMR_OPT_ONE_SHOT The timer counts down only once
  78. * OS_TMR_OPT_PERIODIC The timer counts down and then reloads itself
  79. *
  80. * callback Is a pointer to a callback function that will be called when the timer expires.
  81. * The callback function must be declared as follows:
  82. *
  83. * void MyCallback (OS_TMR *ptmr, void *p_arg);
  84. *
  85. * callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
  86. *
  87. * pname Is a pointer to an ASCII string that is used to name the timer. Names are
  88. * useful for debugging.
  89. *
  90. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  91. * OS_ERR_NONE
  92. * OS_ERR_TMR_INVALID_DLY you specified an invalid delay
  93. * OS_ERR_TMR_INVALID_PERIOD you specified an invalid period
  94. * OS_ERR_TMR_INVALID_OPT you specified an invalid option
  95. * OS_ERR_TMR_ISR if the call was made from an ISR
  96. * OS_ERR_TMR_NON_AVAIL if there are no free timers from the timer pool
  97. *
  98. * Returns : A pointer to an OS_TMR data structure.
  99. * This is the 'handle' that your application will use to reference the timer created.
  100. *********************************************************************************************************
  101. */
  102. #if OS_TMR_EN > 0u
  103. OS_TMR *OSTmrCreate (INT32U dly,
  104. INT32U period,
  105. INT8U opt,
  106. OS_TMR_CALLBACK callback,
  107. void *callback_arg,
  108. INT8U *pname,
  109. INT8U *perr)
  110. {
  111. OS_TMR *ptmr;
  112. #ifdef OS_SAFETY_CRITICAL
  113. if (perr == (INT8U *)0) {
  114. OS_SAFETY_CRITICAL_EXCEPTION();
  115. return ((OS_TMR *)0);
  116. }
  117. #endif
  118. #ifdef OS_SAFETY_CRITICAL_IEC61508
  119. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  120. OS_SAFETY_CRITICAL_EXCEPTION();
  121. return ((OS_TMR *)0);
  122. }
  123. #endif
  124. #if OS_ARG_CHK_EN > 0u
  125. switch (opt) { /* Validate arguments */
  126. case OS_TMR_OPT_PERIODIC:
  127. if (period == 0u) {
  128. *perr = OS_ERR_TMR_INVALID_PERIOD;
  129. return ((OS_TMR *)0);
  130. }
  131. break;
  132. case OS_TMR_OPT_ONE_SHOT:
  133. if (dly == 0u) {
  134. *perr = OS_ERR_TMR_INVALID_DLY;
  135. return ((OS_TMR *)0);
  136. }
  137. break;
  138. default:
  139. *perr = OS_ERR_TMR_INVALID_OPT;
  140. return ((OS_TMR *)0);
  141. }
  142. #endif
  143. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  144. *perr = OS_ERR_TMR_ISR;
  145. return ((OS_TMR *)0);
  146. }
  147. OSSchedLock();
  148. ptmr = OSTmr_Alloc(); /* Obtain a timer from the free pool */
  149. if (ptmr == (OS_TMR *)0) {
  150. OSSchedUnlock();
  151. *perr = OS_ERR_TMR_NON_AVAIL;
  152. return ((OS_TMR *)0);
  153. }
  154. ptmr->OSTmrState = OS_TMR_STATE_STOPPED; /* Indicate that timer is not running yet */
  155. ptmr->OSTmrDly = dly;
  156. ptmr->OSTmrPeriod = period;
  157. ptmr->OSTmrOpt = opt;
  158. ptmr->OSTmrCallback = callback;
  159. ptmr->OSTmrCallbackArg = callback_arg;
  160. #if OS_TMR_CFG_NAME_EN > 0u
  161. if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */
  162. ptmr->OSTmrName = (INT8U *)(void *)"?";
  163. } else {
  164. ptmr->OSTmrName = pname;
  165. }
  166. #endif
  167. OSSchedUnlock();
  168. *perr = OS_ERR_NONE;
  169. return (ptmr);
  170. }
  171. #endif
  172. /*$PAGE*/
  173. /*
  174. *********************************************************************************************************
  175. * DELETE A TIMER
  176. *
  177. * Description: This function is called by your application code to delete a timer.
  178. *
  179. * Arguments : ptmr Is a pointer to the timer to stop and delete.
  180. *
  181. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  182. * OS_ERR_NONE
  183. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  184. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  185. * OS_ERR_TMR_ISR if the function was called from an ISR
  186. * OS_ERR_TMR_INACTIVE if the timer was not created
  187. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  188. *
  189. * Returns : OS_TRUE If the call was successful
  190. * OS_FALSE If not
  191. *********************************************************************************************************
  192. */
  193. #if OS_TMR_EN > 0u
  194. BOOLEAN OSTmrDel (OS_TMR *ptmr,
  195. INT8U *perr)
  196. {
  197. #ifdef OS_SAFETY_CRITICAL
  198. if (perr == (INT8U *)0) {
  199. OS_SAFETY_CRITICAL_EXCEPTION();
  200. return (OS_FALSE);
  201. }
  202. #endif
  203. #if OS_ARG_CHK_EN > 0u
  204. if (ptmr == (OS_TMR *)0) {
  205. *perr = OS_ERR_TMR_INVALID;
  206. return (OS_FALSE);
  207. }
  208. #endif
  209. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  210. *perr = OS_ERR_TMR_INVALID_TYPE;
  211. return (OS_FALSE);
  212. }
  213. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  214. *perr = OS_ERR_TMR_ISR;
  215. return (OS_FALSE);
  216. }
  217. OSSchedLock();
  218. switch (ptmr->OSTmrState) {
  219. case OS_TMR_STATE_RUNNING:
  220. OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
  221. OSTmr_Free(ptmr); /* Return timer to free list of timers */
  222. OSSchedUnlock();
  223. *perr = OS_ERR_NONE;
  224. return (OS_TRUE);
  225. case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
  226. case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
  227. OSTmr_Free(ptmr); /* Return timer to free list of timers */
  228. OSSchedUnlock();
  229. *perr = OS_ERR_NONE;
  230. return (OS_TRUE);
  231. case OS_TMR_STATE_UNUSED: /* Already deleted */
  232. OSSchedUnlock();
  233. *perr = OS_ERR_TMR_INACTIVE;
  234. return (OS_FALSE);
  235. default:
  236. OSSchedUnlock();
  237. *perr = OS_ERR_TMR_INVALID_STATE;
  238. return (OS_FALSE);
  239. }
  240. }
  241. #endif
  242. /*$PAGE*/
  243. /*
  244. *********************************************************************************************************
  245. * GET THE NAME OF A TIMER
  246. *
  247. * Description: This function is called to obtain the name of a timer.
  248. *
  249. * Arguments : ptmr Is a pointer to the timer to obtain the name for
  250. *
  251. * pdest Is a pointer to pointer to where the name of the timer will be placed.
  252. *
  253. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  254. * OS_ERR_NONE The call was successful
  255. * OS_ERR_TMR_INVALID_DEST 'pdest' is a NULL pointer
  256. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  257. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  258. * OS_ERR_NAME_GET_ISR if the call was made from an ISR
  259. * OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
  260. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  261. *
  262. * Returns : The length of the string or 0 if the timer does not exist.
  263. *********************************************************************************************************
  264. */
  265. #if OS_TMR_EN > 0u && OS_TMR_CFG_NAME_EN > 0u
  266. INT8U OSTmrNameGet (OS_TMR *ptmr,
  267. INT8U **pdest,
  268. INT8U *perr)
  269. {
  270. INT8U len;
  271. #ifdef OS_SAFETY_CRITICAL
  272. if (perr == (INT8U *)0) {
  273. OS_SAFETY_CRITICAL_EXCEPTION();
  274. return (0u);
  275. }
  276. #endif
  277. #if OS_ARG_CHK_EN > 0u
  278. if (pdest == (INT8U **)0) {
  279. *perr = OS_ERR_TMR_INVALID_DEST;
  280. return (0u);
  281. }
  282. if (ptmr == (OS_TMR *)0) {
  283. *perr = OS_ERR_TMR_INVALID;
  284. return (0u);
  285. }
  286. #endif
  287. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  288. *perr = OS_ERR_TMR_INVALID_TYPE;
  289. return (0u);
  290. }
  291. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  292. *perr = OS_ERR_NAME_GET_ISR;
  293. return (0u);
  294. }
  295. OSSchedLock();
  296. switch (ptmr->OSTmrState) {
  297. case OS_TMR_STATE_RUNNING:
  298. case OS_TMR_STATE_STOPPED:
  299. case OS_TMR_STATE_COMPLETED:
  300. *pdest = ptmr->OSTmrName;
  301. len = OS_StrLen(*pdest);
  302. OSSchedUnlock();
  303. *perr = OS_ERR_NONE;
  304. return (len);
  305. case OS_TMR_STATE_UNUSED: /* Timer is not allocated */
  306. OSSchedUnlock();
  307. *perr = OS_ERR_TMR_INACTIVE;
  308. return (0u);
  309. default:
  310. OSSchedUnlock();
  311. *perr = OS_ERR_TMR_INVALID_STATE;
  312. return (0u);
  313. }
  314. }
  315. #endif
  316. /*$PAGE*/
  317. /*
  318. *********************************************************************************************************
  319. * GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
  320. *
  321. * Description: This function is called to get the number of ticks before a timer times out.
  322. *
  323. * Arguments : ptmr Is a pointer to the timer to obtain the remaining time from.
  324. *
  325. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  326. * OS_ERR_NONE
  327. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  328. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  329. * OS_ERR_TMR_ISR if the call was made from an ISR
  330. * OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
  331. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  332. *
  333. * Returns : The time remaining for the timer to expire. The time represents 'timer' increments.
  334. * In other words, if OSTmr_Task() is signaled every 1/10 of a second then the returned
  335. * value represents the number of 1/10 of a second remaining before the timer expires.
  336. *********************************************************************************************************
  337. */
  338. #if OS_TMR_EN > 0u
  339. INT32U OSTmrRemainGet (OS_TMR *ptmr,
  340. INT8U *perr)
  341. {
  342. INT32U remain;
  343. #ifdef OS_SAFETY_CRITICAL
  344. if (perr == (INT8U *)0) {
  345. OS_SAFETY_CRITICAL_EXCEPTION();
  346. return (0u);
  347. }
  348. #endif
  349. #if OS_ARG_CHK_EN > 0u
  350. if (ptmr == (OS_TMR *)0) {
  351. *perr = OS_ERR_TMR_INVALID;
  352. return (0u);
  353. }
  354. #endif
  355. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  356. *perr = OS_ERR_TMR_INVALID_TYPE;
  357. return (0u);
  358. }
  359. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  360. *perr = OS_ERR_TMR_ISR;
  361. return (0u);
  362. }
  363. OSSchedLock();
  364. switch (ptmr->OSTmrState) {
  365. case OS_TMR_STATE_RUNNING:
  366. remain = ptmr->OSTmrMatch - OSTmrTime; /* Determine how much time is left to timeout */
  367. OSSchedUnlock();
  368. *perr = OS_ERR_NONE;
  369. return (remain);
  370. case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
  371. switch (ptmr->OSTmrOpt) {
  372. case OS_TMR_OPT_PERIODIC:
  373. if (ptmr->OSTmrDly == 0u) {
  374. remain = ptmr->OSTmrPeriod;
  375. } else {
  376. remain = ptmr->OSTmrDly;
  377. }
  378. OSSchedUnlock();
  379. *perr = OS_ERR_NONE;
  380. break;
  381. case OS_TMR_OPT_ONE_SHOT:
  382. default:
  383. remain = ptmr->OSTmrDly;
  384. OSSchedUnlock();
  385. *perr = OS_ERR_NONE;
  386. break;
  387. }
  388. return (remain);
  389. case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT that timed out can be in this state */
  390. OSSchedUnlock();
  391. *perr = OS_ERR_NONE;
  392. return (0u);
  393. case OS_TMR_STATE_UNUSED:
  394. OSSchedUnlock();
  395. *perr = OS_ERR_TMR_INACTIVE;
  396. return (0u);
  397. default:
  398. OSSchedUnlock();
  399. *perr = OS_ERR_TMR_INVALID_STATE;
  400. return (0u);
  401. }
  402. }
  403. #endif
  404. /*$PAGE*/
  405. /*
  406. *********************************************************************************************************
  407. * FIND OUT WHAT STATE A TIMER IS IN
  408. *
  409. * Description: This function is called to determine what state the timer is in:
  410. *
  411. * OS_TMR_STATE_UNUSED the timer has not been created
  412. * OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped
  413. * OS_TMR_STATE_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout
  414. * OS_TMR_STATE_RUNNING the timer is currently running
  415. *
  416. * Arguments : ptmr Is a pointer to the desired timer
  417. *
  418. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  419. * OS_ERR_NONE
  420. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  421. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  422. * OS_ERR_TMR_ISR if the call was made from an ISR
  423. * OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
  424. * OS_ERR_TMR_INVALID_STATE if the timer is not in a valid state
  425. *
  426. * Returns : The current state of the timer (see description).
  427. *********************************************************************************************************
  428. */
  429. #if OS_TMR_EN > 0u
  430. INT8U OSTmrStateGet (OS_TMR *ptmr,
  431. INT8U *perr)
  432. {
  433. INT8U state;
  434. #ifdef OS_SAFETY_CRITICAL
  435. if (perr == (INT8U *)0) {
  436. OS_SAFETY_CRITICAL_EXCEPTION();
  437. return (0u);
  438. }
  439. #endif
  440. #if OS_ARG_CHK_EN > 0u
  441. if (ptmr == (OS_TMR *)0) {
  442. *perr = OS_ERR_TMR_INVALID;
  443. return (0u);
  444. }
  445. #endif
  446. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  447. *perr = OS_ERR_TMR_INVALID_TYPE;
  448. return (0u);
  449. }
  450. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  451. *perr = OS_ERR_TMR_ISR;
  452. return (0u);
  453. }
  454. OSSchedLock();
  455. state = ptmr->OSTmrState;
  456. switch (state) {
  457. case OS_TMR_STATE_UNUSED:
  458. case OS_TMR_STATE_STOPPED:
  459. case OS_TMR_STATE_COMPLETED:
  460. case OS_TMR_STATE_RUNNING:
  461. *perr = OS_ERR_NONE;
  462. break;
  463. default:
  464. *perr = OS_ERR_TMR_INVALID_STATE;
  465. break;
  466. }
  467. OSSchedUnlock();
  468. return (state);
  469. }
  470. #endif
  471. /*$PAGE*/
  472. /*
  473. *********************************************************************************************************
  474. * START A TIMER
  475. *
  476. * Description: This function is called by your application code to start a timer.
  477. *
  478. * Arguments : ptmr Is a pointer to an OS_TMR
  479. *
  480. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  481. * OS_ERR_NONE
  482. * OS_ERR_TMR_INVALID
  483. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  484. * OS_ERR_TMR_ISR if the call was made from an ISR
  485. * OS_ERR_TMR_INACTIVE if the timer was not created
  486. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  487. *
  488. * Returns : OS_TRUE if the timer was started
  489. * OS_FALSE if an error was detected
  490. *********************************************************************************************************
  491. */
  492. #if OS_TMR_EN > 0u
  493. BOOLEAN OSTmrStart (OS_TMR *ptmr,
  494. INT8U *perr)
  495. {
  496. #ifdef OS_SAFETY_CRITICAL
  497. if (perr == (INT8U *)0) {
  498. OS_SAFETY_CRITICAL_EXCEPTION();
  499. return (OS_FALSE);
  500. }
  501. #endif
  502. #if OS_ARG_CHK_EN > 0u
  503. if (ptmr == (OS_TMR *)0) {
  504. *perr = OS_ERR_TMR_INVALID;
  505. return (OS_FALSE);
  506. }
  507. #endif
  508. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  509. *perr = OS_ERR_TMR_INVALID_TYPE;
  510. return (OS_FALSE);
  511. }
  512. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  513. *perr = OS_ERR_TMR_ISR;
  514. return (OS_FALSE);
  515. }
  516. OSSchedLock();
  517. switch (ptmr->OSTmrState) {
  518. case OS_TMR_STATE_RUNNING: /* Restart the timer */
  519. OSTmr_Unlink(ptmr); /* ... Stop the timer */
  520. OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */
  521. OSSchedUnlock();
  522. *perr = OS_ERR_NONE;
  523. return (OS_TRUE);
  524. case OS_TMR_STATE_STOPPED: /* Start the timer */
  525. case OS_TMR_STATE_COMPLETED:
  526. OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */
  527. OSSchedUnlock();
  528. *perr = OS_ERR_NONE;
  529. return (OS_TRUE);
  530. case OS_TMR_STATE_UNUSED: /* Timer not created */
  531. OSSchedUnlock();
  532. *perr = OS_ERR_TMR_INACTIVE;
  533. return (OS_FALSE);
  534. default:
  535. OSSchedUnlock();
  536. *perr = OS_ERR_TMR_INVALID_STATE;
  537. return (OS_FALSE);
  538. }
  539. }
  540. #endif
  541. /*$PAGE*/
  542. /*
  543. *********************************************************************************************************
  544. * STOP A TIMER
  545. *
  546. * Description: This function is called by your application code to stop a timer.
  547. *
  548. * Arguments : ptmr Is a pointer to the timer to stop.
  549. *
  550. * opt Allows you to specify an option to this functions which can be:
  551. *
  552. * OS_TMR_OPT_NONE Do nothing special but stop the timer
  553. * OS_TMR_OPT_CALLBACK Execute the callback function, pass it the
  554. * callback argument specified when the timer
  555. * was created.
  556. * OS_TMR_OPT_CALLBACK_ARG Execute the callback function, pass it the
  557. * callback argument specified in THIS function call.
  558. *
  559. * callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback
  560. * function instead of the timer's callback argument. In other words, use
  561. * 'callback_arg' passed in THIS function INSTEAD of ptmr->OSTmrCallbackArg.
  562. *
  563. * perr Is a pointer to an error code. '*perr' will contain one of the following:
  564. * OS_ERR_NONE
  565. * OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
  566. * OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
  567. * OS_ERR_TMR_ISR if the function was called from an ISR
  568. * OS_ERR_TMR_INACTIVE if the timer was not created
  569. * OS_ERR_TMR_INVALID_OPT if you specified an invalid option for 'opt'
  570. * OS_ERR_TMR_STOPPED if the timer was already stopped
  571. * OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
  572. * OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined
  573. *
  574. * Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE)
  575. * OS_FALSE If not
  576. *********************************************************************************************************
  577. */
  578. #if OS_TMR_EN > 0u
  579. BOOLEAN OSTmrStop (OS_TMR *ptmr,
  580. INT8U opt,
  581. void *callback_arg,
  582. INT8U *perr)
  583. {
  584. OS_TMR_CALLBACK pfnct;
  585. #ifdef OS_SAFETY_CRITICAL
  586. if (perr == (INT8U *)0) {
  587. OS_SAFETY_CRITICAL_EXCEPTION();
  588. return (OS_FALSE);
  589. }
  590. #endif
  591. #if OS_ARG_CHK_EN > 0u
  592. if (ptmr == (OS_TMR *)0) {
  593. *perr = OS_ERR_TMR_INVALID;
  594. return (OS_FALSE);
  595. }
  596. #endif
  597. if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
  598. *perr = OS_ERR_TMR_INVALID_TYPE;
  599. return (OS_FALSE);
  600. }
  601. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  602. *perr = OS_ERR_TMR_ISR;
  603. return (OS_FALSE);
  604. }
  605. OSSchedLock();
  606. switch (ptmr->OSTmrState) {
  607. case OS_TMR_STATE_RUNNING:
  608. OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
  609. *perr = OS_ERR_NONE;
  610. switch (opt) {
  611. case OS_TMR_OPT_CALLBACK:
  612. pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */
  613. if (pfnct != (OS_TMR_CALLBACK)0) {
  614. (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg); /* Use callback arg when timer was created */
  615. } else {
  616. *perr = OS_ERR_TMR_NO_CALLBACK;
  617. }
  618. break;
  619. case OS_TMR_OPT_CALLBACK_ARG:
  620. pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */
  621. if (pfnct != (OS_TMR_CALLBACK)0) {
  622. (*pfnct)((void *)ptmr, callback_arg); /* ... using the 'callback_arg' provided in call */
  623. } else {
  624. *perr = OS_ERR_TMR_NO_CALLBACK;
  625. }
  626. break;
  627. case OS_TMR_OPT_NONE:
  628. break;
  629. default:
  630. *perr = OS_ERR_TMR_INVALID_OPT;
  631. break;
  632. }
  633. OSSchedUnlock();
  634. return (OS_TRUE);
  635. case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or ... */
  636. case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
  637. OSSchedUnlock();
  638. *perr = OS_ERR_TMR_STOPPED;
  639. return (OS_TRUE);
  640. case OS_TMR_STATE_UNUSED: /* Timer was not created */
  641. OSSchedUnlock();
  642. *perr = OS_ERR_TMR_INACTIVE;
  643. return (OS_FALSE);
  644. default:
  645. OSSchedUnlock();
  646. *perr = OS_ERR_TMR_INVALID_STATE;
  647. return (OS_FALSE);
  648. }
  649. }
  650. #endif
  651. /*$PAGE*/
  652. /*
  653. *********************************************************************************************************
  654. * SIGNAL THAT IT'S TIME TO UPDATE THE TIMERS
  655. *
  656. * Description: This function is typically called by the ISR that occurs at the timer tick rate and is
  657. * used to signal to OSTmr_Task() that it's time to update the timers.
  658. *
  659. * Arguments : none
  660. *
  661. * Returns : OS_ERR_NONE The call was successful and the timer task was signaled.
  662. * OS_ERR_SEM_OVF If OSTmrSignal() was called more often than OSTmr_Task() can handle
  663. * the timers. This would indicate that your system is heavily loaded.
  664. * OS_ERR_EVENT_TYPE Unlikely you would get this error because the semaphore used for
  665. * signaling is created by uC/OS-II.
  666. * OS_ERR_PEVENT_NULL Again, unlikely you would ever get this error because the semaphore
  667. * used for signaling is created by uC/OS-II.
  668. *********************************************************************************************************
  669. */
  670. #if OS_TMR_EN > 0u
  671. INT8U OSTmrSignal (void)
  672. {
  673. INT8U err;
  674. err = OSSemPost(OSTmrSemSignal);
  675. return (err);
  676. }
  677. #endif
  678. /*$PAGE*/
  679. /*
  680. *********************************************************************************************************
  681. * ALLOCATE AND FREE A TIMER
  682. *
  683. * Description: This function is called to allocate a timer.
  684. *
  685. * Arguments : none
  686. *
  687. * Returns : a pointer to a timer if one is available
  688. *********************************************************************************************************
  689. */
  690. #if OS_TMR_EN > 0u
  691. static OS_TMR *OSTmr_Alloc (void)
  692. {
  693. OS_TMR *ptmr;
  694. if (OSTmrFreeList == (OS_TMR *)0) {
  695. return ((OS_TMR *)0);
  696. }
  697. ptmr = (OS_TMR *)OSTmrFreeList;
  698. OSTmrFreeList = (OS_TMR *)ptmr->OSTmrNext;
  699. ptmr->OSTmrNext = (OS_TCB *)0;
  700. ptmr->OSTmrPrev = (OS_TCB *)0;
  701. OSTmrUsed++;
  702. OSTmrFree--;
  703. return (ptmr);
  704. }
  705. #endif
  706. /*
  707. *********************************************************************************************************
  708. * RETURN A TIMER TO THE FREE LIST
  709. *
  710. * Description: This function is called to return a timer object to the free list of timers.
  711. *
  712. * Arguments : ptmr is a pointer to the timer to free
  713. *
  714. * Returns : none
  715. *********************************************************************************************************
  716. */
  717. #if OS_TMR_EN > 0u
  718. static void OSTmr_Free (OS_TMR *ptmr)
  719. {
  720. ptmr->OSTmrState = OS_TMR_STATE_UNUSED; /* Clear timer object fields */
  721. ptmr->OSTmrOpt = OS_TMR_OPT_NONE;
  722. ptmr->OSTmrPeriod = 0u;
  723. ptmr->OSTmrMatch = 0u;
  724. ptmr->OSTmrCallback = (OS_TMR_CALLBACK)0;
  725. ptmr->OSTmrCallbackArg = (void *)0;
  726. #if OS_TMR_CFG_NAME_EN > 0u
  727. ptmr->OSTmrName = (INT8U *)(void *)"?";
  728. #endif
  729. ptmr->OSTmrPrev = (OS_TCB *)0; /* Chain timer to free list */
  730. ptmr->OSTmrNext = OSTmrFreeList;
  731. OSTmrFreeList = ptmr;
  732. OSTmrUsed--; /* Update timer object statistics */
  733. OSTmrFree++;
  734. }
  735. #endif
  736. /*$PAGE*/
  737. /*
  738. *********************************************************************************************************
  739. * INITIALIZATION
  740. * INITIALIZE THE FREE LIST OF TIMERS
  741. *
  742. * Description: This function is called by OSInit() to initialize the free list of OS_TMRs.
  743. *
  744. * Arguments : none
  745. *
  746. * Returns : none
  747. *********************************************************************************************************
  748. */
  749. #if OS_TMR_EN > 0u
  750. void OSTmr_Init (void)
  751. {
  752. #if OS_EVENT_NAME_EN > 0u
  753. INT8U err;
  754. #endif
  755. INT16U ix;
  756. INT16U ix_next;
  757. OS_TMR *ptmr1;
  758. OS_TMR *ptmr2;
  759. OS_MemClr((INT8U *)&OSTmrTbl[0], sizeof(OSTmrTbl)); /* Clear all the TMRs */
  760. OS_MemClr((INT8U *)&OSTmrWheelTbl[0], sizeof(OSTmrWheelTbl)); /* Clear the timer wheel */
  761. for (ix = 0u; ix < (OS_TMR_CFG_MAX - 1u); ix++) { /* Init. list of free TMRs */
  762. ix_next = ix + 1u;
  763. ptmr1 = &OSTmrTbl[ix];
  764. ptmr2 = &OSTmrTbl[ix_next];
  765. ptmr1->OSTmrType = OS_TMR_TYPE;
  766. ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */
  767. ptmr1->OSTmrNext = (void *)ptmr2; /* Link to next timer */
  768. #if OS_TMR_CFG_NAME_EN > 0u
  769. ptmr1->OSTmrName = (INT8U *)(void *)"?";
  770. #endif
  771. }
  772. ptmr1 = &OSTmrTbl[ix];
  773. ptmr1->OSTmrType = OS_TMR_TYPE;
  774. ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */
  775. ptmr1->OSTmrNext = (void *)0; /* Last OS_TMR */
  776. #if OS_TMR_CFG_NAME_EN > 0u
  777. ptmr1->OSTmrName = (INT8U *)(void *)"?";
  778. #endif
  779. OSTmrTime = 0u;
  780. OSTmrUsed = 0u;
  781. OSTmrFree = OS_TMR_CFG_MAX;
  782. OSTmrFreeList = &OSTmrTbl[0];
  783. OSTmrSem = OSSemCreate(1u);
  784. OSTmrSemSignal = OSSemCreate(0u);
  785. #if OS_EVENT_NAME_EN > 0u /* Assign names to semaphores */
  786. OSEventNameSet(OSTmrSem, (INT8U *)(void *)"uC/OS-II TmrLock", &err);
  787. OSEventNameSet(OSTmrSemSignal, (INT8U *)(void *)"uC/OS-II TmrSignal", &err);
  788. #endif
  789. OSTmr_InitTask();
  790. }
  791. #endif
  792. /*$PAGE*/
  793. /*
  794. *********************************************************************************************************
  795. * INITIALIZE THE TIMER MANAGEMENT TASK
  796. *
  797. * Description: This function is called by OSTmrInit() to create the timer management task.
  798. * * Arguments : none
  799. *
  800. * Returns : none
  801. *********************************************************************************************************
  802. */
  803. #if OS_TMR_EN > 0u
  804. static void OSTmr_InitTask (void)
  805. {
  806. #if OS_TASK_NAME_EN > 0u
  807. INT8U err;
  808. #endif
  809. #if OS_TASK_CREATE_EXT_EN > 0u
  810. #if OS_STK_GROWTH == 1u
  811. (void)OSTaskCreateExt(OSTmr_Task,
  812. (void *)0, /* No arguments passed to OSTmrTask() */
  813. &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Top-Of-Stack */
  814. OS_TASK_TMR_PRIO,
  815. OS_TASK_TMR_ID,
  816. &OSTmrTaskStk[0], /* Set Bottom-Of-Stack */
  817. OS_TASK_TMR_STK_SIZE,
  818. (void *)0, /* No TCB extension */
  819. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */
  820. #else
  821. (void)OSTaskCreateExt(OSTmr_Task,
  822. (void *)0, /* No arguments passed to OSTmrTask() */
  823. &OSTmrTaskStk[0], /* Set Top-Of-Stack */
  824. OS_TASK_TMR_PRIO,
  825. OS_TASK_TMR_ID,
  826. &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Bottom-Of-Stack */
  827. OS_TASK_TMR_STK_SIZE,
  828. (void *)0, /* No TCB extension */
  829. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */
  830. #endif
  831. #else
  832. #if OS_STK_GROWTH == 1u
  833. (void)OSTaskCreate(OSTmr_Task,
  834. (void *)0,
  835. &OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u],
  836. OS_TASK_TMR_PRIO);
  837. #else
  838. (void)OSTaskCreate(OSTmr_Task,
  839. (void *)0,
  840. &OSTmrTaskStk[0],
  841. OS_TASK_TMR_PRIO);
  842. #endif
  843. #endif
  844. #if OS_TASK_NAME_EN > 0u
  845. OSTaskNameSet(OS_TASK_TMR_PRIO, (INT8U *)(void *)"uC/OS-II Tmr", &err);
  846. #endif
  847. }
  848. #endif
  849. /*$PAGE*/
  850. /*
  851. *********************************************************************************************************
  852. * INSERT A TIMER INTO THE TIMER WHEEL
  853. *
  854. * Description: This function is called to insert the timer into the timer wheel. The timer is always
  855. * inserted at the beginning of the list.
  856. *
  857. * Arguments : ptmr Is a pointer to the timer to insert.
  858. *
  859. * type Is either:
  860. * OS_TMR_LINK_PERIODIC Means to re-insert the timer after a period expired
  861. * OS_TMR_LINK_DLY Means to insert the timer the first time
  862. *
  863. * Returns : none
  864. *********************************************************************************************************
  865. */
  866. #if OS_TMR_EN > 0u
  867. static void OSTmr_Link (OS_TMR *ptmr,
  868. INT8U type)
  869. {
  870. OS_TMR *ptmr1;
  871. OS_TMR_WHEEL *pspoke;
  872. INT16U spoke;
  873. ptmr->OSTmrState = OS_TMR_STATE_RUNNING;
  874. if (type == OS_TMR_LINK_PERIODIC) { /* Determine when timer will expire */
  875. ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
  876. } else {
  877. if (ptmr->OSTmrDly == 0u) {
  878. ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
  879. } else {
  880. ptmr->OSTmrMatch = ptmr->OSTmrDly + OSTmrTime;
  881. }
  882. }
  883. spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
  884. pspoke = &OSTmrWheelTbl[spoke];
  885. if (pspoke->OSTmrFirst == (OS_TMR *)0) { /* Link into timer wheel */
  886. pspoke->OSTmrFirst = ptmr;
  887. ptmr->OSTmrNext = (OS_TMR *)0;
  888. pspoke->OSTmrEntries = 1u;
  889. } else {
  890. ptmr1 = pspoke->OSTmrFirst; /* Point to first timer in the spoke */
  891. pspoke->OSTmrFirst = ptmr;
  892. ptmr->OSTmrNext = (void *)ptmr1;
  893. ptmr1->OSTmrPrev = (void *)ptmr;
  894. pspoke->OSTmrEntries++;
  895. }
  896. ptmr->OSTmrPrev = (void *)0; /* Timer always inserted as first node in list */
  897. }
  898. #endif
  899. /*$PAGE*/
  900. /*
  901. *********************************************************************************************************
  902. * REMOVE A TIMER FROM THE TIMER WHEEL
  903. *
  904. * Description: This function is called to remove the timer from the timer wheel.
  905. *
  906. * Arguments : ptmr Is a pointer to the timer to remove.
  907. *
  908. * Returns : none
  909. *********************************************************************************************************
  910. */
  911. #if OS_TMR_EN > 0u
  912. static void OSTmr_Unlink (OS_TMR *ptmr)
  913. {
  914. OS_TMR *ptmr1;
  915. OS_TMR *ptmr2;
  916. OS_TMR_WHEEL *pspoke;
  917. INT16U spoke;
  918. spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
  919. pspoke = &OSTmrWheelTbl[spoke];
  920. if (pspoke->OSTmrFirst == ptmr) { /* See if timer to remove is at the beginning of list */
  921. ptmr1 = (OS_TMR *)ptmr->OSTmrNext;
  922. pspoke->OSTmrFirst = (OS_TMR *)ptmr1;
  923. if (ptmr1 != (OS_TMR *)0) {
  924. ptmr1->OSTmrPrev = (void *)0;
  925. }
  926. } else {
  927. ptmr1 = (OS_TMR *)ptmr->OSTmrPrev; /* Remove timer from somewhere in the list */
  928. ptmr2 = (OS_TMR *)ptmr->OSTmrNext;
  929. ptmr1->OSTmrNext = ptmr2;
  930. if (ptmr2 != (OS_TMR *)0) {
  931. ptmr2->OSTmrPrev = (void *)ptmr1;
  932. }
  933. }
  934. ptmr->OSTmrState = OS_TMR_STATE_STOPPED;
  935. ptmr->OSTmrNext = (void *)0;
  936. ptmr->OSTmrPrev = (void *)0;
  937. pspoke->OSTmrEntries--;
  938. }
  939. #endif
  940. /*$PAGE*/
  941. /*
  942. *********************************************************************************************************
  943. * TIMER MANAGEMENT TASK
  944. *
  945. * Description: This task is created by OSTmrInit().
  946. *
  947. * Arguments : none
  948. *
  949. * Returns : none
  950. *********************************************************************************************************
  951. */
  952. #if OS_TMR_EN > 0u
  953. static void OSTmr_Task (void *p_arg)
  954. {
  955. INT8U err;
  956. OS_TMR *ptmr;
  957. OS_TMR *ptmr_next;
  958. OS_TMR_CALLBACK pfnct;
  959. OS_TMR_WHEEL *pspoke;
  960. INT16U spoke;
  961. p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
  962. for (;;) {
  963. OSSemPend(OSTmrSemSignal, 0u, &err); /* Wait for signal indicating time to update timers */
  964. OSSchedLock();
  965. OSTmrTime++; /* Increment the current time */
  966. spoke = (INT16U)(OSTmrTime % OS_TMR_CFG_WHEEL_SIZE); /* Position on current timer wheel entry */
  967. pspoke = &OSTmrWheelTbl[spoke];
  968. ptmr = pspoke->OSTmrFirst;
  969. while (ptmr != (OS_TMR *)0) {
  970. ptmr_next = (OS_TMR *)ptmr->OSTmrNext; /* Point to next timer to update because current ... */
  971. /* ... timer could get unlinked from the wheel. */
  972. if (OSTmrTime == ptmr->OSTmrMatch) { /* Process each timer that expires */
  973. OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
  974. if (ptmr->OSTmrOpt == OS_TMR_OPT_PERIODIC) {
  975. OSTmr_Link(ptmr, OS_TMR_LINK_PERIODIC); /* Recalculate new position of timer in wheel */
  976. } else {
  977. ptmr->OSTmrState = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */
  978. }
  979. pfnct = ptmr->OSTmrCallback; /* Execute callback function if available */
  980. if (pfnct != (OS_TMR_CALLBACK)0) {
  981. (*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg);
  982. }
  983. }
  984. ptmr = ptmr_next;
  985. }
  986. OSSchedUnlock();
  987. }
  988. }
  989. #endif