os_time.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /*
  2. ************************************************************************************************************************
  3. * uC/OS-III
  4. * The Real-Time Kernel
  5. *
  6. * (c) Copyright 2009-2011; Micrium, Inc.; Weston, FL
  7. * All rights reserved. Protected by international copyright laws.
  8. *
  9. * TIME MANAGEMENT
  10. *
  11. * File : OS_TIME.C
  12. * By : JJL
  13. * Version : V3.02.00
  14. *
  15. * LICENSING TERMS:
  16. * ---------------
  17. * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
  18. * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
  19. * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
  20. * application/product. We provide ALL the source code for your convenience and to help you
  21. * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
  22. * it commercially without paying a licensing fee.
  23. *
  24. * Knowledge of the source code may NOT be used to develop a similar product.
  25. *
  26. * Please help us continue to provide the embedded community with the finest software available.
  27. * Your honesty is greatly appreciated.
  28. *
  29. * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
  30. ************************************************************************************************************************
  31. */
  32. #include <os.h>
  33. #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
  34. const CPU_CHAR *os_time__c = "$Id: $";
  35. #endif
  36. /*
  37. ************************************************************************************************************************
  38. * DELAY TASK 'n' TICKS
  39. *
  40. * Description: This function is called to delay execution of the currently running task until the specified number of
  41. * system ticks expires. This, of course, directly equates to delaying the current task for some time to
  42. * expire. No delay will result if the specified delay is 0. If the specified delay is greater than 0
  43. * then, a context switch will result.
  44. *
  45. * Arguments : dly is a value in 'clock ticks' that the task will either delay for or, the target match value
  46. * of the tick counter (OSTickCtr). Note that specifying 0 means the task is not to delay.
  47. *
  48. * depending on the option argument, the task will wake up when OSTickCtr reaches:
  49. *
  50. * OS_OPT_TIME_DLY : OSTickCtr + dly
  51. * OS_OPT_TIME_TIMEOUT : OSTickCtr + dly
  52. * OS_OPT_TIME_MATCH : dly
  53. * OS_OPT_TIME_PERIODIC : OSTCBCurPtr->TickCtrPrev + dly
  54. *
  55. * opt specifies whether 'dly' represents absolute or relative time; default option marked with *** :
  56. *
  57. * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
  58. * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
  59. * OS_OPT_TIME_MATCH indicates that 'dly' specifies the absolute value that OSTickCtr
  60. * must reach before the task will be resumed.
  61. * OS_OPT_TIME_PERIODIC indicates that 'dly' specifies the periodic value that OSTickCtr
  62. * must reach before the task will be resumed.
  63. *
  64. * p_err is a pointer to a variable that will contain an error code from this call.
  65. *
  66. * OS_ERR_NONE the call was successful and the delay occurred.
  67. * OS_ERR_OPT_INVALID if you specified an invalid option for this function.
  68. * OS_ERR_SCHED_LOCKED can't delay when the scheduler is locked.
  69. * OS_ERR_TIME_DLY_ISR if you called this function from an ISR.
  70. * OS_ERR_TIME_ZERO_DLY if you specified a delay of zero.
  71. *
  72. * Returns : none
  73. ************************************************************************************************************************
  74. */
  75. void OSTimeDly (OS_TICK dly,
  76. OS_OPT opt,
  77. OS_ERR *p_err)
  78. {
  79. CPU_SR_ALLOC();
  80. #ifdef OS_SAFETY_CRITICAL
  81. if (p_err == (OS_ERR *)0) {
  82. OS_SAFETY_CRITICAL_EXCEPTION();
  83. return;
  84. }
  85. #endif
  86. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  87. if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
  88. *p_err = OS_ERR_TIME_DLY_ISR;
  89. return;
  90. }
  91. #endif
  92. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */
  93. *p_err = OS_ERR_SCHED_LOCKED;
  94. return;
  95. }
  96. switch (opt) {
  97. case OS_OPT_TIME_DLY:
  98. case OS_OPT_TIME_TIMEOUT:
  99. case OS_OPT_TIME_PERIODIC:
  100. if (dly == (OS_TICK)0u) { /* 0 means no delay! */
  101. *p_err = OS_ERR_TIME_ZERO_DLY;
  102. return;
  103. }
  104. break;
  105. case OS_OPT_TIME_MATCH:
  106. break;
  107. default:
  108. *p_err = OS_ERR_OPT_INVALID;
  109. return;
  110. }
  111. OS_CRITICAL_ENTER();
  112. OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY;
  113. OS_TickListInsert(OSTCBCurPtr,
  114. dly,
  115. opt,
  116. p_err);
  117. if (*p_err != OS_ERR_NONE) {
  118. OS_CRITICAL_EXIT_NO_SCHED();
  119. return;
  120. }
  121. OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
  122. OS_CRITICAL_EXIT_NO_SCHED();
  123. OSSched(); /* Find next task to run! */
  124. *p_err = OS_ERR_NONE;
  125. }
  126. /*$PAGE*/
  127. /*
  128. ************************************************************************************************************************
  129. * DELAY TASK FOR SPECIFIED TIME
  130. *
  131. * Description: This function is called to delay execution of the currently running task until some time expires. This
  132. * call allows you to specify the delay time in HOURS, MINUTES, SECONDS and MILLISECONDS instead of ticks.
  133. *
  134. * Arguments : hours specifies the number of hours that the task will be delayed (max. is 999 if the tick rate is
  135. * 1000 Hz or less otherwise, a higher value would overflow a 32-bit unsigned counter).
  136. *
  137. * minutes specifies the number of minutes (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
  138. *
  139. * seconds specifies the number of seconds (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
  140. *
  141. * milli specifies the number of milliseconds (max. 999 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
  142. *
  143. * opt specifies time delay bit-field options logically OR'd; default options marked with *** :
  144. *
  145. * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
  146. * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
  147. * OS_OPT_TIME_MATCH indicates that the delay specifies the absolute value that OSTickCtr
  148. * must reach before the task will be resumed.
  149. * OS_OPT_TIME_PERIODIC indicates that the delay specifies the periodic value that OSTickCtr
  150. * must reach before the task will be resumed.
  151. *
  152. * *** OS_OPT_TIME_HMSM_STRICT strictly allow only hours (0...99)
  153. * minutes (0...59)
  154. * seconds (0...59)
  155. * milliseconds (0...999)
  156. * OS_OPT_TIME_HMSM_NON_STRICT allow any value of hours (0...999)
  157. * minutes (0...9999)
  158. * seconds (0...65535)
  159. * milliseconds (0...4294967295)
  160. *
  161. * p_err is a pointer to a variable that will receive an error code from this call.
  162. *
  163. * OS_ERR_NONE If the function returns from the desired delay
  164. * OS_ERR_OPT_INVALID If you specified an invalid option for 'opt'
  165. * OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked
  166. * OS_ERR_TIME_DLY_ISR If called from an ISR
  167. * OS_ERR_TIME_INVALID_HOURS If you didn't specify a valid value for 'hours'
  168. * OS_ERR_TIME_INVALID_MINUTES If you didn't specify a valid value for 'minutes'
  169. * OS_ERR_TIME_INVALID_SECONDS If you didn't specify a valid value for 'seconds'
  170. * OS_ERR_TIME_INVALID_MILLISECONDS If you didn't specify a valid value for 'milli'
  171. * OS_ERR_TIME_ZERO_DLY If hours, minutes, seconds and milli are all 0
  172. *
  173. * Returns : none
  174. *
  175. * Note(s) : 1) The resolution on the milliseconds depends on the tick rate. For example, you can't do a 10 mS delay
  176. * if the ticker interrupts every 100 mS. In this case, the delay would be set to 0. The actual delay
  177. * is rounded to the nearest tick.
  178. *
  179. * 2) Although this function allows you to delay a task for many, many hours, it's not recommended to put
  180. * a task to sleep for that long.
  181. ************************************************************************************************************************
  182. */
  183. #if OS_CFG_TIME_DLY_HMSM_EN > 0u
  184. void OSTimeDlyHMSM (CPU_INT16U hours,
  185. CPU_INT16U minutes,
  186. CPU_INT16U seconds,
  187. CPU_INT32U milli,
  188. OS_OPT opt,
  189. OS_ERR *p_err)
  190. {
  191. #if OS_CFG_ARG_CHK_EN > 0u
  192. CPU_BOOLEAN opt_invalid;
  193. CPU_BOOLEAN opt_non_strict;
  194. #endif
  195. OS_OPT opt_time;
  196. OS_RATE_HZ tick_rate;
  197. OS_TICK ticks;
  198. CPU_SR_ALLOC();
  199. #ifdef OS_SAFETY_CRITICAL
  200. if (p_err == (OS_ERR *)0) {
  201. OS_SAFETY_CRITICAL_EXCEPTION();
  202. return;
  203. }
  204. #endif
  205. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  206. if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
  207. *p_err = OS_ERR_TIME_DLY_ISR;
  208. return;
  209. }
  210. #endif
  211. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */
  212. *p_err = OS_ERR_SCHED_LOCKED;
  213. return;
  214. }
  215. opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */
  216. switch (opt_time) {
  217. case OS_OPT_TIME_DLY:
  218. case OS_OPT_TIME_TIMEOUT:
  219. case OS_OPT_TIME_PERIODIC:
  220. if (milli == (CPU_INT32U)0u) { /* Make sure we didn't specify a 0 delay */
  221. if (seconds == (CPU_INT16U)0u) {
  222. if (minutes == (CPU_INT16U)0u) {
  223. if (hours == (CPU_INT16U)0u) {
  224. *p_err = OS_ERR_TIME_ZERO_DLY;
  225. return;
  226. }
  227. }
  228. }
  229. }
  230. break;
  231. case OS_OPT_TIME_MATCH:
  232. break;
  233. default:
  234. *p_err = OS_ERR_OPT_INVALID;
  235. return;
  236. }
  237. #if OS_CFG_ARG_CHK_EN > 0u /* Validate arguments to be within range */
  238. opt_invalid = DEF_BIT_IS_SET_ANY(opt, ~OS_OPT_TIME_OPTS_MASK);
  239. if (opt_invalid == DEF_YES) {
  240. *p_err = OS_ERR_OPT_INVALID;
  241. return;
  242. }
  243. opt_non_strict = DEF_BIT_IS_SET(opt, OS_OPT_TIME_HMSM_NON_STRICT);
  244. if (opt_non_strict != DEF_YES) {
  245. if (milli > (CPU_INT32U)999u) {
  246. *p_err = OS_ERR_TIME_INVALID_MILLISECONDS;
  247. return;
  248. }
  249. if (seconds > (CPU_INT16U)59u) {
  250. *p_err = OS_ERR_TIME_INVALID_SECONDS;
  251. return;
  252. }
  253. if (minutes > (CPU_INT16U)59u) {
  254. *p_err = OS_ERR_TIME_INVALID_MINUTES;
  255. return;
  256. }
  257. if (hours > (CPU_INT16U)99u) {
  258. *p_err = OS_ERR_TIME_INVALID_HOURS;
  259. return;
  260. }
  261. } else {
  262. if (minutes > (CPU_INT16U)9999u) {
  263. *p_err = OS_ERR_TIME_INVALID_MINUTES;
  264. return;
  265. }
  266. if (hours > (CPU_INT16U)999u) {
  267. *p_err = OS_ERR_TIME_INVALID_HOURS;
  268. return;
  269. }
  270. }
  271. #endif
  272. /* Compute the total number of clock ticks required.. */
  273. /* .. (rounded to the nearest tick) */
  274. tick_rate = OSCfg_TickRate_Hz;
  275. ticks = ((OS_TICK)hours * (OS_TICK)3600u + (OS_TICK)minutes * (OS_TICK)60u + (OS_TICK)seconds) * tick_rate
  276. + (tick_rate * ((OS_TICK)milli + (OS_TICK)500u / tick_rate)) / (OS_TICK)1000u;
  277. if (ticks > (OS_TICK)0u) {
  278. OS_CRITICAL_ENTER();
  279. OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY;
  280. OS_TickListInsert(OSTCBCurPtr,
  281. ticks,
  282. opt_time,
  283. p_err);
  284. if (*p_err != OS_ERR_NONE) {
  285. OS_CRITICAL_EXIT_NO_SCHED();
  286. return;
  287. }
  288. OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
  289. OS_CRITICAL_EXIT_NO_SCHED();
  290. OSSched(); /* Find next task to run! */
  291. *p_err = OS_ERR_NONE;
  292. } else {
  293. *p_err = OS_ERR_TIME_ZERO_DLY;
  294. }
  295. }
  296. #endif
  297. /*$PAGE*/
  298. /*
  299. ************************************************************************************************************************
  300. * RESUME A DELAYED TASK
  301. *
  302. * Description: This function is used resume a task that has been delayed through a call to either OSTimeDly() or
  303. * OSTimeDlyHMSM(). Note that cannot call this function to resume a task that is waiting for an event
  304. * with timeout.
  305. *
  306. * Arguments : p_tcb is a pointer to the TCB of the task to resume.
  307. *
  308. * p_err is a pointer to a variable that will receive an error code
  309. *
  310. * OS_ERR_NONE Task has been resumed
  311. * OS_ERR_STATE_INVALID Task is in an invalid state
  312. * OS_ERR_TIME_DLY_RESUME_ISR Task is not waiting for time to expire
  313. * OS_ERR_TIME_NOT_DLY Task is not waiting for time to expire
  314. * OS_ERR_TASK_SUSPENDED Task cannot be resumed, it was suspended by OSTaskSuspend()
  315. *
  316. * Note(s) : none
  317. ************************************************************************************************************************
  318. */
  319. #if OS_CFG_TIME_DLY_RESUME_EN > 0u
  320. void OSTimeDlyResume (OS_TCB *p_tcb,
  321. OS_ERR *p_err)
  322. {
  323. CPU_SR_ALLOC();
  324. #ifdef OS_SAFETY_CRITICAL
  325. if (p_err == (OS_ERR *)0) {
  326. OS_SAFETY_CRITICAL_EXCEPTION();
  327. return;
  328. }
  329. #endif
  330. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  331. if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
  332. *p_err = OS_ERR_TIME_DLY_RESUME_ISR;
  333. return;
  334. }
  335. #endif
  336. #if OS_CFG_ARG_CHK_EN > 0u
  337. if (p_tcb == (OS_TCB *)0) { /* Not possible for the running task to be delayed! */
  338. *p_err = OS_ERR_TASK_NOT_DLY;
  339. return;
  340. }
  341. #endif
  342. CPU_CRITICAL_ENTER();
  343. switch (p_tcb->TaskState) {
  344. case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */
  345. CPU_CRITICAL_EXIT();
  346. *p_err = OS_ERR_TASK_NOT_DLY;
  347. break;
  348. case OS_TASK_STATE_DLY:
  349. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  350. p_tcb->TaskState = OS_TASK_STATE_RDY;
  351. OS_TickListRemove(p_tcb); /* Remove task from tick list */
  352. OS_RdyListInsert(p_tcb); /* Add to ready list */
  353. OS_CRITICAL_EXIT_NO_SCHED();
  354. *p_err = OS_ERR_NONE;
  355. break;
  356. case OS_TASK_STATE_PEND:
  357. CPU_CRITICAL_EXIT();
  358. *p_err = OS_ERR_TASK_NOT_DLY;
  359. break;
  360. case OS_TASK_STATE_PEND_TIMEOUT:
  361. CPU_CRITICAL_EXIT();
  362. *p_err = OS_ERR_TASK_NOT_DLY;
  363. break;
  364. case OS_TASK_STATE_SUSPENDED:
  365. CPU_CRITICAL_EXIT();
  366. *p_err = OS_ERR_TASK_NOT_DLY;
  367. break;
  368. case OS_TASK_STATE_DLY_SUSPENDED:
  369. OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
  370. p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
  371. OS_TickListRemove(p_tcb); /* Remove task from tick list */
  372. OS_CRITICAL_EXIT_NO_SCHED();
  373. *p_err = OS_ERR_TASK_SUSPENDED;
  374. break;
  375. case OS_TASK_STATE_PEND_SUSPENDED:
  376. CPU_CRITICAL_EXIT();
  377. *p_err = OS_ERR_TASK_NOT_DLY;
  378. break;
  379. case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
  380. CPU_CRITICAL_EXIT();
  381. *p_err = OS_ERR_TASK_NOT_DLY;
  382. break;
  383. default:
  384. CPU_CRITICAL_EXIT();
  385. *p_err = OS_ERR_STATE_INVALID;
  386. break;
  387. }
  388. OSSched();
  389. }
  390. #endif
  391. /*$PAGE*/
  392. /*
  393. ************************************************************************************************************************
  394. * GET CURRENT SYSTEM TIME
  395. *
  396. * Description: This function is used by your application to obtain the current value of the counter which keeps track of
  397. * the number of clock ticks.
  398. *
  399. * Arguments : p_err is a pointer to a variable that will receive an error code
  400. *
  401. * OS_ERR_NONE If the call was successful
  402. *
  403. * Returns : The current value of OSTickCtr
  404. ************************************************************************************************************************
  405. */
  406. OS_TICK OSTimeGet (OS_ERR *p_err)
  407. {
  408. OS_TICK ticks;
  409. CPU_SR_ALLOC();
  410. #ifdef OS_SAFETY_CRITICAL
  411. if (p_err == (OS_ERR *)0) {
  412. OS_SAFETY_CRITICAL_EXCEPTION();
  413. return ((OS_TICK)0);
  414. }
  415. #endif
  416. CPU_CRITICAL_ENTER();
  417. ticks = OSTickCtr;
  418. CPU_CRITICAL_EXIT();
  419. *p_err = OS_ERR_NONE;
  420. return (ticks);
  421. }
  422. /*
  423. ************************************************************************************************************************
  424. * SET SYSTEM CLOCK
  425. *
  426. * Description: This function sets the counter which keeps track of the number of clock ticks.
  427. *
  428. * Arguments : ticks is the desired tick value
  429. *
  430. * p_err is a pointer to a variable that will receive an error code
  431. *
  432. * OS_ERR_NONE If the call was successful
  433. *
  434. * Returns : none
  435. ************************************************************************************************************************
  436. */
  437. void OSTimeSet (OS_TICK ticks,
  438. OS_ERR *p_err)
  439. {
  440. CPU_SR_ALLOC();
  441. #ifdef OS_SAFETY_CRITICAL
  442. if (p_err == (OS_ERR *)0) {
  443. OS_SAFETY_CRITICAL_EXCEPTION();
  444. return;
  445. }
  446. #endif
  447. CPU_CRITICAL_ENTER();
  448. OSTickCtr = ticks;
  449. CPU_CRITICAL_EXIT();
  450. *p_err = OS_ERR_NONE;
  451. }
  452. /*$PAGE*/
  453. /*
  454. ************************************************************************************************************************
  455. * PROCESS SYSTEM TICK
  456. *
  457. * Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a
  458. * 'clock tick'). This function should be called by the tick ISR.
  459. *
  460. * Arguments : none
  461. *
  462. * Returns : none
  463. ************************************************************************************************************************
  464. */
  465. void OSTimeTick (void)
  466. {
  467. OS_ERR err;
  468. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  469. CPU_TS ts;
  470. #endif
  471. OSTimeTickHook(); /* Call user definable hook */
  472. #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
  473. ts = OS_TS_GET(); /* Get timestamp */
  474. OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK, /* Post to ISR queue */
  475. (void *)&OSRdyList[OSPrioCur],
  476. (void *) 0,
  477. (OS_MSG_SIZE) 0u,
  478. (OS_FLAGS ) 0u,
  479. (OS_OPT ) 0u,
  480. (CPU_TS ) ts,
  481. (OS_ERR *)&err);
  482. #else
  483. (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB, /* Signal tick task */
  484. (OS_OPT ) OS_OPT_POST_NONE,
  485. (OS_ERR *)&err);
  486. #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
  487. OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
  488. #endif
  489. #if OS_CFG_TMR_EN > 0u
  490. OSTmrUpdateCtr--;
  491. if (OSTmrUpdateCtr == (OS_CTR)0u) {
  492. OSTmrUpdateCtr = OSTmrUpdateCnt;
  493. OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB, /* Signal timer task */
  494. (OS_OPT ) OS_OPT_POST_NONE,
  495. (OS_ERR *)&err);
  496. }
  497. #endif
  498. #endif
  499. }