LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_time.c
Go to the documentation of this file.
1 /*
2 ************************************************************************************************************************
3 * uC/OS-III
4 * The Real-Time Kernel
5 *
6 * (c) Copyright 2009-2012; 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.03.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 
33 #define MICRIUM_SOURCE
34 #include <os.h>
35 
36 #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
37 const CPU_CHAR *os_time__c = "$Id: $";
38 #endif
39 
40 /*
41 ************************************************************************************************************************
42 * DELAY TASK 'n' TICKS
43 *
44 * Description: This function is called to delay execution of the currently running task until the specified number of
45 * system ticks expires. This, of course, directly equates to delaying the current task for some time to
46 * expire. No delay will result if the specified delay is 0. If the specified delay is greater than 0
47 * then, a context switch will result.
48 *
49 * Arguments : dly is a value in 'clock ticks' that the task will either delay for or, the target match value
50 * of the tick counter (OSTickCtr). Note that specifying 0 means the task is not to delay.
51 *
52 * depending on the option argument, the task will wake up when OSTickCtr reaches:
53 *
54 * OS_OPT_TIME_DLY : OSTickCtr + dly
55 * OS_OPT_TIME_TIMEOUT : OSTickCtr + dly
56 * OS_OPT_TIME_MATCH : dly
57 * OS_OPT_TIME_PERIODIC : OSTCBCurPtr->TickCtrPrev + dly
58 *
59 * opt specifies whether 'dly' represents absolute or relative time; default option marked with *** :
60 *
61 * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
62 * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
63 * OS_OPT_TIME_MATCH indicates that 'dly' specifies the absolute value that OSTickCtr
64 * must reach before the task will be resumed.
65 * OS_OPT_TIME_PERIODIC indicates that 'dly' specifies the periodic value that OSTickCtr
66 * must reach before the task will be resumed.
67 *
68 * p_err is a pointer to a variable that will contain an error code from this call.
69 *
70 * OS_ERR_NONE the call was successful and the delay occurred.
71 * OS_ERR_OPT_INVALID if you specified an invalid option for this function.
72 * OS_ERR_SCHED_LOCKED can't delay when the scheduler is locked.
73 * OS_ERR_TIME_DLY_ISR if you called this function from an ISR.
74 * OS_ERR_TIME_ZERO_DLY if you specified a delay of zero.
75 *
76 * Returns : none
77 ************************************************************************************************************************
78 */
79 
80 void OSTimeDly (OS_TICK dly,
81  OS_OPT opt,
82  OS_ERR *p_err)
83 {
84  CPU_SR_ALLOC();
85 
86 
87 
88 #ifdef OS_SAFETY_CRITICAL
89  if (p_err == (OS_ERR *)0) {
90  OS_SAFETY_CRITICAL_EXCEPTION();
91  return;
92  }
93 #endif
94 
95 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
96  if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
97  *p_err = OS_ERR_TIME_DLY_ISR;
98  return;
99  }
100 #endif
101 
102  if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */
103  *p_err = OS_ERR_SCHED_LOCKED;
104  return;
105  }
106 
107  switch (opt) {
108  case OS_OPT_TIME_DLY:
109  case OS_OPT_TIME_TIMEOUT:
111  if (dly == (OS_TICK)0u) { /* 0 means no delay! */
112  *p_err = OS_ERR_TIME_ZERO_DLY;
113  return;
114  }
115  break;
116 
117  case OS_OPT_TIME_MATCH:
118  break;
119 
120  default:
121  *p_err = OS_ERR_OPT_INVALID;
122  return;
123  }
124 
126  OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY;
128  dly,
129  opt,
130  p_err);
131  if (*p_err != OS_ERR_NONE) {
133  return;
134  }
135  OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
137  OSSched(); /* Find next task to run! */
138  *p_err = OS_ERR_NONE;
139 }
140 
141 /*$PAGE*/
142 /*
143 ************************************************************************************************************************
144 * DELAY TASK FOR SPECIFIED TIME
145 *
146 * Description: This function is called to delay execution of the currently running task until some time expires. This
147 * call allows you to specify the delay time in HOURS, MINUTES, SECONDS and MILLISECONDS instead of ticks.
148 *
149 * Arguments : hours specifies the number of hours that the task will be delayed (max. is 999 if the tick rate is
150 * 1000 Hz or less otherwise, a higher value would overflow a 32-bit unsigned counter).
151 *
152 * minutes specifies the number of minutes (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
153 *
154 * seconds specifies the number of seconds (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
155 *
156 * milli specifies the number of milliseconds (max. 999 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
157 *
158 * opt specifies time delay bit-field options logically OR'd; default options marked with *** :
159 *
160 * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
161 * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
162 * OS_OPT_TIME_MATCH indicates that the delay specifies the absolute value that OSTickCtr
163 * must reach before the task will be resumed.
164 * OS_OPT_TIME_PERIODIC indicates that the delay specifies the periodic value that OSTickCtr
165 * must reach before the task will be resumed.
166 *
167 * *** OS_OPT_TIME_HMSM_STRICT strictly allow only hours (0...99)
168 * minutes (0...59)
169 * seconds (0...59)
170 * milliseconds (0...999)
171 * OS_OPT_TIME_HMSM_NON_STRICT allow any value of hours (0...999)
172 * minutes (0...9999)
173 * seconds (0...65535)
174 * milliseconds (0...4294967295)
175 *
176 * p_err is a pointer to a variable that will receive an error code from this call.
177 *
178 * OS_ERR_NONE If the function returns from the desired delay
179 * OS_ERR_OPT_INVALID If you specified an invalid option for 'opt'
180 * OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked
181 * OS_ERR_TIME_DLY_ISR If called from an ISR
182 * OS_ERR_TIME_INVALID_HOURS If you didn't specify a valid value for 'hours'
183 * OS_ERR_TIME_INVALID_MINUTES If you didn't specify a valid value for 'minutes'
184 * OS_ERR_TIME_INVALID_SECONDS If you didn't specify a valid value for 'seconds'
185 * OS_ERR_TIME_INVALID_MILLISECONDS If you didn't specify a valid value for 'milli'
186 * OS_ERR_TIME_ZERO_DLY If hours, minutes, seconds and milli are all 0
187 *
188 * Returns : none
189 *
190 * Note(s) : 1) The resolution on the milliseconds depends on the tick rate. For example, you can't do a 10 mS delay
191 * if the ticker interrupts every 100 mS. In this case, the delay would be set to 0. The actual delay
192 * is rounded to the nearest tick.
193 *
194 * 2) Although this function allows you to delay a task for many, many hours, it's not recommended to put
195 * a task to sleep for that long.
196 ************************************************************************************************************************
197 */
198 
199 #if OS_CFG_TIME_DLY_HMSM_EN > 0u
200 void OSTimeDlyHMSM (CPU_INT16U hours,
201  CPU_INT16U minutes,
202  CPU_INT16U seconds,
203  CPU_INT32U milli,
204  OS_OPT opt,
205  OS_ERR *p_err)
206 {
207 #if OS_CFG_ARG_CHK_EN > 0u
208  CPU_BOOLEAN opt_invalid;
209  CPU_BOOLEAN opt_non_strict;
210 #endif
211  OS_OPT opt_time;
212  OS_RATE_HZ tick_rate;
213  OS_TICK ticks;
214  CPU_SR_ALLOC();
215 
216 
217 
218 #ifdef OS_SAFETY_CRITICAL
219  if (p_err == (OS_ERR *)0) {
220  OS_SAFETY_CRITICAL_EXCEPTION();
221  return;
222  }
223 #endif
224 
225 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
226  if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
227  *p_err = OS_ERR_TIME_DLY_ISR;
228  return;
229  }
230 #endif
231 
232  if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */
233  *p_err = OS_ERR_SCHED_LOCKED;
234  return;
235  }
236 
237  opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */
238  switch (opt_time) {
239  case OS_OPT_TIME_DLY:
240  case OS_OPT_TIME_TIMEOUT:
242  if (milli == (CPU_INT32U)0u) { /* Make sure we didn't specify a 0 delay */
243  if (seconds == (CPU_INT16U)0u) {
244  if (minutes == (CPU_INT16U)0u) {
245  if (hours == (CPU_INT16U)0u) {
246  *p_err = OS_ERR_TIME_ZERO_DLY;
247  return;
248  }
249  }
250  }
251  }
252  break;
253 
254  case OS_OPT_TIME_MATCH:
255  break;
256 
257  default:
258  *p_err = OS_ERR_OPT_INVALID;
259  return;
260  }
261 
262 #if OS_CFG_ARG_CHK_EN > 0u /* Validate arguments to be within range */
263  opt_invalid = DEF_BIT_IS_SET_ANY(opt, ~OS_OPT_TIME_OPTS_MASK);
264  if (opt_invalid == DEF_YES) {
265  *p_err = OS_ERR_OPT_INVALID;
266  return;
267  }
268 
269  opt_non_strict = DEF_BIT_IS_SET(opt, OS_OPT_TIME_HMSM_NON_STRICT);
270  if (opt_non_strict != DEF_YES) {
271  if (milli > (CPU_INT32U)999u) {
273  return;
274  }
275  if (seconds > (CPU_INT16U)59u) {
277  return;
278  }
279  if (minutes > (CPU_INT16U)59u) {
281  return;
282  }
283  if (hours > (CPU_INT16U)99u) {
284  *p_err = OS_ERR_TIME_INVALID_HOURS;
285  return;
286  }
287  } else {
288  if (minutes > (CPU_INT16U)9999u) {
290  return;
291  }
292  if (hours > (CPU_INT16U)999u) {
293  *p_err = OS_ERR_TIME_INVALID_HOURS;
294  return;
295  }
296  }
297 #endif
298 
299  /* Compute the total number of clock ticks required.. */
300  /* .. (rounded to the nearest tick) */
301  tick_rate = OSCfg_TickRate_Hz;
302  ticks = ((OS_TICK)hours * (OS_TICK)3600u + (OS_TICK)minutes * (OS_TICK)60u + (OS_TICK)seconds) * tick_rate
303  + (tick_rate * ((OS_TICK)milli + (OS_TICK)500u / tick_rate)) / (OS_TICK)1000u;
304 
305  if (ticks > (OS_TICK)0u) {
307  OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY;
309  ticks,
310  opt_time,
311  p_err);
312  if (*p_err != OS_ERR_NONE) {
314  return;
315  }
316  OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
318  OSSched(); /* Find next task to run! */
319  *p_err = OS_ERR_NONE;
320  } else {
321  *p_err = OS_ERR_TIME_ZERO_DLY;
322  }
323 }
324 #endif
325 /*$PAGE*/
326 /*
327 ************************************************************************************************************************
328 * RESUME A DELAYED TASK
329 *
330 * Description: This function is used resume a task that has been delayed through a call to either OSTimeDly() or
331 * OSTimeDlyHMSM(). Note that cannot call this function to resume a task that is waiting for an event
332 * with timeout.
333 *
334 * Arguments : p_tcb is a pointer to the TCB of the task to resume.
335 *
336 * p_err is a pointer to a variable that will receive an error code
337 *
338 * OS_ERR_NONE Task has been resumed
339 * OS_ERR_STATE_INVALID Task is in an invalid state
340 * OS_ERR_TIME_DLY_RESUME_ISR If called from an ISR
341 * OS_ERR_TIME_NOT_DLY Task is not waiting for time to expire
342 * OS_ERR_TASK_SUSPENDED Task cannot be resumed, it was suspended by OSTaskSuspend()
343 *
344 * Note(s) : none
345 ************************************************************************************************************************
346 */
347 
348 #if OS_CFG_TIME_DLY_RESUME_EN > 0u
349 void OSTimeDlyResume (OS_TCB *p_tcb,
350  OS_ERR *p_err)
351 {
352  CPU_SR_ALLOC();
353 
354 
355 
356 #ifdef OS_SAFETY_CRITICAL
357  if (p_err == (OS_ERR *)0) {
358  OS_SAFETY_CRITICAL_EXCEPTION();
359  return;
360  }
361 #endif
362 
363 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
364  if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
366  return;
367  }
368 #endif
369 
370 #if OS_CFG_ARG_CHK_EN > 0u
371  if (p_tcb == (OS_TCB *)0) { /* Not possible for the running task to be delayed! */
372  *p_err = OS_ERR_TASK_NOT_DLY;
373  return;
374  }
375 #endif
376 
378  if (p_tcb == OSTCBCurPtr) { /* Not possible for the running task to be delayed! */
379  *p_err = OS_ERR_TASK_NOT_DLY;
381  return;
382  }
383 
384  switch (p_tcb->TaskState) {
385  case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */
387  *p_err = OS_ERR_TASK_NOT_DLY;
388  break;
389 
390  case OS_TASK_STATE_DLY:
392  p_tcb->TaskState = OS_TASK_STATE_RDY;
393  OS_TickListRemove(p_tcb); /* Remove task from tick list */
394  OS_RdyListInsert(p_tcb); /* Add to ready list */
396  *p_err = OS_ERR_NONE;
397  break;
398 
399  case OS_TASK_STATE_PEND:
401  *p_err = OS_ERR_TASK_NOT_DLY;
402  break;
403 
406  *p_err = OS_ERR_TASK_NOT_DLY;
407  break;
408 
411  *p_err = OS_ERR_TASK_NOT_DLY;
412  break;
413 
416  p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
417  OS_TickListRemove(p_tcb); /* Remove task from tick list */
419  *p_err = OS_ERR_TASK_SUSPENDED;
420  break;
421 
424  *p_err = OS_ERR_TASK_NOT_DLY;
425  break;
426 
429  *p_err = OS_ERR_TASK_NOT_DLY;
430  break;
431 
432  default:
434  *p_err = OS_ERR_STATE_INVALID;
435  break;
436  }
437 
438  OSSched();
439 }
440 #endif
441 /*$PAGE*/
442 /*
443 ************************************************************************************************************************
444 * GET CURRENT SYSTEM TIME
445 *
446 * Description: This function is used by your application to obtain the current value of the counter which keeps track of
447 * the number of clock ticks.
448 *
449 * Arguments : p_err is a pointer to a variable that will receive an error code
450 *
451 * OS_ERR_NONE If the call was successful
452 *
453 * Returns : The current value of OSTickCtr
454 ************************************************************************************************************************
455 */
456 
458 {
459  OS_TICK ticks;
460  CPU_SR_ALLOC();
461 
462 
463 
464 #ifdef OS_SAFETY_CRITICAL
465  if (p_err == (OS_ERR *)0) {
466  OS_SAFETY_CRITICAL_EXCEPTION();
467  return ((OS_TICK)0);
468  }
469 #endif
470 
472  ticks = OSTickCtr;
474  *p_err = OS_ERR_NONE;
475  return (ticks);
476 }
477 
478 /*
479 ************************************************************************************************************************
480 * SET SYSTEM CLOCK
481 *
482 * Description: This function sets the counter which keeps track of the number of clock ticks.
483 *
484 * Arguments : ticks is the desired tick value
485 *
486 * p_err is a pointer to a variable that will receive an error code
487 *
488 * OS_ERR_NONE If the call was successful
489 *
490 * Returns : none
491 ************************************************************************************************************************
492 */
493 
494 void OSTimeSet (OS_TICK ticks,
495  OS_ERR *p_err)
496 {
497  CPU_SR_ALLOC();
498 
499 
500 
501 #ifdef OS_SAFETY_CRITICAL
502  if (p_err == (OS_ERR *)0) {
503  OS_SAFETY_CRITICAL_EXCEPTION();
504  return;
505  }
506 #endif
507 
509  OSTickCtr = ticks;
511  *p_err = OS_ERR_NONE;
512 }
513 
514 /*$PAGE*/
515 /*
516 ************************************************************************************************************************
517 * PROCESS SYSTEM TICK
518 *
519 * Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a
520 * 'clock tick'). This function should be called by the tick ISR.
521 *
522 * Arguments : none
523 *
524 * Returns : none
525 ************************************************************************************************************************
526 */
527 
528 void OSTimeTick (void)
529 {
530  OS_ERR err;
531 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
532  CPU_TS ts;
533 #endif
534 
535 
536  OSTimeTickHook(); /* Call user definable hook */
537 
538 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
539 
540  ts = OS_TS_GET(); /* Get timestamp */
541  OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK, /* Post to ISR queue */
542  (void *)&OSRdyList[OSPrioCur],
543  (void *) 0,
544  (OS_MSG_SIZE) 0u,
545  (OS_FLAGS ) 0u,
546  (OS_OPT ) 0u,
547  (CPU_TS ) ts,
548  (OS_ERR *)&err);
549 
550 #else
551 
552  (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB, /* Signal tick task */
554  (OS_ERR *)&err);
555 
556 
557 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
558  OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
559 #endif
560 
561 #if OS_CFG_TMR_EN > 0u
562  OSTmrUpdateCtr--;
563  if (OSTmrUpdateCtr == (OS_CTR)0u) {
564  OSTmrUpdateCtr = OSTmrUpdateCnt;
565  OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB, /* Signal timer task */
567  (OS_ERR *)&err);
568  }
569 #endif
570 
571 #endif
572 }