| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- /*
- *********************************************************************************************************
- * uC/OS-III
- * The Real-Time Kernel
- *
- * Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
- *
- * SPDX-License-Identifier: APACHE-2.0
- *
- * This software is subject to an open source license and is distributed by
- * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
- * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
- *
- *********************************************************************************************************
- */
- /*
- *********************************************************************************************************
- * TIME MANAGEMENT
- *
- * File : os_time.c
- * Version : V3.08.02
- *********************************************************************************************************
- */
- #define MICRIUM_SOURCE
- #include "os.h"
- #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
- const CPU_CHAR *os_time__c = "$Id: $";
- #endif
- /*
- ************************************************************************************************************************
- * DELAY TASK 'n' TICKS
- *
- * Description: This function is called to delay execution of the currently running task until the specified number of
- * system ticks expires. This, of course, directly equates to delaying the current task for some time to
- * expire. No delay will result if the specified delay is 0. If the specified delay is greater than 0
- * then, a context switch will result.
- *
- * Arguments : dly is a value in 'clock ticks' that the task will either delay for or, the target match value
- * of the tick counter (OSTickCtr). Note that specifying 0 means the task is not to delay.
- *
- * depending on the option argument, the task will wake up when OSTickCtr reaches:
- *
- * OS_OPT_TIME_DLY : OSTickCtr + dly
- * OS_OPT_TIME_TIMEOUT : OSTickCtr + dly
- * OS_OPT_TIME_MATCH : dly
- * OS_OPT_TIME_PERIODIC : OSTCBCurPtr->TickCtrPrev + dly
- *
- * opt specifies whether 'dly' represents absolute or relative time; default option marked with *** :
- *
- * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
- * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
- * OS_OPT_TIME_MATCH indicates that 'dly' specifies the absolute value that OSTickCtr
- * must reach before the task will be resumed.
- * OS_OPT_TIME_PERIODIC indicates that 'dly' specifies the periodic value that OSTickCtr
- * must reach before the task will be resumed.
- *
- * p_err is a pointer to a variable that will contain an error code from this call.
- *
- * OS_ERR_NONE The call was successful and the delay occurred
- * OS_ERR_OPT_INVALID If you specified an invalid option for this function
- * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
- * OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked
- * OS_ERR_TIME_DLY_ISR If you called this function from an ISR
- * OS_ERR_TIME_ZERO_DLY If the effective delay is zero
- * OS_ERR_TICK_DISABLED If kernel ticks are disabled
- *
- * Returns : none
- *
- * Note(s) : none
- ************************************************************************************************************************
- */
- void OSTimeDly (OS_TICK dly,
- OS_OPT opt,
- OS_ERR *p_err)
- {
- #if (OS_CFG_TICK_EN > 0u)
- CPU_SR_ALLOC();
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (p_err == (OS_ERR *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
- #if (OS_CFG_TICK_EN == 0u)
- *p_err = OS_ERR_TICK_DISABLED;
- return;
- #else
- #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
- if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
- *p_err = OS_ERR_TIME_DLY_ISR;
- return;
- }
- #endif
- #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
- if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
- *p_err = OS_ERR_OS_NOT_RUNNING;
- return;
- }
- #endif
- if (OSSchedLockNestingCtr > 0u) { /* Can't delay when the scheduler is locked */
- *p_err = OS_ERR_SCHED_LOCKED;
- return;
- }
- switch (opt) {
- case OS_OPT_TIME_DLY:
- case OS_OPT_TIME_TIMEOUT:
- case OS_OPT_TIME_PERIODIC:
- case OS_OPT_TIME_MATCH:
- break;
- default:
- *p_err = OS_ERR_OPT_INVALID;
- return;
- }
- #if (OS_CFG_TICK_EN > 0u)
- CPU_CRITICAL_ENTER();
- OS_TickListInsertDly(OSTCBCurPtr,
- dly,
- opt,
- p_err);
- if (*p_err != OS_ERR_NONE) {
- CPU_CRITICAL_EXIT();
- return;
- }
- OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
- CPU_CRITICAL_EXIT();
- OSSched(); /* Find next task to run! */
- #endif
- #endif
- }
- /*
- ************************************************************************************************************************
- * DELAY TASK FOR SPECIFIED TIME
- *
- * Description: This function is called to delay execution of the currently running task until some time expires. This
- * call allows you to specify the delay time in HOURS, MINUTES, SECONDS and MILLISECONDS instead of ticks.
- *
- * Arguments : hours specifies the number of hours that the task will be delayed (max. is 999 if the tick rate is
- * 1000 Hz or less otherwise, a higher value would overflow a 32-bit unsigned counter).
- *
- * minutes specifies the number of minutes (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
- *
- * seconds specifies the number of seconds (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
- *
- * milli specifies the number of milliseconds (max. 999 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
- *
- * opt specifies time delay bit-field options logically OR'd; default options marked with *** :
- *
- * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
- * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
- * OS_OPT_TIME_MATCH indicates that the delay specifies the absolute value that OSTickCtr
- * must reach before the task will be resumed.
- * OS_OPT_TIME_PERIODIC indicates that the delay specifies the periodic value that OSTickCtr
- * must reach before the task will be resumed.
- *
- * *** OS_OPT_TIME_HMSM_STRICT strictly allow only hours (0...99)
- * minutes (0...59)
- * seconds (0...59)
- * milliseconds (0...999)
- * OS_OPT_TIME_HMSM_NON_STRICT allow any value of hours (0...999)
- * minutes (0...9999)
- * seconds (0...65535)
- * milliseconds (0...4294967295)
- *
- * p_err is a pointer to a variable that will receive an error code from this call.
- *
- * OS_ERR_NONE If the function returns from the desired delay
- * OS_ERR_OPT_INVALID If you specified an invalid option for 'opt'
- * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
- * OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked
- * OS_ERR_TIME_DLY_ISR If called from an ISR
- * OS_ERR_TIME_INVALID_HOURS If you didn't specify a valid value for 'hours'
- * OS_ERR_TIME_INVALID_MINUTES If you didn't specify a valid value for 'minutes'
- * OS_ERR_TIME_INVALID_SECONDS If you didn't specify a valid value for 'seconds'
- * OS_ERR_TIME_INVALID_MILLISECONDS If you didn't specify a valid value for 'milli'
- * OS_ERR_TIME_ZERO_DLY If the effective delay is zero
- * OS_ERR_TICK_DISABLED If kernel ticks are disabled
- *
- * Returns : none
- *
- * Note(s) : 1) The resolution on the milliseconds depends on the tick rate. For example, you can't do a 10 mS delay
- * if the ticker interrupts every 100 mS. In this case, the delay would be set to 0. The actual delay
- * is rounded to the nearest tick.
- *
- * 2) Although this function allows you to delay a task for many, many hours, it's not recommended to put
- * a task to sleep for that long.
- ************************************************************************************************************************
- */
- #if (OS_CFG_TIME_DLY_HMSM_EN > 0u)
- void OSTimeDlyHMSM (CPU_INT16U hours,
- CPU_INT16U minutes,
- CPU_INT16U seconds,
- CPU_INT32U milli,
- OS_OPT opt,
- OS_ERR *p_err)
- {
- #if (OS_CFG_TICK_EN > 0u)
- #if (OS_CFG_ARG_CHK_EN > 0u)
- CPU_BOOLEAN opt_invalid;
- CPU_BOOLEAN opt_non_strict;
- #endif
- OS_OPT opt_time;
- OS_RATE_HZ tick_rate;
- OS_TICK ticks;
- CPU_SR_ALLOC();
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (p_err == (OS_ERR *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
- #if (OS_CFG_TICK_EN == 0u)
- *p_err = OS_ERR_TICK_DISABLED;
- return;
- #else
- #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
- if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
- *p_err = OS_ERR_TIME_DLY_ISR;
- return;
- }
- #endif
- #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
- if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
- *p_err = OS_ERR_OS_NOT_RUNNING;
- return;
- }
- #endif
- if (OSSchedLockNestingCtr > 0u) { /* Can't delay when the scheduler is locked */
- *p_err = OS_ERR_SCHED_LOCKED;
- return;
- }
- opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */
- switch (opt_time) {
- case OS_OPT_TIME_DLY:
- case OS_OPT_TIME_TIMEOUT:
- case OS_OPT_TIME_PERIODIC:
- case OS_OPT_TIME_MATCH:
- break;
- default:
- *p_err = OS_ERR_OPT_INVALID;
- return;
- }
- #if (OS_CFG_ARG_CHK_EN > 0u) /* Validate arguments to be within range */
- opt_invalid = ((((opt) & (~OS_OPT_TIME_OPTS_MASK)) == 0u) ? (OS_FALSE) : (OS_TRUE));
- if (opt_invalid == OS_TRUE) {
- *p_err = OS_ERR_OPT_INVALID;
- return;
- }
- opt_non_strict = ((((opt) & (OS_OPT_TIME_HMSM_NON_STRICT)) == 0u) ? (OS_FALSE) : (OS_TRUE));
- if (opt_non_strict != OS_TRUE) {
- if (milli > 999u) {
- *p_err = OS_ERR_TIME_INVALID_MILLISECONDS;
- return;
- }
- if (seconds > 59u) {
- *p_err = OS_ERR_TIME_INVALID_SECONDS;
- return;
- }
- if (minutes > 59u) {
- *p_err = OS_ERR_TIME_INVALID_MINUTES;
- return;
- }
- if (hours > 99u) {
- *p_err = OS_ERR_TIME_INVALID_HOURS;
- return;
- }
- } else {
- if (minutes > 9999u) {
- *p_err = OS_ERR_TIME_INVALID_MINUTES;
- return;
- }
- if (hours > 999u) {
- *p_err = OS_ERR_TIME_INVALID_HOURS;
- return;
- }
- }
- #endif
- /* Compute the total number of clock ticks required.. */
- /* .. (rounded to the nearest tick) */
- tick_rate = OSCfg_TickRate_Hz;
- ticks = ((((OS_TICK)hours * (OS_TICK)3600u) + ((OS_TICK)minutes * (OS_TICK)60u) + (OS_TICK)seconds) * tick_rate)
- + ((tick_rate * ((OS_TICK)milli + ((OS_TICK)500u / tick_rate))) / (OS_TICK)1000u);
- CPU_CRITICAL_ENTER();
- OS_TickListInsertDly(OSTCBCurPtr,
- ticks,
- opt_time,
- p_err);
- if (*p_err != OS_ERR_NONE) {
- CPU_CRITICAL_EXIT();
- return;
- }
- OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
- CPU_CRITICAL_EXIT();
- OSSched(); /* Find next task to run! */
- #endif
- }
- #endif
- /*
- ************************************************************************************************************************
- * RESUME A DELAYED TASK
- *
- * Description: This function is used resume a task that has been delayed through a call to either OSTimeDly() or
- * OSTimeDlyHMSM(). Note that you cannot call this function to resume a task that is waiting for an event
- * with timeout.
- *
- * Arguments : p_tcb is a pointer to the TCB of the task to resume.
- *
- * p_err is a pointer to a variable that will receive an error code
- *
- * OS_ERR_NONE Task has been resumed
- * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
- * OS_ERR_STATE_INVALID Task is in an invalid state
- * OS_ERR_TASK_NOT_DLY Task is not waiting for time to expire
- * OS_ERR_TASK_SUSPENDED Task cannot be resumed, it was suspended by OSTaskSuspend()
- * OS_ERR_TCB_INVALID If 'p_tcb' is a NULL pointer
- * OS_ERR_TIME_DLY_RESUME_ISR If called from an ISR
- *
- * Returns : none
- *
- * Note(s) : none
- ************************************************************************************************************************
- */
- #if (OS_CFG_TIME_DLY_RESUME_EN > 0u)
- void OSTimeDlyResume (OS_TCB *p_tcb,
- OS_ERR *p_err)
- {
- CPU_SR_ALLOC();
- #ifdef OS_SAFETY_CRITICAL
- if (p_err == (OS_ERR *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
- #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
- if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
- *p_err = OS_ERR_TIME_DLY_RESUME_ISR;
- return;
- }
- #endif
- #if (OS_CFG_ARG_CHK_EN > 0u) /* ---------------- VALIDATE ARGUMENTS ---------------- */
- if (p_tcb == (OS_TCB *)0) { /* User must supply a valid OS_TCB */
- *p_err = OS_ERR_TCB_INVALID;
- return;
- }
- #endif
- #if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
- if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */
- *p_err = OS_ERR_OS_NOT_RUNNING;
- return;
- }
- #endif
- CPU_CRITICAL_ENTER();
- switch (p_tcb->TaskState) {
- case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */
- case OS_TASK_STATE_PEND:
- case OS_TASK_STATE_PEND_TIMEOUT:
- case OS_TASK_STATE_SUSPENDED:
- case OS_TASK_STATE_PEND_SUSPENDED:
- case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
- CPU_CRITICAL_EXIT();
- *p_err = OS_ERR_TASK_NOT_DLY;
- break;
- case OS_TASK_STATE_DLY:
- p_tcb->TaskState = OS_TASK_STATE_RDY;
- #if (OS_CFG_TICK_EN > 0u)
- OS_TickListRemove(p_tcb); /* Remove task from tick list */
- OS_RdyListInsert(p_tcb); /* Add to ready list */
- #endif
- CPU_CRITICAL_EXIT();
- *p_err = OS_ERR_NONE;
- break;
- case OS_TASK_STATE_DLY_SUSPENDED:
- p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
- #if (OS_CFG_TICK_EN > 0u)
- OS_TickListRemove(p_tcb); /* Remove task from tick list */
- #endif
- CPU_CRITICAL_EXIT();
- *p_err = OS_ERR_TASK_SUSPENDED;
- break;
- default:
- CPU_CRITICAL_EXIT();
- *p_err = OS_ERR_STATE_INVALID;
- break;
- }
- OSSched();
- }
- #endif
- /*
- ************************************************************************************************************************
- * GET CURRENT SYSTEM TIME
- *
- * Description: This function is used by your application to obtain the current value of the counter which keeps track of
- * the number of clock ticks.
- *
- * Arguments : p_err is a pointer to a variable that will receive an error code
- *
- * OS_ERR_NONE If the call was successful
- * OS_ERR_TICK_DISABLED If kernel ticks are disabled
- *
- * Returns : The current value of OSTickCtr
- *
- * Note(s) : none
- ************************************************************************************************************************
- */
- OS_TICK OSTimeGet (OS_ERR *p_err)
- {
- OS_TICK ticks;
- #if (OS_CFG_TICK_EN > 0u)
- CPU_SR_ALLOC();
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (p_err == (OS_ERR *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return (0u);
- }
- #endif
- #if (OS_CFG_TICK_EN > 0u)
- CPU_CRITICAL_ENTER();
- #if (OS_CFG_DYN_TICK_EN > 0u)
- if (OSRunning == OS_STATE_OS_RUNNING) {
- ticks = OSTickCtr + OS_DynTickGet();
- } else {
- ticks = OSTickCtr;
- }
- #else
- ticks = OSTickCtr;
- #endif
- CPU_CRITICAL_EXIT();
- *p_err = OS_ERR_NONE;
- #else
- ticks = 0u;
- *p_err = OS_ERR_TICK_DISABLED;
- #endif
- return (ticks);
- }
- /*
- ************************************************************************************************************************
- * SET SYSTEM CLOCK
- *
- * Description: This function sets the counter which keeps track of the number of clock ticks.
- *
- * Arguments : ticks is the desired tick value
- *
- * p_err is a pointer to a variable that will receive an error code
- *
- * OS_ERR_NONE If the call was successful
- * OS_ERR_TICK_DISABLED If kernel ticks are disabled
- *
- * Returns : none
- *
- * Note(s) : none
- ************************************************************************************************************************
- */
- void OSTimeSet (OS_TICK ticks,
- OS_ERR *p_err)
- {
- #if (OS_CFG_TICK_EN > 0u)
- CPU_SR_ALLOC();
- #else
- (void)ticks;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (p_err == (OS_ERR *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
- #if (OS_CFG_TICK_EN > 0u)
- CPU_CRITICAL_ENTER();
- OSTickCtr = ticks;
- OS_TRACE_TICK_INCREMENT(OSTickCtr);
- CPU_CRITICAL_EXIT();
- *p_err = OS_ERR_NONE;
- #else
- *p_err = OS_ERR_TICK_DISABLED;
- #endif
- }
- /*
- ************************************************************************************************************************
- * PROCESS SYSTEM TICK
- *
- * Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a
- * 'clock tick'). This function should be called by the tick ISR.
- *
- * Arguments : none
- *
- * Returns : none
- *
- * Note(s) : none
- ************************************************************************************************************************
- */
- void OSTimeTick (void)
- {
- if (OSRunning != OS_STATE_OS_RUNNING) {
- return;
- }
- OSTimeTickHook(); /* Call user definable hook */
- #if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u)
- OS_SchedRoundRobin(&OSRdyList[OSPrioCur]); /* Update quanta ctr for the task which just ran */
- #endif
- #if (OS_CFG_TICK_EN > 0u)
- OS_TickUpdate(1u); /* Update from the ISR */
- #endif
- }
- /*
- ************************************************************************************************************************
- * PROCESS SYSTEM TICK (DYNAMIC)
- *
- * Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a
- * 'clock tick'). This function should be called by the tick ISR.
- *
- * Arguments : none
- *
- * Returns : none
- *
- * Note(s) : none
- ************************************************************************************************************************
- */
- #if (OS_CFG_DYN_TICK_EN > 0u)
- void OSTimeDynTick (OS_TICK ticks)
- {
- if (OSRunning != OS_STATE_OS_RUNNING) {
- return;
- }
- OSTimeTickHook();
- OS_TickUpdate(ticks); /* Update from the ISR */
- }
- #endif
|