os_tmr.c 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-III
  4. * The Real-Time Kernel
  5. *
  6. * Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
  7. *
  8. * SPDX-License-Identifier: APACHE-2.0
  9. *
  10. * This software is subject to an open source license and is distributed by
  11. * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
  12. * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
  13. *
  14. *********************************************************************************************************
  15. */
  16. /*
  17. *********************************************************************************************************
  18. * TIMER MANAGEMENT
  19. *
  20. * File : os_tmr.c
  21. * Version : V3.08.02
  22. *********************************************************************************************************
  23. */
  24. #define MICRIUM_SOURCE
  25. #include "os.h"
  26. #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
  27. const CPU_CHAR *os_tmr__c = "$Id: $";
  28. #endif
  29. #if (OS_CFG_TMR_EN > 0u)
  30. /*
  31. ************************************************************************************************************************
  32. * LOCAL FUNCTION PROTOTYPES
  33. ************************************************************************************************************************
  34. */
  35. static void OS_TmrLock (void);
  36. static void OS_TmrUnlock (void);
  37. static void OS_TmrCondCreate(void);
  38. static void OS_TmrCondSignal(void);
  39. static void OS_TmrCondWait (OS_TICK timeout);
  40. /*
  41. ************************************************************************************************************************
  42. * CREATE A TIMER
  43. *
  44. * Description: This function is called by your application code to create a timer.
  45. *
  46. * Arguments : p_tmr Is a pointer to a timer control block
  47. *
  48. * p_name Is a pointer to an ASCII string that is used to name the timer. Names are useful for
  49. * debugging.
  50. *
  51. * dly Initial delay.
  52. * If the timer is configured for ONE-SHOT mode, this is the timeout used
  53. * If the timer is configured for PERIODIC mode, this is the first timeout to wait for
  54. * before the timer starts entering periodic mode
  55. *
  56. * period The 'period' being repeated for the timer.
  57. * If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will
  58. * automatically restart with the same period.
  59. *
  60. * opt Specifies either:
  61. *
  62. * OS_OPT_TMR_ONE_SHOT The timer counts down only once
  63. * OS_OPT_TMR_PERIODIC The timer counts down and then reloads itself
  64. *
  65. * p_callback Is a pointer to a callback function that will be called when the timer expires. The
  66. * callback function must be declared as follows:
  67. *
  68. * void MyCallback (OS_TMR *p_tmr, void *p_arg);
  69. *
  70. * p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
  71. *
  72. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  73. *
  74. * OS_ERR_NONE The call succeeded
  75. * OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the timer after you called
  76. * OSSafetyCriticalStart()
  77. * OS_ERR_OBJ_PTR_NULL Is 'p_tmr' is a NULL pointer
  78. * OS_ERR_OPT_INVALID You specified an invalid option
  79. * OS_ERR_TMR_INVALID_CALLBACK You specified an invalid callback for a periodic timer
  80. * OS_ERR_TMR_INVALID_DLY You specified an invalid delay
  81. * OS_ERR_TMR_INVALID_PERIOD You specified an invalid period
  82. * OS_ERR_TMR_ISR If the call was made from an ISR
  83. * OS_ERR_OBJ_CREATED If the timer was already created
  84. *
  85. * Returns : none
  86. *
  87. * Note(s) : 1) This function only creates the timer. In other words, the timer is not started when created. To
  88. * start the timer, call OSTmrStart().
  89. ************************************************************************************************************************
  90. */
  91. void OSTmrCreate (OS_TMR *p_tmr,
  92. CPU_CHAR *p_name,
  93. OS_TICK dly,
  94. OS_TICK period,
  95. OS_OPT opt,
  96. OS_TMR_CALLBACK_PTR p_callback,
  97. void *p_callback_arg,
  98. OS_ERR *p_err)
  99. {
  100. #ifdef OS_SAFETY_CRITICAL
  101. if (p_err == (OS_ERR *)0) {
  102. OS_SAFETY_CRITICAL_EXCEPTION();
  103. return;
  104. }
  105. #endif
  106. #ifdef OS_SAFETY_CRITICAL_IEC61508
  107. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  108. *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  109. return;
  110. }
  111. #endif
  112. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  113. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  114. *p_err = OS_ERR_TMR_ISR;
  115. return;
  116. }
  117. #endif
  118. #if (OS_CFG_ARG_CHK_EN > 0u)
  119. if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */
  120. *p_err = OS_ERR_OBJ_PTR_NULL;
  121. return;
  122. }
  123. switch (opt) {
  124. case OS_OPT_TMR_PERIODIC:
  125. if (period == 0u) {
  126. *p_err = OS_ERR_TMR_INVALID_PERIOD;
  127. return;
  128. }
  129. if (p_callback == (OS_TMR_CALLBACK_PTR)0) { /* No point in a periodic timer without a callback */
  130. *p_err = OS_ERR_TMR_INVALID_CALLBACK;
  131. return;
  132. }
  133. break;
  134. case OS_OPT_TMR_ONE_SHOT:
  135. if (dly == 0u) {
  136. *p_err = OS_ERR_TMR_INVALID_DLY;
  137. return;
  138. }
  139. break;
  140. default:
  141. *p_err = OS_ERR_OPT_INVALID;
  142. return;
  143. }
  144. #endif
  145. if (OSRunning == OS_STATE_OS_RUNNING) { /* Only lock when the kernel is running */
  146. OS_TmrLock();
  147. }
  148. #if (OS_OBJ_TYPE_REQ > 0u)
  149. #if (OS_CFG_OBJ_CREATED_CHK_EN > 0u)
  150. if (p_tmr->Type == OS_OBJ_TYPE_TMR) {
  151. if (OSRunning == OS_STATE_OS_RUNNING) {
  152. OS_TmrUnlock();
  153. }
  154. *p_err = OS_ERR_OBJ_CREATED;
  155. return;
  156. }
  157. #endif
  158. p_tmr->Type = OS_OBJ_TYPE_TMR;
  159. #endif
  160. p_tmr->State = OS_TMR_STATE_STOPPED; /* Initialize the timer fields */
  161. #if (OS_CFG_DBG_EN > 0u)
  162. p_tmr->NamePtr = p_name;
  163. #else
  164. (void)p_name;
  165. #endif
  166. p_tmr->Dly = dly * OSTmrToTicksMult; /* Convert to Timer Start Delay to ticks */
  167. p_tmr->Remain = 0u;
  168. p_tmr->Period = period * OSTmrToTicksMult; /* Convert to Timer Period to ticks */
  169. p_tmr->Opt = opt;
  170. p_tmr->CallbackPtr = p_callback;
  171. p_tmr->CallbackPtrArg = p_callback_arg;
  172. p_tmr->NextPtr = (OS_TMR *)0;
  173. p_tmr->PrevPtr = (OS_TMR *)0;
  174. #if (OS_CFG_DBG_EN > 0u)
  175. OS_TmrDbgListAdd(p_tmr);
  176. #endif
  177. #if (OS_CFG_DBG_EN > 0u)
  178. OSTmrQty++; /* Keep track of the number of timers created */
  179. #endif
  180. if (OSRunning == OS_STATE_OS_RUNNING) {
  181. OS_TmrUnlock();
  182. }
  183. *p_err = OS_ERR_NONE;
  184. }
  185. /*
  186. ************************************************************************************************************************
  187. * DELETE A TIMER
  188. *
  189. * Description: This function is called by your application code to delete a timer.
  190. *
  191. * Arguments : p_tmr Is a pointer to the timer to stop and delete.
  192. *
  193. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  194. *
  195. * OS_ERR_NONE The call succeeded
  196. * OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the timer after you called
  197. * OSStart()
  198. * OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
  199. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  200. * OS_ERR_TMR_INACTIVE If the timer was not created
  201. * OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
  202. * OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
  203. * OS_ERR_TMR_ISR If the function was called from an ISR
  204. *
  205. * Returns : OS_TRUE if the timer was deleted
  206. * OS_FALSE if not or upon an error
  207. *
  208. * Note(s) : none
  209. ************************************************************************************************************************
  210. */
  211. #if (OS_CFG_TMR_DEL_EN > 0u)
  212. CPU_BOOLEAN OSTmrDel (OS_TMR *p_tmr,
  213. OS_ERR *p_err)
  214. {
  215. CPU_BOOLEAN success;
  216. OS_TICK time;
  217. CPU_SR_ALLOC();
  218. #ifdef OS_SAFETY_CRITICAL
  219. if (p_err == (OS_ERR *)0) {
  220. OS_SAFETY_CRITICAL_EXCEPTION();
  221. return (OS_FALSE);
  222. }
  223. #endif
  224. #ifdef OS_SAFETY_CRITICAL_IEC61508
  225. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  226. *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
  227. return (OS_FALSE);
  228. }
  229. #endif
  230. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  231. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  232. *p_err = OS_ERR_TMR_ISR;
  233. return (OS_FALSE);
  234. }
  235. #endif
  236. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  237. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  238. *p_err = OS_ERR_OS_NOT_RUNNING;
  239. return (OS_FALSE);
  240. }
  241. #endif
  242. #if (OS_CFG_ARG_CHK_EN > 0u)
  243. if (p_tmr == (OS_TMR *)0) {
  244. *p_err = OS_ERR_TMR_INVALID;
  245. return (OS_FALSE);
  246. }
  247. #endif
  248. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  249. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  250. *p_err = OS_ERR_OBJ_TYPE;
  251. return (OS_FALSE);
  252. }
  253. #endif
  254. OS_TmrLock();
  255. CPU_CRITICAL_ENTER();
  256. if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */
  257. time = OSTmrTaskTickBase;
  258. } else {
  259. #if (OS_CFG_DYN_TICK_EN > 0u)
  260. time = OSTickCtr + OS_DynTickGet();
  261. #else
  262. time = OSTickCtr;
  263. #endif
  264. }
  265. CPU_CRITICAL_EXIT();
  266. #if (OS_CFG_DBG_EN > 0u)
  267. OS_TmrDbgListRemove(p_tmr);
  268. #endif
  269. switch (p_tmr->State) {
  270. case OS_TMR_STATE_RUNNING:
  271. case OS_TMR_STATE_TIMEOUT:
  272. OS_TmrUnlink(p_tmr, time); /* Remove from the list */
  273. OS_TmrClr(p_tmr);
  274. #if (OS_CFG_DBG_EN > 0u)
  275. OSTmrQty--; /* One less timer */
  276. #endif
  277. *p_err = OS_ERR_NONE;
  278. success = OS_TRUE;
  279. break;
  280. case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
  281. case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
  282. OS_TmrClr(p_tmr); /* Clear timer fields */
  283. #if (OS_CFG_DBG_EN > 0u)
  284. OSTmrQty--; /* One less timer */
  285. #endif
  286. *p_err = OS_ERR_NONE;
  287. success = OS_TRUE;
  288. break;
  289. case OS_TMR_STATE_UNUSED: /* Already deleted */
  290. *p_err = OS_ERR_TMR_INACTIVE;
  291. success = OS_FALSE;
  292. break;
  293. default:
  294. *p_err = OS_ERR_TMR_INVALID_STATE;
  295. success = OS_FALSE;
  296. break;
  297. }
  298. OS_TmrUnlock();
  299. return (success);
  300. }
  301. #endif
  302. /*
  303. ************************************************************************************************************************
  304. * GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
  305. *
  306. * Description: This function is called to get the number of timer increments before a timer times out.
  307. *
  308. * Arguments : p_tmr Is a pointer to the timer to obtain the remaining time from.
  309. *
  310. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  311. *
  312. * OS_ERR_NONE The call succeeded
  313. * OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
  314. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  315. * OS_ERR_TMR_INACTIVE If 'p_tmr' points to a timer that is not active
  316. * OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
  317. * OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
  318. * OS_ERR_TMR_ISR If the call was made from an ISR
  319. *
  320. * Returns : The time remaining for the timer to expire. The time represents 'timer' increments (typically 1/10 sec).
  321. *
  322. * Note(s) : none
  323. ************************************************************************************************************************
  324. */
  325. OS_TICK OSTmrRemainGet (OS_TMR *p_tmr,
  326. OS_ERR *p_err)
  327. {
  328. OS_TMR *p_tmr1;
  329. OS_TICK remain;
  330. #ifdef OS_SAFETY_CRITICAL
  331. if (p_err == (OS_ERR *)0) {
  332. OS_SAFETY_CRITICAL_EXCEPTION();
  333. return (0u);
  334. }
  335. #endif
  336. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  337. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  338. *p_err = OS_ERR_TMR_ISR;
  339. return (0u);
  340. }
  341. #endif
  342. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  343. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  344. *p_err = OS_ERR_OS_NOT_RUNNING;
  345. return (0u);
  346. }
  347. #endif
  348. #if (OS_CFG_ARG_CHK_EN > 0u)
  349. if (p_tmr == (OS_TMR *)0) {
  350. *p_err = OS_ERR_TMR_INVALID;
  351. return (0u);
  352. }
  353. #endif
  354. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  355. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  356. *p_err = OS_ERR_OBJ_TYPE;
  357. return (0u);
  358. }
  359. #endif
  360. OS_TmrLock();
  361. switch (p_tmr->State) {
  362. case OS_TMR_STATE_RUNNING:
  363. p_tmr1 = OSTmrListPtr;
  364. remain = 0u;
  365. while (p_tmr1 != (OS_TMR *)0) { /* Add up all the deltas up until the current timer */
  366. remain += p_tmr1->Remain;
  367. if (p_tmr1 == p_tmr) {
  368. break;
  369. }
  370. p_tmr1 = p_tmr1->NextPtr;
  371. }
  372. remain /= OSTmrToTicksMult;
  373. *p_err = OS_ERR_NONE;
  374. break;
  375. case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
  376. if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
  377. if (p_tmr->Dly == 0u) {
  378. remain = p_tmr->Period / OSTmrToTicksMult;
  379. } else {
  380. remain = p_tmr->Dly / OSTmrToTicksMult;
  381. }
  382. } else {
  383. remain = p_tmr->Dly / OSTmrToTicksMult;
  384. }
  385. *p_err = OS_ERR_NONE;
  386. break;
  387. case OS_TMR_STATE_TIMEOUT: /* Within a callback, timers are in the TIMEOUT state */
  388. case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT timers can be in the COMPLETED state */
  389. *p_err = OS_ERR_NONE;
  390. remain = 0u;
  391. break;
  392. case OS_TMR_STATE_UNUSED:
  393. *p_err = OS_ERR_TMR_INACTIVE;
  394. remain = 0u;
  395. break;
  396. default:
  397. *p_err = OS_ERR_TMR_INVALID_STATE;
  398. remain = 0u;
  399. break;
  400. }
  401. OS_TmrUnlock();
  402. return (remain);
  403. }
  404. /*
  405. ************************************************************************************************************************
  406. * SET A TIMER
  407. *
  408. * Description: This function is called by your application code to set a timer.
  409. *
  410. * Arguments : p_tmr Is a pointer to a timer control block
  411. *
  412. * dly Initial delay.
  413. * If the timer is configured for ONE-SHOT mode, this is the timeout used
  414. * If the timer is configured for PERIODIC mode, this is the first timeout to wait for
  415. * before the timer starts entering periodic mode
  416. *
  417. * period The 'period' being repeated for the timer.
  418. * If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will
  419. * automatically restart with the same period.
  420. *
  421. * p_callback Is a pointer to a callback function that will be called when the timer expires. The
  422. * callback function must be declared as follows:
  423. *
  424. * void MyCallback (OS_TMR *p_tmr, void *p_arg);
  425. *
  426. * p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
  427. *
  428. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  429. *
  430. * OS_ERR_NONE The timer was configured as expected
  431. * OS_ERR_OBJ_TYPE If the object type is invalid
  432. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  433. * OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer or invalid option
  434. * OS_ERR_TMR_INVALID_CALLBACK you specified an invalid callback for a periodic timer
  435. * OS_ERR_TMR_INVALID_DLY You specified an invalid delay
  436. * OS_ERR_TMR_INVALID_PERIOD You specified an invalid period
  437. * OS_ERR_TMR_ISR If the call was made from an ISR
  438. *
  439. * Returns : none
  440. *
  441. * Note(s) : 1) This function can be called on a running timer. The change to the delay and period will only
  442. * take effect after the current period or delay has passed. Change to the callback will take
  443. * effect immediately.
  444. ************************************************************************************************************************
  445. */
  446. void OSTmrSet (OS_TMR *p_tmr,
  447. OS_TICK dly,
  448. OS_TICK period,
  449. OS_TMR_CALLBACK_PTR p_callback,
  450. void *p_callback_arg,
  451. OS_ERR *p_err)
  452. {
  453. #ifdef OS_SAFETY_CRITICAL
  454. if (p_err == (OS_ERR *)0) {
  455. OS_SAFETY_CRITICAL_EXCEPTION();
  456. return;
  457. }
  458. #endif
  459. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  460. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  461. *p_err = OS_ERR_TMR_ISR;
  462. return;
  463. }
  464. #endif
  465. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  466. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  467. *p_err = OS_ERR_OS_NOT_RUNNING;
  468. return;
  469. }
  470. #endif
  471. #if (OS_CFG_ARG_CHK_EN > 0u)
  472. if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */
  473. *p_err = OS_ERR_TMR_INVALID;
  474. return;
  475. }
  476. #endif
  477. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  478. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  479. *p_err = OS_ERR_OBJ_TYPE;
  480. return;
  481. }
  482. #endif
  483. #if (OS_CFG_ARG_CHK_EN > 0u)
  484. switch (p_tmr->Opt) {
  485. case OS_OPT_TMR_PERIODIC:
  486. if (period == 0u) {
  487. *p_err = OS_ERR_TMR_INVALID_PERIOD;
  488. return;
  489. }
  490. if (p_callback == (OS_TMR_CALLBACK_PTR)0) { /* No point in a periodic timer without a callback */
  491. *p_err = OS_ERR_TMR_INVALID_CALLBACK;
  492. return;
  493. }
  494. break;
  495. case OS_OPT_TMR_ONE_SHOT:
  496. if (dly == 0u) {
  497. *p_err = OS_ERR_TMR_INVALID_DLY;
  498. return;
  499. }
  500. break;
  501. default:
  502. *p_err = OS_ERR_TMR_INVALID;
  503. return;
  504. }
  505. #endif
  506. OS_TmrLock();
  507. p_tmr->Dly = dly * OSTmrToTicksMult; /* Convert Timer Delay to ticks */
  508. p_tmr->Period = period * OSTmrToTicksMult; /* Convert Timer Period to ticks */
  509. p_tmr->CallbackPtr = p_callback;
  510. p_tmr->CallbackPtrArg = p_callback_arg;
  511. *p_err = OS_ERR_NONE;
  512. OS_TmrUnlock();
  513. }
  514. /*
  515. ************************************************************************************************************************
  516. * START A TIMER
  517. *
  518. * Description: This function is called by your application code to start a timer.
  519. *
  520. * Arguments : p_tmr Is a pointer to an OS_TMR
  521. *
  522. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  523. *
  524. * OS_ERR_NONE The timer was started
  525. * OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
  526. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  527. * OS_ERR_TMR_INACTIVE If the timer was not created
  528. * OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
  529. * OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
  530. * OS_ERR_TMR_ISR If the call was made from an ISR
  531. *
  532. * Returns : OS_TRUE is the timer was started
  533. * OS_FALSE if not or upon an error
  534. *
  535. * Note(s) : 1) When starting/restarting a timer, regardless if it is in PERIODIC or ONE-SHOT mode, the timer is
  536. * linked to the timer list with the OS_OPT_LINK_DLY option. This option sets the initial expiration
  537. * time for the timer. For timers in PERIODIC mode, subsequent expiration times are handled by
  538. * the OS_TmrTask().
  539. ************************************************************************************************************************
  540. */
  541. CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr,
  542. OS_ERR *p_err)
  543. {
  544. CPU_BOOLEAN success;
  545. OS_TICK time;
  546. CPU_SR_ALLOC();
  547. #ifdef OS_SAFETY_CRITICAL
  548. if (p_err == (OS_ERR *)0) {
  549. OS_SAFETY_CRITICAL_EXCEPTION();
  550. return (OS_FALSE);
  551. }
  552. #endif
  553. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  554. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  555. *p_err = OS_ERR_TMR_ISR;
  556. return (OS_FALSE);
  557. }
  558. #endif
  559. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  560. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  561. *p_err = OS_ERR_OS_NOT_RUNNING;
  562. return (OS_FALSE);
  563. }
  564. #endif
  565. #if (OS_CFG_ARG_CHK_EN > 0u)
  566. if (p_tmr == (OS_TMR *)0) {
  567. *p_err = OS_ERR_TMR_INVALID;
  568. return (OS_FALSE);
  569. }
  570. #endif
  571. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  572. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  573. *p_err = OS_ERR_OBJ_TYPE;
  574. return (OS_FALSE);
  575. }
  576. #endif
  577. OS_TmrLock();
  578. CPU_CRITICAL_ENTER();
  579. if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */
  580. time = OSTmrTaskTickBase;
  581. } else {
  582. #if (OS_CFG_DYN_TICK_EN > 0u)
  583. time = OSTickCtr + OS_DynTickGet();
  584. #else
  585. time = OSTickCtr;
  586. #endif
  587. }
  588. CPU_CRITICAL_EXIT();
  589. switch (p_tmr->State) {
  590. case OS_TMR_STATE_RUNNING: /* Restart the timer */
  591. case OS_TMR_STATE_TIMEOUT:
  592. p_tmr->State = OS_TMR_STATE_RUNNING;
  593. OS_TmrUnlink(p_tmr, time); /* Remove from current position in List */
  594. if (p_tmr->Dly == 0u) {
  595. p_tmr->Remain = p_tmr->Period;
  596. } else {
  597. p_tmr->Remain = p_tmr->Dly;
  598. }
  599. OS_TmrLink(p_tmr, time); /* Add timer to List */
  600. *p_err = OS_ERR_NONE;
  601. success = OS_TRUE;
  602. break;
  603. case OS_TMR_STATE_STOPPED: /* Start the timer */
  604. case OS_TMR_STATE_COMPLETED:
  605. p_tmr->State = OS_TMR_STATE_RUNNING;
  606. if (p_tmr->Dly == 0u) {
  607. p_tmr->Remain = p_tmr->Period;
  608. } else {
  609. p_tmr->Remain = p_tmr->Dly;
  610. }
  611. OS_TmrLink(p_tmr, time); /* Add timer to List */
  612. *p_err = OS_ERR_NONE;
  613. success = OS_TRUE;
  614. break;
  615. case OS_TMR_STATE_UNUSED: /* Timer not created */
  616. *p_err = OS_ERR_TMR_INACTIVE;
  617. success = OS_FALSE;
  618. break;
  619. default:
  620. *p_err = OS_ERR_TMR_INVALID_STATE;
  621. success = OS_FALSE;
  622. break;
  623. }
  624. OS_TmrUnlock();
  625. return (success);
  626. }
  627. /*
  628. ************************************************************************************************************************
  629. * FIND OUT WHAT STATE A TIMER IS IN
  630. *
  631. * Description: This function is called to determine what state the timer is in:
  632. *
  633. * OS_TMR_STATE_UNUSED the timer has not been created
  634. * OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped
  635. * OS_TMR_STATE_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout
  636. * OS_TMR_SATE_RUNNING the timer is currently running
  637. *
  638. * Arguments : p_tmr Is a pointer to the desired timer
  639. *
  640. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  641. *
  642. * OS_ERR_NONE The return value reflects the state of the timer
  643. * OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
  644. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  645. * OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
  646. * OS_ERR_TMR_INVALID_STATE If the timer is not in a valid state
  647. * OS_ERR_TMR_ISR If the call was made from an ISR
  648. *
  649. * Returns : The current state of the timer (see description).
  650. *
  651. * Note(s) : none
  652. ************************************************************************************************************************
  653. */
  654. OS_STATE OSTmrStateGet (OS_TMR *p_tmr,
  655. OS_ERR *p_err)
  656. {
  657. OS_STATE state;
  658. #ifdef OS_SAFETY_CRITICAL
  659. if (p_err == (OS_ERR *)0) {
  660. OS_SAFETY_CRITICAL_EXCEPTION();
  661. return (OS_TMR_STATE_UNUSED);
  662. }
  663. #endif
  664. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  665. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  666. *p_err = OS_ERR_TMR_ISR;
  667. return (OS_TMR_STATE_UNUSED);
  668. }
  669. #endif
  670. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  671. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  672. *p_err = OS_ERR_OS_NOT_RUNNING;
  673. return (OS_TMR_STATE_UNUSED);
  674. }
  675. #endif
  676. #if (OS_CFG_ARG_CHK_EN > 0u)
  677. if (p_tmr == (OS_TMR *)0) {
  678. *p_err = OS_ERR_TMR_INVALID;
  679. return (OS_TMR_STATE_UNUSED);
  680. }
  681. #endif
  682. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  683. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  684. *p_err = OS_ERR_OBJ_TYPE;
  685. return (OS_TMR_STATE_UNUSED);
  686. }
  687. #endif
  688. OS_TmrLock();
  689. state = p_tmr->State;
  690. switch (state) {
  691. case OS_TMR_STATE_UNUSED:
  692. case OS_TMR_STATE_STOPPED:
  693. case OS_TMR_STATE_COMPLETED:
  694. case OS_TMR_STATE_RUNNING:
  695. case OS_TMR_STATE_TIMEOUT:
  696. *p_err = OS_ERR_NONE;
  697. break;
  698. default:
  699. *p_err = OS_ERR_TMR_INVALID_STATE;
  700. break;
  701. }
  702. OS_TmrUnlock();
  703. return (state);
  704. }
  705. /*
  706. ************************************************************************************************************************
  707. * STOP A TIMER
  708. *
  709. * Description: This function is called by your application code to stop a timer.
  710. *
  711. * Arguments : p_tmr Is a pointer to the timer to stop.
  712. *
  713. * opt Allows you to specify an option to this functions which can be:
  714. *
  715. * OS_OPT_TMR_NONE Do nothing special but stop the timer
  716. * OS_OPT_TMR_CALLBACK Execute the callback function, pass it the callback argument
  717. * specified when the timer was created.
  718. * OS_OPT_TMR_CALLBACK_ARG Execute the callback function, pass it the callback argument
  719. * specified in THIS function call
  720. *
  721. * callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function
  722. * instead of the timer's callback argument. In other words, use 'callback_arg' passed in
  723. * THIS function INSTEAD of p_tmr->OSTmrCallbackArg
  724. *
  725. * p_err Is a pointer to an error code. '*p_err' will contain one of the following:
  726. *
  727. * OS_ERR_NONE The timer has stopped
  728. * OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
  729. * OS_ERR_OPT_INVALID If you specified an invalid option for 'opt'
  730. * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
  731. * OS_ERR_TMR_INACTIVE If the timer was not created
  732. * OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
  733. * OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
  734. * OS_ERR_TMR_ISR If the function was called from an ISR
  735. * OS_ERR_TMR_NO_CALLBACK If the timer does not have a callback function defined
  736. * OS_ERR_TMR_STOPPED If the timer was already stopped
  737. *
  738. * Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE)
  739. * OS_FALSE If not
  740. *
  741. * Note(s) : none
  742. ************************************************************************************************************************
  743. */
  744. CPU_BOOLEAN OSTmrStop (OS_TMR *p_tmr,
  745. OS_OPT opt,
  746. void *p_callback_arg,
  747. OS_ERR *p_err)
  748. {
  749. OS_TMR_CALLBACK_PTR p_fnct;
  750. CPU_BOOLEAN success;
  751. OS_TICK time;
  752. CPU_SR_ALLOC();
  753. #ifdef OS_SAFETY_CRITICAL
  754. if (p_err == (OS_ERR *)0) {
  755. OS_SAFETY_CRITICAL_EXCEPTION();
  756. return (OS_FALSE);
  757. }
  758. #endif
  759. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  760. if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
  761. *p_err = OS_ERR_TMR_ISR;
  762. return (OS_FALSE);
  763. }
  764. #endif
  765. #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
  766. if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
  767. *p_err = OS_ERR_OS_NOT_RUNNING;
  768. return (OS_FALSE);
  769. }
  770. #endif
  771. #if (OS_CFG_ARG_CHK_EN > 0u)
  772. if (p_tmr == (OS_TMR *)0) {
  773. *p_err = OS_ERR_TMR_INVALID;
  774. return (OS_FALSE);
  775. }
  776. #endif
  777. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  778. if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
  779. *p_err = OS_ERR_OBJ_TYPE;
  780. return (OS_FALSE);
  781. }
  782. #endif
  783. OS_TmrLock();
  784. CPU_CRITICAL_ENTER();
  785. if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */
  786. time = OSTmrTaskTickBase;
  787. } else {
  788. #if (OS_CFG_DYN_TICK_EN > 0u)
  789. time = OSTickCtr + OS_DynTickGet();
  790. #else
  791. time = OSTickCtr;
  792. #endif
  793. }
  794. CPU_CRITICAL_EXIT();
  795. switch (p_tmr->State) {
  796. case OS_TMR_STATE_RUNNING:
  797. case OS_TMR_STATE_TIMEOUT:
  798. p_tmr->State = OS_TMR_STATE_STOPPED; /* Ensure that any callbacks see the stop state */
  799. switch (opt) {
  800. case OS_OPT_TMR_CALLBACK:
  801. OS_TmrUnlink(p_tmr, time); /* Remove from timer list */
  802. p_fnct = p_tmr->CallbackPtr; /* Execute callback function ... */
  803. if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { /* ... if available */
  804. (*p_fnct)(p_tmr, p_tmr->CallbackPtrArg);/* Use callback arg when timer was created */
  805. } else {
  806. *p_err = OS_ERR_TMR_NO_CALLBACK;
  807. }
  808. break;
  809. case OS_OPT_TMR_CALLBACK_ARG:
  810. OS_TmrUnlink(p_tmr, time); /* Remove from timer list */
  811. p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available ... */
  812. if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
  813. (*p_fnct)(p_tmr, p_callback_arg); /* .. using the 'callback_arg' provided in call */
  814. } else {
  815. *p_err = OS_ERR_TMR_NO_CALLBACK;
  816. }
  817. break;
  818. case OS_OPT_TMR_NONE:
  819. OS_TmrUnlink(p_tmr, time); /* Remove from timer list */
  820. break;
  821. default:
  822. OS_TmrUnlock();
  823. *p_err = OS_ERR_OPT_INVALID;
  824. return (OS_FALSE);
  825. }
  826. *p_err = OS_ERR_NONE;
  827. success = OS_TRUE;
  828. break;
  829. case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or */
  830. case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
  831. p_tmr->State = OS_TMR_STATE_STOPPED;
  832. *p_err = OS_ERR_TMR_STOPPED;
  833. success = OS_TRUE;
  834. break;
  835. case OS_TMR_STATE_UNUSED: /* Timer was not created */
  836. *p_err = OS_ERR_TMR_INACTIVE;
  837. success = OS_FALSE;
  838. break;
  839. default:
  840. *p_err = OS_ERR_TMR_INVALID_STATE;
  841. success = OS_FALSE;
  842. break;
  843. }
  844. OS_TmrUnlock();
  845. return (success);
  846. }
  847. /*
  848. ************************************************************************************************************************
  849. * CLEAR TIMER FIELDS
  850. *
  851. * Description: This function is called to clear all timer fields.
  852. *
  853. * Argument(s): p_tmr Is a pointer to the timer to clear
  854. * -----
  855. *
  856. * Returns : none
  857. *
  858. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  859. ************************************************************************************************************************
  860. */
  861. void OS_TmrClr (OS_TMR *p_tmr)
  862. {
  863. p_tmr->State = OS_TMR_STATE_UNUSED; /* Clear timer fields */
  864. #if (OS_OBJ_TYPE_REQ > 0u)
  865. p_tmr->Type = OS_OBJ_TYPE_NONE;
  866. #endif
  867. #if (OS_CFG_DBG_EN > 0u)
  868. p_tmr->NamePtr = (CPU_CHAR *)((void *)"?TMR");
  869. #endif
  870. p_tmr->Dly = 0u;
  871. p_tmr->Remain = 0u;
  872. p_tmr->Period = 0u;
  873. p_tmr->Opt = 0u;
  874. p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)0;
  875. p_tmr->CallbackPtrArg = (void *)0;
  876. p_tmr->NextPtr = (OS_TMR *)0;
  877. p_tmr->PrevPtr = (OS_TMR *)0;
  878. }
  879. /*
  880. ************************************************************************************************************************
  881. * ADD/REMOVE TIMER TO/FROM DEBUG TABLE
  882. *
  883. * Description: These functions are called by uC/OS-III to add or remove a timer to/from a timer debug table.
  884. *
  885. * Arguments : p_tmr is a pointer to the timer to add/remove
  886. *
  887. * Returns : none
  888. *
  889. * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
  890. ************************************************************************************************************************
  891. */
  892. #if (OS_CFG_DBG_EN > 0u)
  893. void OS_TmrDbgListAdd (OS_TMR *p_tmr)
  894. {
  895. p_tmr->DbgPrevPtr = (OS_TMR *)0;
  896. if (OSTmrDbgListPtr == (OS_TMR *)0) {
  897. p_tmr->DbgNextPtr = (OS_TMR *)0;
  898. } else {
  899. p_tmr->DbgNextPtr = OSTmrDbgListPtr;
  900. OSTmrDbgListPtr->DbgPrevPtr = p_tmr;
  901. }
  902. OSTmrDbgListPtr = p_tmr;
  903. }
  904. void OS_TmrDbgListRemove (OS_TMR *p_tmr)
  905. {
  906. OS_TMR *p_tmr_next;
  907. OS_TMR *p_tmr_prev;
  908. p_tmr_prev = p_tmr->DbgPrevPtr;
  909. p_tmr_next = p_tmr->DbgNextPtr;
  910. if (p_tmr_prev == (OS_TMR *)0) {
  911. OSTmrDbgListPtr = p_tmr_next;
  912. if (p_tmr_next != (OS_TMR *)0) {
  913. p_tmr_next->DbgPrevPtr = (OS_TMR *)0;
  914. }
  915. p_tmr->DbgNextPtr = (OS_TMR *)0;
  916. } else if (p_tmr_next == (OS_TMR *)0) {
  917. p_tmr_prev->DbgNextPtr = (OS_TMR *)0;
  918. p_tmr->DbgPrevPtr = (OS_TMR *)0;
  919. } else {
  920. p_tmr_prev->DbgNextPtr = p_tmr_next;
  921. p_tmr_next->DbgPrevPtr = p_tmr_prev;
  922. p_tmr->DbgNextPtr = (OS_TMR *)0;
  923. p_tmr->DbgPrevPtr = (OS_TMR *)0;
  924. }
  925. }
  926. #endif
  927. /*
  928. ************************************************************************************************************************
  929. * INITIALIZE THE TIMER MANAGER
  930. *
  931. * Description: This function is called by OSInit() to initialize the timer manager module.
  932. *
  933. * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
  934. *
  935. * OS_ERR_NONE
  936. * OS_ERR_TMR_STK_INVALID if you didn't specify a stack for the timer task
  937. * OS_ERR_TMR_STK_SIZE_INVALID if you didn't allocate enough space for the timer stack
  938. * OS_ERR_PRIO_INVALID if you specified the same priority as the idle task
  939. * OS_ERR_xxx any error code returned by OSTaskCreate()
  940. *
  941. * Returns : none
  942. *
  943. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  944. ************************************************************************************************************************
  945. */
  946. void OS_TmrInit (OS_ERR *p_err)
  947. {
  948. #if (OS_CFG_DBG_EN > 0u)
  949. OSTmrQty = 0u; /* Keep track of the number of timers created */
  950. OSTmrDbgListPtr = (OS_TMR *)0;
  951. #endif
  952. OSTmrListPtr = (OS_TMR *)0; /* Create an empty timer list */
  953. #if (OS_CFG_DBG_EN > 0u)
  954. OSTmrListEntries = 0u;
  955. #endif
  956. /* Calculate Timer to Ticks multiplier */
  957. OSTmrToTicksMult = OSCfg_TickRate_Hz / OSCfg_TmrTaskRate_Hz;
  958. #if (OS_CFG_TS_EN > 0u)
  959. OSTmrTaskTime = 0u;
  960. OSTmrTaskTimeMax = 0u;
  961. #endif
  962. OSMutexCreate(&OSTmrMutex, /* Use a mutex to protect the timers */
  963. #if (OS_CFG_DBG_EN == 0u)
  964. (CPU_CHAR *)0,
  965. #else
  966. (CPU_CHAR *)"OS Tmr Mutex",
  967. #endif
  968. p_err);
  969. if (*p_err != OS_ERR_NONE) {
  970. return;
  971. }
  972. OS_TmrCondCreate();
  973. /* -------------- CREATE THE TIMER TASK --------------- */
  974. if (OSCfg_TmrTaskStkBasePtr == (CPU_STK *)0) {
  975. *p_err = OS_ERR_TMR_STK_INVALID;
  976. return;
  977. }
  978. if (OSCfg_TmrTaskStkSize < OSCfg_StkSizeMin) {
  979. *p_err = OS_ERR_TMR_STK_SIZE_INVALID;
  980. return;
  981. }
  982. if (OSCfg_TmrTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) {
  983. *p_err = OS_ERR_TMR_PRIO_INVALID;
  984. return;
  985. }
  986. OSTaskCreate(&OSTmrTaskTCB,
  987. #if (OS_CFG_DBG_EN == 0u)
  988. (CPU_CHAR *)0,
  989. #else
  990. (CPU_CHAR *)"uC/OS-III Timer Task",
  991. #endif
  992. OS_TmrTask,
  993. (void *)0,
  994. OSCfg_TmrTaskPrio,
  995. OSCfg_TmrTaskStkBasePtr,
  996. OSCfg_TmrTaskStkLimit,
  997. OSCfg_TmrTaskStkSize,
  998. 0u,
  999. 0u,
  1000. (void *)0,
  1001. (OS_OPT_TASK_STK_CHK | (OS_OPT)(OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS)),
  1002. p_err);
  1003. }
  1004. /*
  1005. ************************************************************************************************************************
  1006. * ADD A TIMER TO THE TIMER LIST
  1007. *
  1008. * Description: This function is called to add a timer to the timer list.
  1009. *
  1010. * Arguments : p_tmr Is a pointer to the timer to add.
  1011. *
  1012. * time Is the system time when this timer was linked.
  1013. * -----
  1014. *
  1015. * Returns : none
  1016. *
  1017. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  1018. ************************************************************************************************************************
  1019. */
  1020. void OS_TmrLink (OS_TMR *p_tmr,
  1021. OS_TICK time)
  1022. {
  1023. OS_TMR *p_tmr1;
  1024. OS_TMR *p_tmr2;
  1025. OS_TICK remain;
  1026. OS_TICK delta;
  1027. if (OSTmrListPtr == (OS_TMR *)0) { /* Is the list empty? */
  1028. p_tmr->NextPtr = (OS_TMR *)0; /* Yes, this is the first entry */
  1029. p_tmr->PrevPtr = (OS_TMR *)0;
  1030. OSTmrListPtr = p_tmr;
  1031. #if (OS_CFG_DBG_EN > 0u)
  1032. OSTmrListEntries = 1u;
  1033. #endif
  1034. OSTmrTaskTickBase = time;
  1035. OS_TmrCondSignal();
  1036. return;
  1037. }
  1038. #if (OS_CFG_DBG_EN > 0u)
  1039. OSTmrListEntries++;
  1040. #endif
  1041. delta = (time + p_tmr->Remain) - OSTmrTaskTickBase;
  1042. p_tmr2 = OSTmrListPtr; /* No, Insert somewhere in the list in delta order */
  1043. remain = p_tmr2->Remain;
  1044. if ((delta < remain) &&
  1045. (p_tmr2->PrevPtr == (OS_TMR *)0)) { /* Are we the new head of the list? */
  1046. p_tmr2->Remain = remain - delta;
  1047. p_tmr->PrevPtr = (OS_TMR *)0;
  1048. p_tmr->NextPtr = p_tmr2;
  1049. p_tmr2->PrevPtr = p_tmr;
  1050. OSTmrListPtr = p_tmr;
  1051. OSTmrTaskTickBase = time;
  1052. OS_TmrCondSignal();
  1053. return;
  1054. }
  1055. /* No */
  1056. delta -= remain; /* Make delta relative to the current head. */
  1057. p_tmr1 = p_tmr2;
  1058. p_tmr2 = p_tmr1->NextPtr;
  1059. while ((p_tmr2 != (OS_TMR *)0) && /* Find the appropriate position in the delta list. */
  1060. (delta >= p_tmr2->Remain)) {
  1061. delta -= p_tmr2->Remain; /* Update our delta as we traverse the list. */
  1062. p_tmr1 = p_tmr2;
  1063. p_tmr2 = p_tmr2->NextPtr;
  1064. }
  1065. if (p_tmr2 != (OS_TMR *)0) { /* Our entry is not the last element in the list. */
  1066. p_tmr1 = p_tmr2->PrevPtr;
  1067. p_tmr->Remain = delta; /* Store remaining time */
  1068. p_tmr->PrevPtr = p_tmr1;
  1069. p_tmr->NextPtr = p_tmr2;
  1070. p_tmr2->Remain -= delta; /* Reduce time of next entry in the list */
  1071. p_tmr2->PrevPtr = p_tmr;
  1072. p_tmr1->NextPtr = p_tmr;
  1073. } else { /* Our entry belongs at the end of the list. */
  1074. p_tmr->Remain = delta;
  1075. p_tmr->PrevPtr = p_tmr1;
  1076. p_tmr->NextPtr = (OS_TMR *)0;
  1077. p_tmr1->NextPtr = p_tmr;
  1078. }
  1079. }
  1080. /*
  1081. ************************************************************************************************************************
  1082. * REMOVE A TIMER FROM THE TIMER LIST
  1083. *
  1084. * Description: This function is called to remove the timer from the timer list.
  1085. *
  1086. * Arguments : p_tmr Is a pointer to the timer to remove.
  1087. *
  1088. * time Is the system time when this timer was unlinked.
  1089. * -----
  1090. *
  1091. * Returns : none
  1092. *
  1093. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  1094. ************************************************************************************************************************
  1095. */
  1096. void OS_TmrUnlink (OS_TMR *p_tmr,
  1097. OS_TICK time)
  1098. {
  1099. OS_TMR *p_tmr1;
  1100. OS_TMR *p_tmr2;
  1101. OS_TICK elapsed;
  1102. p_tmr1 = p_tmr->PrevPtr;
  1103. p_tmr2 = p_tmr->NextPtr;
  1104. if (p_tmr1 == (OS_TMR *)0) {
  1105. if (p_tmr2 == (OS_TMR *)0) { /* Remove the ONLY entry in the list? */
  1106. OSTmrListPtr = (OS_TMR *)0;
  1107. #if (OS_CFG_DBG_EN > 0u)
  1108. OSTmrListEntries = 0u;
  1109. #endif
  1110. p_tmr->Remain = 0u;
  1111. OSTmrTaskTickBase = time;
  1112. OS_TmrCondSignal();
  1113. } else {
  1114. #if (OS_CFG_DBG_EN > 0u)
  1115. OSTmrListEntries--;
  1116. #endif
  1117. elapsed = time - OSTmrTaskTickBase;
  1118. p_tmr2->PrevPtr = (OS_TMR *)0;
  1119. p_tmr2->Remain += p_tmr->Remain; /* Add back the ticks to the delta */
  1120. OSTmrListPtr = p_tmr2;
  1121. while ((elapsed > 0u) &&
  1122. (p_tmr2 != (OS_TMR *)0)) {
  1123. if (elapsed > p_tmr2->Remain) {
  1124. elapsed -= p_tmr2->Remain;
  1125. p_tmr2->Remain = 0u;
  1126. } else {
  1127. p_tmr2->Remain -= elapsed;
  1128. elapsed = 0u;
  1129. }
  1130. p_tmr1 = p_tmr2;
  1131. p_tmr2 = p_tmr1->NextPtr;
  1132. }
  1133. if ((OSTmrListPtr->Remain != p_tmr->Remain) || /* Reload if new head has a different delay ... */
  1134. (OSTmrListPtr->Remain == 0u)) { /* ... or has already timed out. */
  1135. OSTmrTaskTickBase = time;
  1136. OS_TmrCondSignal();
  1137. }
  1138. p_tmr->NextPtr = (OS_TMR *)0;
  1139. p_tmr->Remain = 0u;
  1140. }
  1141. } else {
  1142. #if (OS_CFG_DBG_EN > 0u)
  1143. OSTmrListEntries--;
  1144. #endif
  1145. p_tmr1->NextPtr = p_tmr2;
  1146. if (p_tmr2 != (OS_TMR *)0) {
  1147. p_tmr2->PrevPtr = p_tmr1;
  1148. p_tmr2->Remain += p_tmr->Remain; /* Add back the ticks to the delta list */
  1149. }
  1150. p_tmr->PrevPtr = (OS_TMR *)0;
  1151. p_tmr->NextPtr = (OS_TMR *)0;
  1152. p_tmr->Remain = 0u;
  1153. }
  1154. }
  1155. /*
  1156. ************************************************************************************************************************
  1157. * TIMER MANAGEMENT TASK
  1158. *
  1159. * Description: This task is created by OS_TmrInit().
  1160. *
  1161. * Arguments : none
  1162. *
  1163. * Returns : none
  1164. *
  1165. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  1166. *
  1167. * 2) The timer list is processed in two stages.
  1168. * a) Subtract the expired time from the delta list, which leaves expired timers at the head.
  1169. * b) Process each of the expired timers by invoking its callback (if any) and removing it.
  1170. * This method allows timer callbacks to Link/Unlink timers while maintaining the correct delta values.
  1171. *
  1172. * 3) Timer callbacks are allowed to make calls to the Timer APIs.
  1173. ************************************************************************************************************************
  1174. */
  1175. void OS_TmrTask (void *p_arg)
  1176. {
  1177. OS_TMR_CALLBACK_PTR p_fnct;
  1178. OS_TMR *p_tmr;
  1179. OS_TICK timeout;
  1180. OS_TICK elapsed;
  1181. OS_TICK time;
  1182. #if (OS_CFG_TS_EN > 0u)
  1183. CPU_TS ts_start;
  1184. #endif
  1185. CPU_SR_ALLOC();
  1186. (void)p_arg; /* Not using 'p_arg', prevent compiler warning */
  1187. OS_TmrLock();
  1188. for (;;) {
  1189. if (OSTmrListPtr == (OS_TMR *)0) {
  1190. timeout = 0u;
  1191. } else {
  1192. timeout = OSTmrListPtr->Remain;
  1193. }
  1194. OS_TmrCondWait(timeout); /* Suspend the timer task until it needs to process ... */
  1195. /* ... the timer list again. Also release the mutex ... */
  1196. /* ... so that application tasks can add/remove timers. */
  1197. if (OSTmrListPtr == (OS_TMR *)0) { /* Suppresses static analyzer warnings. */
  1198. continue;
  1199. }
  1200. #if (OS_CFG_TS_EN > 0u)
  1201. ts_start = OS_TS_GET();
  1202. #endif
  1203. CPU_CRITICAL_ENTER();
  1204. #if (OS_CFG_DYN_TICK_EN > 0u)
  1205. time = OSTickCtr + OS_DynTickGet();
  1206. #else
  1207. time = OSTickCtr;
  1208. #endif
  1209. CPU_CRITICAL_EXIT();
  1210. elapsed = time - OSTmrTaskTickBase;
  1211. OSTmrTaskTickBase = time;
  1212. /* Update the delta values. */
  1213. p_tmr = OSTmrListPtr;
  1214. while ((elapsed != 0u) &&
  1215. (p_tmr != (OS_TMR *)0)) {
  1216. if (elapsed > p_tmr->Remain) {
  1217. elapsed -= p_tmr->Remain;
  1218. p_tmr->Remain = 0u;
  1219. } else {
  1220. p_tmr->Remain -= elapsed;
  1221. elapsed = 0u;
  1222. }
  1223. p_tmr = p_tmr->NextPtr;
  1224. }
  1225. /* Process timers that have expired. */
  1226. p_tmr = OSTmrListPtr;
  1227. while ((p_tmr != (OS_TMR *)0) &&
  1228. (p_tmr->Remain == 0u)) {
  1229. p_tmr->State = OS_TMR_STATE_TIMEOUT;
  1230. /* Execute callback function if available */
  1231. p_fnct = p_tmr->CallbackPtr;
  1232. if (p_fnct != (OS_TMR_CALLBACK_PTR)0u) {
  1233. (*p_fnct)(p_tmr, p_tmr->CallbackPtrArg);
  1234. }
  1235. if (p_tmr->State == OS_TMR_STATE_TIMEOUT) {
  1236. OS_TmrUnlink(p_tmr, OSTmrTaskTickBase);
  1237. if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
  1238. p_tmr->State = OS_TMR_STATE_RUNNING;
  1239. p_tmr->Remain = p_tmr->Period;
  1240. OS_TmrLink(p_tmr, OSTmrTaskTickBase);
  1241. } else {
  1242. p_tmr->PrevPtr = (OS_TMR *)0;
  1243. p_tmr->NextPtr = (OS_TMR *)0;
  1244. p_tmr->Remain = 0u;
  1245. p_tmr->State = OS_TMR_STATE_COMPLETED;
  1246. }
  1247. }
  1248. p_tmr = OSTmrListPtr;
  1249. }
  1250. #if (OS_CFG_TS_EN > 0u)
  1251. OSTmrTaskTime = OS_TS_GET() - ts_start; /* Measure execution time of timer task */
  1252. if (OSTmrTaskTimeMax < OSTmrTaskTime) {
  1253. OSTmrTaskTimeMax = OSTmrTaskTime;
  1254. }
  1255. #endif
  1256. }
  1257. }
  1258. /*
  1259. ************************************************************************************************************************
  1260. * TIMER MANAGEMENT LOCKING MECHANISM
  1261. *
  1262. * Description: These functions are used to handle timer critical sections. The method uses a mutex
  1263. * to protect access to the global timer list.
  1264. *
  1265. * Arguments : none
  1266. *
  1267. * Returns : none
  1268. *
  1269. * Note(s) : 1) These functions are INTERNAL to uC/OS-III and your application MUST NOT call them.
  1270. ************************************************************************************************************************
  1271. */
  1272. static void OS_TmrLock (void)
  1273. {
  1274. OS_ERR err;
  1275. OSMutexPend(&OSTmrMutex, 0u, OS_OPT_PEND_BLOCKING, (CPU_TS *)0, &err);
  1276. }
  1277. static void OS_TmrUnlock (void)
  1278. {
  1279. OS_ERR err;
  1280. OSMutexPost(&OSTmrMutex, OS_OPT_POST_NONE, &err);
  1281. }
  1282. /*
  1283. ************************************************************************************************************************
  1284. * CREATE TIMER TASK CONDITION VARIABLE
  1285. *
  1286. * Description: Initializes a condition variable for INTERNAL use ONLY.
  1287. *
  1288. * Arguments : none
  1289. *
  1290. * Returns : none
  1291. *
  1292. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  1293. ************************************************************************************************************************
  1294. */
  1295. static void OS_TmrCondCreate (void)
  1296. {
  1297. CPU_SR_ALLOC();
  1298. CPU_CRITICAL_ENTER();
  1299. #if (OS_OBJ_TYPE_REQ > 0u)
  1300. OSTmrCond.Type = OS_OBJ_TYPE_COND; /* Mark the data structure as a condition variable. */
  1301. #endif
  1302. OSTmrCond.Mutex = &OSTmrMutex; /* Bind the timer mutex to the condition variable. */
  1303. OS_PendListInit(&OSTmrCond.PendList); /* Initialize the waiting list */
  1304. CPU_CRITICAL_EXIT();
  1305. }
  1306. /*
  1307. ************************************************************************************************************************
  1308. * WAIT ON TIMER TASK CONDITION VARIABLE
  1309. *
  1310. * Description: Allows the timer task to release the global mutex and pend atomically. This ensures that
  1311. * timers are only added/removed after the timer task has processed the current list and pended
  1312. * for the next timeout. The timer task will always acquire the mutex before returning from this function.
  1313. *
  1314. * Arguments : timeout The number of ticks before the timer task will wake up.
  1315. * A value of zero signifies an indefinite pend.
  1316. *
  1317. * Returns : none
  1318. *
  1319. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  1320. ************************************************************************************************************************
  1321. */
  1322. static void OS_TmrCondWait (OS_TICK timeout)
  1323. {
  1324. OS_TCB *p_tcb;
  1325. OS_PEND_LIST *p_pend_list;
  1326. CPU_TS ts;
  1327. CPU_SR_ALLOC();
  1328. CPU_CRITICAL_ENTER();
  1329. #if (OS_CFG_TS_EN > 0u)
  1330. ts = OS_TS_GET(); /* Get timestamp */
  1331. OSTmrMutex.TS = ts;
  1332. #else
  1333. ts = 0u;
  1334. #endif
  1335. /* Release mutex to other tasks. */
  1336. OS_MutexGrpRemove(&OSTmrTaskTCB, &OSTmrMutex);
  1337. p_pend_list = &OSTmrMutex.PendList;
  1338. if (OSTmrTaskTCB.Prio != OSTmrTaskTCB.BasePrio) { /* Restore our original prio. */
  1339. OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(&OSTmrTaskTCB, OSTmrTaskTCB.Prio);
  1340. OSTmrTaskTCB.Prio = OSTmrTaskTCB.BasePrio;
  1341. OSPrioCur = OSTmrTaskTCB.BasePrio;
  1342. }
  1343. if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on mutex? */
  1344. OSTmrMutex.OwnerTCBPtr = (OS_TCB *)0; /* No */
  1345. OSTmrMutex.OwnerNestingCtr = 0u;
  1346. } else {
  1347. p_tcb = p_pend_list->HeadPtr; /* Yes, give mutex to new owner */
  1348. OSTmrMutex.OwnerTCBPtr = p_tcb;
  1349. OSTmrMutex.OwnerNestingCtr = 1u;
  1350. OS_MutexGrpAdd(p_tcb, &OSTmrMutex);
  1351. /* Post to mutex */
  1352. OS_Post((OS_PEND_OBJ *)((void *)&OSTmrMutex),
  1353. p_tcb,
  1354. (void *) 0,
  1355. 0u,
  1356. ts);
  1357. }
  1358. OS_Pend((OS_PEND_OBJ *)((void *)&OSTmrCond), /* Pend on the condition variable. */
  1359. &OSTmrTaskTCB,
  1360. OS_TASK_PEND_ON_COND,
  1361. timeout);
  1362. CPU_CRITICAL_EXIT();
  1363. OSSched();
  1364. CPU_CRITICAL_ENTER(); /* Either we timed out, or were signaled. */
  1365. if (OSTmrMutex.OwnerTCBPtr == (OS_TCB *)0) { /* Can we grab the mutex? */
  1366. OS_MutexGrpAdd(&OSTmrTaskTCB, &OSTmrMutex); /* Yes, no-one else pending. */
  1367. OSTmrMutex.OwnerTCBPtr = &OSTmrTaskTCB;
  1368. OSTmrMutex.OwnerNestingCtr = 1u;
  1369. CPU_CRITICAL_EXIT();
  1370. } else {
  1371. p_tcb = OSTmrMutex.OwnerTCBPtr; /* No, we need to wait for it. */
  1372. if (p_tcb->Prio > OSTmrTaskTCB.Prio) { /* See if mutex owner has a lower priority than TmrTask.*/
  1373. OS_TaskChangePrio(p_tcb, OSTmrTaskTCB.Prio);
  1374. }
  1375. OS_Pend((OS_PEND_OBJ *)((void *)&OSTmrMutex), /* Block TmrTask until it gets the Mutex. */
  1376. &OSTmrTaskTCB,
  1377. OS_TASK_PEND_ON_MUTEX,
  1378. 0u);
  1379. CPU_CRITICAL_EXIT();
  1380. OSSched();
  1381. }
  1382. }
  1383. /*
  1384. ************************************************************************************************************************
  1385. * SIGNAL THE TIMER TASK CONDITION VARIABLE
  1386. *
  1387. * Description: Used to signal the timer task when a timer is added/removed which requires the task to reload
  1388. * its timeout. We ensure that this function is always called with the timer mutex locked.
  1389. *
  1390. * Arguments : none.
  1391. *
  1392. * Returns : none
  1393. *
  1394. * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
  1395. ************************************************************************************************************************
  1396. */
  1397. static void OS_TmrCondSignal (void)
  1398. {
  1399. OS_PEND_LIST *p_pend_list;
  1400. CPU_TS ts;
  1401. CPU_SR_ALLOC();
  1402. CPU_CRITICAL_ENTER();
  1403. #if (OS_CFG_TS_EN > 0u)
  1404. ts = OS_TS_GET(); /* Get timestamp */
  1405. OSTmrMutex.TS = ts;
  1406. #else
  1407. ts = 0u;
  1408. #endif
  1409. p_pend_list = &OSTmrCond.PendList;
  1410. if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Timer task waiting on cond? */
  1411. CPU_CRITICAL_EXIT();
  1412. return; /* No, nothing to signal. */
  1413. } else {
  1414. /* Yes, signal the timer task. */
  1415. OS_Post((OS_PEND_OBJ *)((void *)&OSTmrCond),
  1416. &OSTmrTaskTCB,
  1417. (void *) 0,
  1418. 0u,
  1419. ts);
  1420. }
  1421. CPU_CRITICAL_EXIT();
  1422. }
  1423. #endif