kopia lustrzana https://github.com/OpenRTX/OpenRTX
1658 wiersze
62 KiB
C
1658 wiersze
62 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/OS-III
|
|
* The Real-Time Kernel
|
|
*
|
|
* Copyright 2009-2020 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.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* TIMER MANAGEMENT
|
|
*
|
|
* File : os_tmr.c
|
|
* Version : V3.08.00
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define MICRIUM_SOURCE
|
|
#include "os.h"
|
|
|
|
#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
|
|
const CPU_CHAR *os_tmr__c = "$Id: $";
|
|
#endif
|
|
|
|
|
|
#if (OS_CFG_TMR_EN > 0u)
|
|
/*
|
|
************************************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
static void OS_TmrLock (void);
|
|
static void OS_TmrUnlock (void);
|
|
|
|
static void OS_TmrCondCreate(void);
|
|
static void OS_TmrCondSignal(void);
|
|
static void OS_TmrCondWait (OS_TICK timeout);
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* CREATE A TIMER
|
|
*
|
|
* Description: This function is called by your application code to create a timer.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to a timer control block
|
|
*
|
|
* p_name Is a pointer to an ASCII string that is used to name the timer. Names are useful for
|
|
* debugging.
|
|
*
|
|
* dly Initial delay.
|
|
* If the timer is configured for ONE-SHOT mode, this is the timeout used
|
|
* If the timer is configured for PERIODIC mode, this is the first timeout to wait for
|
|
* before the timer starts entering periodic mode
|
|
*
|
|
* period The 'period' being repeated for the timer.
|
|
* If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will
|
|
* automatically restart with the same period.
|
|
*
|
|
* opt Specifies either:
|
|
*
|
|
* OS_OPT_TMR_ONE_SHOT The timer counts down only once
|
|
* OS_OPT_TMR_PERIODIC The timer counts down and then reloads itself
|
|
*
|
|
* p_callback Is a pointer to a callback function that will be called when the timer expires. The
|
|
* callback function must be declared as follows:
|
|
*
|
|
* void MyCallback (OS_TMR *p_tmr, void *p_arg);
|
|
*
|
|
* p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The call succeeded
|
|
* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the timer after you called
|
|
* OSSafetyCriticalStart()
|
|
* OS_ERR_OBJ_PTR_NULL Is 'p_tmr' is a NULL pointer
|
|
* OS_ERR_OPT_INVALID You specified an invalid option
|
|
* OS_ERR_TMR_INVALID_CALLBACK You specified an invalid callback for a periodic timer
|
|
* OS_ERR_TMR_INVALID_DLY You specified an invalid delay
|
|
* OS_ERR_TMR_INVALID_PERIOD You specified an invalid period
|
|
* OS_ERR_TMR_ISR If the call was made from an ISR
|
|
* OS_ERR_OBJ_CREATED If the timer was already created
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function only creates the timer. In other words, the timer is not started when created. To
|
|
* start the timer, call OSTmrStart().
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OSTmrCreate (OS_TMR *p_tmr,
|
|
CPU_CHAR *p_name,
|
|
OS_TICK dly,
|
|
OS_TICK period,
|
|
OS_OPT opt,
|
|
OS_TMR_CALLBACK_PTR p_callback,
|
|
void *p_callback_arg,
|
|
OS_ERR *p_err)
|
|
{
|
|
#ifdef OS_SAFETY_CRITICAL
|
|
if (p_err == (OS_ERR *)0) {
|
|
OS_SAFETY_CRITICAL_EXCEPTION();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef OS_SAFETY_CRITICAL_IEC61508
|
|
if (OSSafetyCriticalStartFlag == OS_TRUE) {
|
|
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
|
|
if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_ISR;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */
|
|
*p_err = OS_ERR_OBJ_PTR_NULL;
|
|
return;
|
|
}
|
|
|
|
switch (opt) {
|
|
case OS_OPT_TMR_PERIODIC:
|
|
if (period == 0u) {
|
|
*p_err = OS_ERR_TMR_INVALID_PERIOD;
|
|
return;
|
|
}
|
|
|
|
if (p_callback == (OS_TMR_CALLBACK_PTR)0) { /* No point in a periodic timer without a callback */
|
|
*p_err = OS_ERR_TMR_INVALID_CALLBACK;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case OS_OPT_TMR_ONE_SHOT:
|
|
if (dly == 0u) {
|
|
*p_err = OS_ERR_TMR_INVALID_DLY;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_OPT_INVALID;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (OSRunning == OS_STATE_OS_RUNNING) { /* Only lock when the kernel is running */
|
|
OS_TmrLock();
|
|
}
|
|
|
|
p_tmr->State = OS_TMR_STATE_STOPPED; /* Initialize the timer fields */
|
|
#if (OS_OBJ_TYPE_REQ > 0u)
|
|
if (p_tmr->Type == OS_OBJ_TYPE_TMR) {
|
|
if (OSRunning == OS_STATE_OS_RUNNING) {
|
|
OS_TmrUnlock();
|
|
}
|
|
*p_err = OS_ERR_OBJ_CREATED;
|
|
return;
|
|
}
|
|
p_tmr->Type = OS_OBJ_TYPE_TMR;
|
|
#endif
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
p_tmr->NamePtr = p_name;
|
|
#else
|
|
(void)p_name;
|
|
#endif
|
|
p_tmr->Dly = dly * OSTmrToTicksMult; /* Convert to Timer Start Delay to ticks */
|
|
p_tmr->Remain = 0u;
|
|
p_tmr->Period = period * OSTmrToTicksMult; /* Convert to Timer Period to ticks */
|
|
p_tmr->Opt = opt;
|
|
p_tmr->CallbackPtr = p_callback;
|
|
p_tmr->CallbackPtrArg = p_callback_arg;
|
|
p_tmr->NextPtr = (OS_TMR *)0;
|
|
p_tmr->PrevPtr = (OS_TMR *)0;
|
|
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OS_TmrDbgListAdd(p_tmr);
|
|
#endif
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrQty++; /* Keep track of the number of timers created */
|
|
#endif
|
|
|
|
if (OSRunning == OS_STATE_OS_RUNNING) {
|
|
OS_TmrUnlock();
|
|
}
|
|
|
|
*p_err = OS_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* DELETE A TIMER
|
|
*
|
|
* Description: This function is called by your application code to delete a timer.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to the timer to stop and delete.
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The call succeeded
|
|
* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the timer after you called
|
|
* OSStart()
|
|
* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
|
|
* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
|
|
* OS_ERR_TMR_INACTIVE If the timer was not created
|
|
* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
|
|
* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
|
|
* OS_ERR_TMR_ISR If the function was called from an ISR
|
|
*
|
|
* Returns : OS_TRUE if the timer was deleted
|
|
* OS_FALSE if not or upon an error
|
|
*
|
|
* Note(s) : none
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
#if (OS_CFG_TMR_DEL_EN > 0u)
|
|
CPU_BOOLEAN OSTmrDel (OS_TMR *p_tmr,
|
|
OS_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN success;
|
|
OS_TICK time;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#ifdef OS_SAFETY_CRITICAL
|
|
if (p_err == (OS_ERR *)0) {
|
|
OS_SAFETY_CRITICAL_EXCEPTION();
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#ifdef OS_SAFETY_CRITICAL_IEC61508
|
|
if (OSSafetyCriticalStartFlag == OS_TRUE) {
|
|
*p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
|
|
if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_ISR;
|
|
return (OS_FALSE);
|
|
}
|
|
#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 (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) {
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
|
|
if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
|
|
*p_err = OS_ERR_OBJ_TYPE;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
OS_TmrLock();
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */
|
|
time = OSTmrTaskTickBase;
|
|
} else {
|
|
#if (OS_CFG_DYN_TICK_EN > 0u)
|
|
time = OSTickCtr + OS_DynTickGet();
|
|
#else
|
|
time = OSTickCtr;
|
|
#endif
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OS_TmrDbgListRemove(p_tmr);
|
|
#endif
|
|
|
|
switch (p_tmr->State) {
|
|
case OS_TMR_STATE_RUNNING:
|
|
case OS_TMR_STATE_TIMEOUT:
|
|
OS_TmrUnlink(p_tmr, time); /* Remove from the list */
|
|
OS_TmrClr(p_tmr);
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrQty--; /* One less timer */
|
|
#endif
|
|
*p_err = OS_ERR_NONE;
|
|
success = OS_TRUE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
|
|
case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
|
|
OS_TmrClr(p_tmr); /* Clear timer fields */
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrQty--; /* One less timer */
|
|
#endif
|
|
*p_err = OS_ERR_NONE;
|
|
success = OS_TRUE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_UNUSED: /* Already deleted */
|
|
*p_err = OS_ERR_TMR_INACTIVE;
|
|
success = OS_FALSE;
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_TMR_INVALID_STATE;
|
|
success = OS_FALSE;
|
|
break;
|
|
}
|
|
|
|
OS_TmrUnlock();
|
|
|
|
return (success);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
|
|
*
|
|
* Description: This function is called to get the number of timer increments before a timer times out.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to the timer to obtain the remaining time from.
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The call succeeded
|
|
* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
|
|
* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
|
|
* OS_ERR_TMR_INACTIVE If 'p_tmr' points to a timer that is not active
|
|
* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
|
|
* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
|
|
* OS_ERR_TMR_ISR If the call was made from an ISR
|
|
*
|
|
* Returns : The time remaining for the timer to expire. The time represents 'timer' increments (typically 1/10 sec).
|
|
*
|
|
* Note(s) : none
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
OS_TICK OSTmrRemainGet (OS_TMR *p_tmr,
|
|
OS_ERR *p_err)
|
|
{
|
|
OS_TMR *p_tmr1;
|
|
OS_TICK remain;
|
|
|
|
|
|
#ifdef OS_SAFETY_CRITICAL
|
|
if (p_err == (OS_ERR *)0) {
|
|
OS_SAFETY_CRITICAL_EXCEPTION();
|
|
return (0u);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
|
|
if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_ISR;
|
|
return (0u);
|
|
}
|
|
#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 (0u);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) {
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return (0u);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
|
|
if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
|
|
*p_err = OS_ERR_OBJ_TYPE;
|
|
return (0u);
|
|
}
|
|
#endif
|
|
|
|
OS_TmrLock();
|
|
|
|
switch (p_tmr->State) {
|
|
case OS_TMR_STATE_RUNNING:
|
|
p_tmr1 = OSTmrListPtr;
|
|
remain = 0u;
|
|
while (p_tmr1 != (OS_TMR *)0) { /* Add up all the deltas up until the current timer */
|
|
remain += p_tmr1->Remain;
|
|
if (p_tmr1 == p_tmr) {
|
|
break;
|
|
}
|
|
p_tmr1 = p_tmr1->NextPtr;
|
|
}
|
|
remain /= OSTmrToTicksMult;
|
|
*p_err = OS_ERR_NONE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
|
|
if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
|
|
if (p_tmr->Dly == 0u) {
|
|
remain = p_tmr->Period / OSTmrToTicksMult;
|
|
} else {
|
|
remain = p_tmr->Dly / OSTmrToTicksMult;
|
|
}
|
|
} else {
|
|
remain = p_tmr->Dly / OSTmrToTicksMult;
|
|
}
|
|
*p_err = OS_ERR_NONE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_TIMEOUT: /* Within a callback, timers are in the TIMEOUT state */
|
|
case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT timers can be in the COMPLETED state */
|
|
*p_err = OS_ERR_NONE;
|
|
remain = 0u;
|
|
break;
|
|
|
|
case OS_TMR_STATE_UNUSED:
|
|
*p_err = OS_ERR_TMR_INACTIVE;
|
|
remain = 0u;
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_TMR_INVALID_STATE;
|
|
remain = 0u;
|
|
break;
|
|
}
|
|
|
|
OS_TmrUnlock();
|
|
|
|
return (remain);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* SET A TIMER
|
|
*
|
|
* Description: This function is called by your application code to set a timer.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to a timer control block
|
|
*
|
|
* dly Initial delay.
|
|
* If the timer is configured for ONE-SHOT mode, this is the timeout used
|
|
* If the timer is configured for PERIODIC mode, this is the first timeout to wait for
|
|
* before the timer starts entering periodic mode
|
|
*
|
|
* period The 'period' being repeated for the timer.
|
|
* If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will
|
|
* automatically restart with the same period.
|
|
*
|
|
* p_callback Is a pointer to a callback function that will be called when the timer expires. The
|
|
* callback function must be declared as follows:
|
|
*
|
|
* void MyCallback (OS_TMR *p_tmr, void *p_arg);
|
|
*
|
|
* p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The timer was configured as expected
|
|
* OS_ERR_OBJ_TYPE If the object type is invalid
|
|
* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
|
|
* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer or invalid option
|
|
* OS_ERR_TMR_INVALID_CALLBACK you specified an invalid callback for a periodic timer
|
|
* OS_ERR_TMR_INVALID_DLY You specified an invalid delay
|
|
* OS_ERR_TMR_INVALID_PERIOD You specified an invalid period
|
|
* OS_ERR_TMR_ISR If the call was made from an ISR
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function can be called on a running timer. The change to the delay and period will only
|
|
* take effect after the current period or delay has passed. Change to the callback will take
|
|
* effect immediately.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OSTmrSet (OS_TMR *p_tmr,
|
|
OS_TICK dly,
|
|
OS_TICK period,
|
|
OS_TMR_CALLBACK_PTR p_callback,
|
|
void *p_callback_arg,
|
|
OS_ERR *p_err)
|
|
{
|
|
#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) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_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 (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
|
|
if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
|
|
*p_err = OS_ERR_OBJ_TYPE;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
switch (p_tmr->Opt) {
|
|
case OS_OPT_TMR_PERIODIC:
|
|
if (period == 0u) {
|
|
*p_err = OS_ERR_TMR_INVALID_PERIOD;
|
|
return;
|
|
}
|
|
|
|
if (p_callback == (OS_TMR_CALLBACK_PTR)0) { /* No point in a periodic timer without a callback */
|
|
*p_err = OS_ERR_TMR_INVALID_CALLBACK;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case OS_OPT_TMR_ONE_SHOT:
|
|
if (dly == 0u) {
|
|
*p_err = OS_ERR_TMR_INVALID_DLY;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
OS_TmrLock();
|
|
|
|
p_tmr->Dly = dly * OSTmrToTicksMult; /* Convert Timer Delay to ticks */
|
|
p_tmr->Period = period * OSTmrToTicksMult; /* Convert Timer Period to ticks */
|
|
p_tmr->CallbackPtr = p_callback;
|
|
p_tmr->CallbackPtrArg = p_callback_arg;
|
|
|
|
*p_err = OS_ERR_NONE;
|
|
|
|
OS_TmrUnlock();
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* START A TIMER
|
|
*
|
|
* Description: This function is called by your application code to start a timer.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to an OS_TMR
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The timer was started
|
|
* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
|
|
* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
|
|
* OS_ERR_TMR_INACTIVE If the timer was not created
|
|
* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
|
|
* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
|
|
* OS_ERR_TMR_ISR If the call was made from an ISR
|
|
*
|
|
* Returns : OS_TRUE is the timer was started
|
|
* OS_FALSE if not or upon an error
|
|
*
|
|
* Note(s) : 1) When starting/restarting a timer, regardless if it is in PERIODIC or ONE-SHOT mode, the timer is
|
|
* linked to the timer list with the OS_OPT_LINK_DLY option. This option sets the initial expiration
|
|
* time for the timer. For timers in PERIODIC mode, subsequent expiration times are handled by
|
|
* the OS_TmrTask().
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr,
|
|
OS_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN success;
|
|
OS_TICK time;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#ifdef OS_SAFETY_CRITICAL
|
|
if (p_err == (OS_ERR *)0) {
|
|
OS_SAFETY_CRITICAL_EXCEPTION();
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
|
|
if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_ISR;
|
|
return (OS_FALSE);
|
|
}
|
|
#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 (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) {
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
|
|
if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
|
|
*p_err = OS_ERR_OBJ_TYPE;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
OS_TmrLock();
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */
|
|
time = OSTmrTaskTickBase;
|
|
} else {
|
|
#if (OS_CFG_DYN_TICK_EN > 0u)
|
|
time = OSTickCtr + OS_DynTickGet();
|
|
#else
|
|
time = OSTickCtr;
|
|
#endif
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
|
|
switch (p_tmr->State) {
|
|
case OS_TMR_STATE_RUNNING: /* Restart the timer */
|
|
case OS_TMR_STATE_TIMEOUT:
|
|
p_tmr->State = OS_TMR_STATE_RUNNING;
|
|
OS_TmrUnlink(p_tmr, time); /* Remove from current position in List */
|
|
if (p_tmr->Dly == 0u) {
|
|
p_tmr->Remain = p_tmr->Period;
|
|
} else {
|
|
p_tmr->Remain = p_tmr->Dly;
|
|
}
|
|
OS_TmrLink(p_tmr, time); /* Add timer to List */
|
|
*p_err = OS_ERR_NONE;
|
|
success = OS_TRUE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_STOPPED: /* Start the timer */
|
|
case OS_TMR_STATE_COMPLETED:
|
|
p_tmr->State = OS_TMR_STATE_RUNNING;
|
|
if (p_tmr->Dly == 0u) {
|
|
p_tmr->Remain = p_tmr->Period;
|
|
} else {
|
|
p_tmr->Remain = p_tmr->Dly;
|
|
}
|
|
OS_TmrLink(p_tmr, time); /* Add timer to List */
|
|
*p_err = OS_ERR_NONE;
|
|
success = OS_TRUE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_UNUSED: /* Timer not created */
|
|
*p_err = OS_ERR_TMR_INACTIVE;
|
|
success = OS_FALSE;
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_TMR_INVALID_STATE;
|
|
success = OS_FALSE;
|
|
break;
|
|
}
|
|
|
|
OS_TmrUnlock();
|
|
|
|
return (success);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* FIND OUT WHAT STATE A TIMER IS IN
|
|
*
|
|
* Description: This function is called to determine what state the timer is in:
|
|
*
|
|
* OS_TMR_STATE_UNUSED the timer has not been created
|
|
* OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped
|
|
* OS_TMR_STATE_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout
|
|
* OS_TMR_SATE_RUNNING the timer is currently running
|
|
*
|
|
* Arguments : p_tmr Is a pointer to the desired timer
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The return value reflects the state of the timer
|
|
* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
|
|
* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet
|
|
* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
|
|
* OS_ERR_TMR_INVALID_STATE If the timer is not in a valid state
|
|
* OS_ERR_TMR_ISR If the call was made from an ISR
|
|
*
|
|
* Returns : The current state of the timer (see description).
|
|
*
|
|
* Note(s) : none
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
OS_STATE OSTmrStateGet (OS_TMR *p_tmr,
|
|
OS_ERR *p_err)
|
|
{
|
|
OS_STATE state;
|
|
|
|
|
|
|
|
#ifdef OS_SAFETY_CRITICAL
|
|
if (p_err == (OS_ERR *)0) {
|
|
OS_SAFETY_CRITICAL_EXCEPTION();
|
|
return (OS_TMR_STATE_UNUSED);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
|
|
if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_ISR;
|
|
return (OS_TMR_STATE_UNUSED);
|
|
}
|
|
#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 (OS_TMR_STATE_UNUSED);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) {
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return (OS_TMR_STATE_UNUSED);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
|
|
if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
|
|
*p_err = OS_ERR_OBJ_TYPE;
|
|
return (OS_TMR_STATE_UNUSED);
|
|
}
|
|
#endif
|
|
|
|
OS_TmrLock();
|
|
|
|
state = p_tmr->State;
|
|
switch (state) {
|
|
case OS_TMR_STATE_UNUSED:
|
|
case OS_TMR_STATE_STOPPED:
|
|
case OS_TMR_STATE_COMPLETED:
|
|
case OS_TMR_STATE_RUNNING:
|
|
case OS_TMR_STATE_TIMEOUT:
|
|
*p_err = OS_ERR_NONE;
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_TMR_INVALID_STATE;
|
|
break;
|
|
}
|
|
|
|
OS_TmrUnlock();
|
|
|
|
return (state);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* STOP A TIMER
|
|
*
|
|
* Description: This function is called by your application code to stop a timer.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to the timer to stop.
|
|
*
|
|
* opt Allows you to specify an option to this functions which can be:
|
|
*
|
|
* OS_OPT_TMR_NONE Do nothing special but stop the timer
|
|
* OS_OPT_TMR_CALLBACK Execute the callback function, pass it the callback argument
|
|
* specified when the timer was created.
|
|
* OS_OPT_TMR_CALLBACK_ARG Execute the callback function, pass it the callback argument
|
|
* specified in THIS function call
|
|
*
|
|
* callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function
|
|
* instead of the timer's callback argument. In other words, use 'callback_arg' passed in
|
|
* THIS function INSTEAD of p_tmr->OSTmrCallbackArg
|
|
*
|
|
* p_err Is a pointer to an error code. '*p_err' will contain one of the following:
|
|
*
|
|
* OS_ERR_NONE The timer has stopped
|
|
* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer
|
|
* 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_TMR_INACTIVE If the timer was not created
|
|
* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer
|
|
* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state
|
|
* OS_ERR_TMR_ISR If the function was called from an ISR
|
|
* OS_ERR_TMR_NO_CALLBACK If the timer does not have a callback function defined
|
|
* OS_ERR_TMR_STOPPED If the timer was already stopped
|
|
*
|
|
* Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE)
|
|
* OS_FALSE If not
|
|
*
|
|
* Note(s) : none
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN OSTmrStop (OS_TMR *p_tmr,
|
|
OS_OPT opt,
|
|
void *p_callback_arg,
|
|
OS_ERR *p_err)
|
|
{
|
|
OS_TMR_CALLBACK_PTR p_fnct;
|
|
CPU_BOOLEAN success;
|
|
OS_TICK time;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#ifdef OS_SAFETY_CRITICAL
|
|
if (p_err == (OS_ERR *)0) {
|
|
OS_SAFETY_CRITICAL_EXCEPTION();
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
|
|
if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */
|
|
*p_err = OS_ERR_TMR_ISR;
|
|
return (OS_FALSE);
|
|
}
|
|
#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 (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_ARG_CHK_EN > 0u)
|
|
if (p_tmr == (OS_TMR *)0) {
|
|
*p_err = OS_ERR_TMR_INVALID;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
|
|
if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */
|
|
*p_err = OS_ERR_OBJ_TYPE;
|
|
return (OS_FALSE);
|
|
}
|
|
#endif
|
|
|
|
OS_TmrLock();
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */
|
|
time = OSTmrTaskTickBase;
|
|
} else {
|
|
#if (OS_CFG_DYN_TICK_EN > 0u)
|
|
time = OSTickCtr + OS_DynTickGet();
|
|
#else
|
|
time = OSTickCtr;
|
|
#endif
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
switch (p_tmr->State) {
|
|
case OS_TMR_STATE_RUNNING:
|
|
case OS_TMR_STATE_TIMEOUT:
|
|
p_tmr->State = OS_TMR_STATE_STOPPED; /* Ensure that any callbacks see the stop state */
|
|
switch (opt) {
|
|
case OS_OPT_TMR_CALLBACK:
|
|
OS_TmrUnlink(p_tmr, time); /* Remove from timer list */
|
|
p_fnct = p_tmr->CallbackPtr; /* Execute callback function ... */
|
|
if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { /* ... if available */
|
|
(*p_fnct)(p_tmr, p_tmr->CallbackPtrArg);/* Use callback arg when timer was created */
|
|
} else {
|
|
*p_err = OS_ERR_TMR_NO_CALLBACK;
|
|
}
|
|
break;
|
|
|
|
case OS_OPT_TMR_CALLBACK_ARG:
|
|
OS_TmrUnlink(p_tmr, time); /* Remove from timer list */
|
|
p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available ... */
|
|
if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
|
|
(*p_fnct)(p_tmr, p_callback_arg); /* .. using the 'callback_arg' provided in call */
|
|
} else {
|
|
*p_err = OS_ERR_TMR_NO_CALLBACK;
|
|
}
|
|
break;
|
|
|
|
case OS_OPT_TMR_NONE:
|
|
OS_TmrUnlink(p_tmr, time); /* Remove from timer list */
|
|
break;
|
|
|
|
default:
|
|
OS_TmrUnlock();
|
|
*p_err = OS_ERR_OPT_INVALID;
|
|
return (OS_FALSE);
|
|
}
|
|
*p_err = OS_ERR_NONE;
|
|
success = OS_TRUE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or */
|
|
case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
|
|
p_tmr->State = OS_TMR_STATE_STOPPED;
|
|
*p_err = OS_ERR_TMR_STOPPED;
|
|
success = OS_TRUE;
|
|
break;
|
|
|
|
case OS_TMR_STATE_UNUSED: /* Timer was not created */
|
|
*p_err = OS_ERR_TMR_INACTIVE;
|
|
success = OS_FALSE;
|
|
break;
|
|
|
|
default:
|
|
*p_err = OS_ERR_TMR_INVALID_STATE;
|
|
success = OS_FALSE;
|
|
break;
|
|
}
|
|
|
|
OS_TmrUnlock();
|
|
|
|
return (success);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* CLEAR TIMER FIELDS
|
|
*
|
|
* Description: This function is called to clear all timer fields.
|
|
*
|
|
* Argument(s): p_tmr Is a pointer to the timer to clear
|
|
* -----
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OS_TmrClr (OS_TMR *p_tmr)
|
|
{
|
|
p_tmr->State = OS_TMR_STATE_UNUSED; /* Clear timer fields */
|
|
#if (OS_OBJ_TYPE_REQ > 0u)
|
|
p_tmr->Type = OS_OBJ_TYPE_NONE;
|
|
#endif
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
p_tmr->NamePtr = (CPU_CHAR *)((void *)"?TMR");
|
|
#endif
|
|
p_tmr->Dly = 0u;
|
|
p_tmr->Remain = 0u;
|
|
p_tmr->Period = 0u;
|
|
p_tmr->Opt = 0u;
|
|
p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)0;
|
|
p_tmr->CallbackPtrArg = (void *)0;
|
|
p_tmr->NextPtr = (OS_TMR *)0;
|
|
p_tmr->PrevPtr = (OS_TMR *)0;
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* ADD/REMOVE TIMER TO/FROM DEBUG TABLE
|
|
*
|
|
* Description: These functions are called by uC/OS-III to add or remove a timer to/from a timer debug table.
|
|
*
|
|
* Arguments : p_tmr is a pointer to the timer to add/remove
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
void OS_TmrDbgListAdd (OS_TMR *p_tmr)
|
|
{
|
|
p_tmr->DbgPrevPtr = (OS_TMR *)0;
|
|
if (OSTmrDbgListPtr == (OS_TMR *)0) {
|
|
p_tmr->DbgNextPtr = (OS_TMR *)0;
|
|
} else {
|
|
p_tmr->DbgNextPtr = OSTmrDbgListPtr;
|
|
OSTmrDbgListPtr->DbgPrevPtr = p_tmr;
|
|
}
|
|
OSTmrDbgListPtr = p_tmr;
|
|
}
|
|
|
|
|
|
|
|
void OS_TmrDbgListRemove (OS_TMR *p_tmr)
|
|
{
|
|
OS_TMR *p_tmr_next;
|
|
OS_TMR *p_tmr_prev;
|
|
|
|
|
|
p_tmr_prev = p_tmr->DbgPrevPtr;
|
|
p_tmr_next = p_tmr->DbgNextPtr;
|
|
|
|
if (p_tmr_prev == (OS_TMR *)0) {
|
|
OSTmrDbgListPtr = p_tmr_next;
|
|
if (p_tmr_next != (OS_TMR *)0) {
|
|
p_tmr_next->DbgPrevPtr = (OS_TMR *)0;
|
|
}
|
|
p_tmr->DbgNextPtr = (OS_TMR *)0;
|
|
|
|
} else if (p_tmr_next == (OS_TMR *)0) {
|
|
p_tmr_prev->DbgNextPtr = (OS_TMR *)0;
|
|
p_tmr->DbgPrevPtr = (OS_TMR *)0;
|
|
|
|
} else {
|
|
p_tmr_prev->DbgNextPtr = p_tmr_next;
|
|
p_tmr_next->DbgPrevPtr = p_tmr_prev;
|
|
p_tmr->DbgNextPtr = (OS_TMR *)0;
|
|
p_tmr->DbgPrevPtr = (OS_TMR *)0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* INITIALIZE THE TIMER MANAGER
|
|
*
|
|
* Description: This function is called by OSInit() to initialize the timer manager module.
|
|
*
|
|
* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
|
|
*
|
|
* OS_ERR_NONE
|
|
* OS_ERR_TMR_STK_INVALID if you didn't specify a stack for the timer task
|
|
* OS_ERR_TMR_STK_SIZE_INVALID if you didn't allocate enough space for the timer stack
|
|
* OS_ERR_PRIO_INVALID if you specified the same priority as the idle task
|
|
* OS_ERR_xxx any error code returned by OSTaskCreate()
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OS_TmrInit (OS_ERR *p_err)
|
|
{
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrQty = 0u; /* Keep track of the number of timers created */
|
|
OSTmrDbgListPtr = (OS_TMR *)0;
|
|
#endif
|
|
|
|
OSTmrListPtr = (OS_TMR *)0; /* Create an empty timer list */
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrListEntries = 0u;
|
|
#endif
|
|
/* Calculate Timer to Ticks multiplier */
|
|
OSTmrToTicksMult = OSCfg_TickRate_Hz / OSCfg_TmrTaskRate_Hz;
|
|
|
|
#if (OS_CFG_TS_EN > 0u)
|
|
OSTmrTaskTime = 0u;
|
|
OSTmrTaskTimeMax = 0u;
|
|
#endif
|
|
|
|
OSMutexCreate(&OSTmrMutex, /* Use a mutex to protect the timers */
|
|
#if (OS_CFG_DBG_EN == 0u)
|
|
(CPU_CHAR *)0,
|
|
#else
|
|
(CPU_CHAR *)"OS Tmr Mutex",
|
|
#endif
|
|
p_err);
|
|
if (*p_err != OS_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
OS_TmrCondCreate();
|
|
/* -------------- CREATE THE TIMER TASK --------------- */
|
|
if (OSCfg_TmrTaskStkBasePtr == (CPU_STK *)0) {
|
|
*p_err = OS_ERR_TMR_STK_INVALID;
|
|
return;
|
|
}
|
|
|
|
if (OSCfg_TmrTaskStkSize < OSCfg_StkSizeMin) {
|
|
*p_err = OS_ERR_TMR_STK_SIZE_INVALID;
|
|
return;
|
|
}
|
|
|
|
if (OSCfg_TmrTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) {
|
|
*p_err = OS_ERR_TMR_PRIO_INVALID;
|
|
return;
|
|
}
|
|
|
|
OSTaskCreate(&OSTmrTaskTCB,
|
|
#if (OS_CFG_DBG_EN == 0u)
|
|
(CPU_CHAR *)0,
|
|
#else
|
|
(CPU_CHAR *)"uC/OS-III Timer Task",
|
|
#endif
|
|
OS_TmrTask,
|
|
(void *)0,
|
|
OSCfg_TmrTaskPrio,
|
|
OSCfg_TmrTaskStkBasePtr,
|
|
OSCfg_TmrTaskStkLimit,
|
|
OSCfg_TmrTaskStkSize,
|
|
0u,
|
|
0u,
|
|
(void *)0,
|
|
(OS_OPT_TASK_STK_CHK | (OS_OPT)(OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS)),
|
|
p_err);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* ADD A TIMER TO THE TIMER LIST
|
|
*
|
|
* Description: This function is called to add a timer to the timer list.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to the timer to add.
|
|
*
|
|
* time Is the system time when this timer was linked.
|
|
* -----
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OS_TmrLink (OS_TMR *p_tmr,
|
|
OS_TICK time)
|
|
{
|
|
OS_TMR *p_tmr1;
|
|
OS_TMR *p_tmr2;
|
|
OS_TICK remain;
|
|
OS_TICK delta;
|
|
|
|
|
|
if (OSTmrListPtr == (OS_TMR *)0) { /* Is the list empty? */
|
|
p_tmr->NextPtr = (OS_TMR *)0; /* Yes, this is the first entry */
|
|
p_tmr->PrevPtr = (OS_TMR *)0;
|
|
OSTmrListPtr = p_tmr;
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrListEntries = 1u;
|
|
#endif
|
|
OSTmrTaskTickBase = time;
|
|
OS_TmrCondSignal();
|
|
|
|
return;
|
|
}
|
|
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrListEntries++;
|
|
#endif
|
|
|
|
delta = (time + p_tmr->Remain) - OSTmrTaskTickBase;
|
|
|
|
p_tmr2 = OSTmrListPtr; /* No, Insert somewhere in the list in delta order */
|
|
remain = p_tmr2->Remain;
|
|
|
|
if ((delta < remain) &&
|
|
(p_tmr2->PrevPtr == (OS_TMR *)0)) { /* Are we the new head of the list? */
|
|
p_tmr2->Remain = remain - delta;
|
|
p_tmr->PrevPtr = (OS_TMR *)0;
|
|
p_tmr->NextPtr = p_tmr2;
|
|
p_tmr2->PrevPtr = p_tmr;
|
|
OSTmrListPtr = p_tmr;
|
|
|
|
OSTmrTaskTickBase = time;
|
|
OS_TmrCondSignal();
|
|
|
|
return;
|
|
}
|
|
|
|
/* No */
|
|
delta -= remain; /* Make delta relative to the current head. */
|
|
p_tmr1 = p_tmr2;
|
|
p_tmr2 = p_tmr1->NextPtr;
|
|
|
|
|
|
while ((p_tmr2 != (OS_TMR *)0) && /* Find the appropriate position in the delta list. */
|
|
(delta >= p_tmr2->Remain)) {
|
|
delta -= p_tmr2->Remain; /* Update our delta as we traverse the list. */
|
|
p_tmr1 = p_tmr2;
|
|
p_tmr2 = p_tmr2->NextPtr;
|
|
}
|
|
|
|
|
|
if (p_tmr2 != (OS_TMR *)0) { /* Our entry is not the last element in the list. */
|
|
p_tmr1 = p_tmr2->PrevPtr;
|
|
p_tmr->Remain = delta; /* Store remaining time */
|
|
p_tmr->PrevPtr = p_tmr1;
|
|
p_tmr->NextPtr = p_tmr2;
|
|
p_tmr2->Remain -= delta; /* Reduce time of next entry in the list */
|
|
p_tmr2->PrevPtr = p_tmr;
|
|
p_tmr1->NextPtr = p_tmr;
|
|
|
|
} else { /* Our entry belongs at the end of the list. */
|
|
p_tmr->Remain = delta;
|
|
p_tmr->PrevPtr = p_tmr1;
|
|
p_tmr->NextPtr = (OS_TMR *)0;
|
|
p_tmr1->NextPtr = p_tmr;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* REMOVE A TIMER FROM THE TIMER LIST
|
|
*
|
|
* Description: This function is called to remove the timer from the timer list.
|
|
*
|
|
* Arguments : p_tmr Is a pointer to the timer to remove.
|
|
*
|
|
* time Is the system time when this timer was unlinked.
|
|
* -----
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OS_TmrUnlink (OS_TMR *p_tmr,
|
|
OS_TICK time)
|
|
{
|
|
OS_TMR *p_tmr1;
|
|
OS_TMR *p_tmr2;
|
|
OS_TICK elapsed;
|
|
|
|
|
|
p_tmr1 = p_tmr->PrevPtr;
|
|
p_tmr2 = p_tmr->NextPtr;
|
|
if (p_tmr1 == (OS_TMR *)0) {
|
|
if (p_tmr2 == (OS_TMR *)0) { /* Remove the ONLY entry in the list? */
|
|
OSTmrListPtr = (OS_TMR *)0;
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrListEntries = 0u;
|
|
#endif
|
|
p_tmr->Remain = 0u;
|
|
|
|
OSTmrTaskTickBase = time;
|
|
OS_TmrCondSignal();
|
|
} else {
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrListEntries--;
|
|
#endif
|
|
elapsed = time - OSTmrTaskTickBase;
|
|
p_tmr2->PrevPtr = (OS_TMR *)0;
|
|
p_tmr2->Remain += p_tmr->Remain; /* Add back the ticks to the delta */
|
|
OSTmrListPtr = p_tmr2;
|
|
|
|
while ((elapsed > 0u) &&
|
|
(p_tmr2 != (OS_TMR *)0)) {
|
|
|
|
if (elapsed > p_tmr2->Remain) {
|
|
elapsed -= p_tmr2->Remain;
|
|
p_tmr2->Remain = 0u;
|
|
} else {
|
|
p_tmr2->Remain -= elapsed;
|
|
elapsed = 0u;
|
|
}
|
|
|
|
|
|
p_tmr1 = p_tmr2;
|
|
p_tmr2 = p_tmr1->NextPtr;
|
|
}
|
|
|
|
if ((OSTmrListPtr->Remain != p_tmr->Remain) || /* Reload if new head has a different delay ... */
|
|
(OSTmrListPtr->Remain == 0u)) { /* ... or has already timed out. */
|
|
OSTmrTaskTickBase = time;
|
|
OS_TmrCondSignal();
|
|
}
|
|
|
|
p_tmr->NextPtr = (OS_TMR *)0;
|
|
p_tmr->Remain = 0u;
|
|
}
|
|
} else {
|
|
#if (OS_CFG_DBG_EN > 0u)
|
|
OSTmrListEntries--;
|
|
#endif
|
|
p_tmr1->NextPtr = p_tmr2;
|
|
if (p_tmr2 != (OS_TMR *)0) {
|
|
p_tmr2->PrevPtr = p_tmr1;
|
|
p_tmr2->Remain += p_tmr->Remain; /* Add back the ticks to the delta list */
|
|
}
|
|
p_tmr->PrevPtr = (OS_TMR *)0;
|
|
p_tmr->NextPtr = (OS_TMR *)0;
|
|
p_tmr->Remain = 0u;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* TIMER MANAGEMENT TASK
|
|
*
|
|
* Description: This task is created by OS_TmrInit().
|
|
*
|
|
* Arguments : none
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
*
|
|
* 2) The timer list is processed in two stages.
|
|
* a) Subtract the expired time from the delta list, which leaves expired timers at the head.
|
|
* b) Process each of the expired timers by invoking its callback (if any) and removing it.
|
|
* This method allows timer callbacks to Link/Unlink timers while maintaining the correct delta values.
|
|
*
|
|
* 3) Timer callbacks are allowed to make calls to the Timer APIs.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
void OS_TmrTask (void *p_arg)
|
|
{
|
|
OS_TMR_CALLBACK_PTR p_fnct;
|
|
OS_TMR *p_tmr;
|
|
OS_TICK timeout;
|
|
OS_TICK elapsed;
|
|
OS_TICK time;
|
|
#if (OS_CFG_TS_EN > 0u)
|
|
CPU_TS ts_start;
|
|
#endif
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)p_arg; /* Not using 'p_arg', prevent compiler warning */
|
|
|
|
OS_TmrLock();
|
|
|
|
for (;;) {
|
|
if (OSTmrListPtr == (OS_TMR *)0) {
|
|
timeout = 0u;
|
|
} else {
|
|
timeout = OSTmrListPtr->Remain;
|
|
}
|
|
|
|
OS_TmrCondWait(timeout); /* Suspend the timer task until it needs to process ... */
|
|
/* ... the timer list again. Also release the mutex ... */
|
|
/* ... so that application tasks can add/remove timers. */
|
|
|
|
if (OSTmrListPtr == (OS_TMR *)0) { /* Suppresses static analyzer warnings. */
|
|
continue;
|
|
}
|
|
|
|
#if (OS_CFG_TS_EN > 0u)
|
|
ts_start = OS_TS_GET();
|
|
#endif
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
#if (OS_CFG_DYN_TICK_EN > 0u)
|
|
time = OSTickCtr + OS_DynTickGet();
|
|
#else
|
|
time = OSTickCtr;
|
|
#endif
|
|
CPU_CRITICAL_EXIT();
|
|
elapsed = time - OSTmrTaskTickBase;
|
|
OSTmrTaskTickBase = time;
|
|
|
|
/* Update the delta values. */
|
|
p_tmr = OSTmrListPtr;
|
|
while ((elapsed != 0u) &&
|
|
(p_tmr != (OS_TMR *)0)) {
|
|
|
|
if (elapsed > p_tmr->Remain) {
|
|
elapsed -= p_tmr->Remain;
|
|
p_tmr->Remain = 0u;
|
|
} else {
|
|
p_tmr->Remain -= elapsed;
|
|
elapsed = 0u;
|
|
}
|
|
|
|
p_tmr = p_tmr->NextPtr;
|
|
}
|
|
|
|
/* Process timers that have expired. */
|
|
p_tmr = OSTmrListPtr;
|
|
|
|
while ((p_tmr != (OS_TMR *)0) &&
|
|
(p_tmr->Remain == 0u)) {
|
|
p_tmr->State = OS_TMR_STATE_TIMEOUT;
|
|
/* Execute callback function if available */
|
|
p_fnct = p_tmr->CallbackPtr;
|
|
if (p_fnct != (OS_TMR_CALLBACK_PTR)0u) {
|
|
(*p_fnct)(p_tmr, p_tmr->CallbackPtrArg);
|
|
}
|
|
|
|
if (p_tmr->State == OS_TMR_STATE_TIMEOUT) {
|
|
OS_TmrUnlink(p_tmr, OSTmrTaskTickBase);
|
|
|
|
if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {
|
|
p_tmr->State = OS_TMR_STATE_RUNNING;
|
|
p_tmr->Remain = p_tmr->Period;
|
|
OS_TmrLink(p_tmr, OSTmrTaskTickBase);
|
|
} else {
|
|
p_tmr->PrevPtr = (OS_TMR *)0;
|
|
p_tmr->NextPtr = (OS_TMR *)0;
|
|
p_tmr->Remain = 0u;
|
|
p_tmr->State = OS_TMR_STATE_COMPLETED;
|
|
}
|
|
}
|
|
|
|
p_tmr = OSTmrListPtr;
|
|
}
|
|
|
|
#if (OS_CFG_TS_EN > 0u)
|
|
OSTmrTaskTime = OS_TS_GET() - ts_start; /* Measure execution time of timer task */
|
|
if (OSTmrTaskTimeMax < OSTmrTaskTime) {
|
|
OSTmrTaskTimeMax = OSTmrTaskTime;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* TIMER MANAGEMENT LOCKING MECHANISM
|
|
*
|
|
* Description: These functions are used to handle timer critical sections. The method uses a mutex
|
|
* to protect access to the global timer list.
|
|
*
|
|
* Arguments : none
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) These functions are INTERNAL to uC/OS-III and your application MUST NOT call them.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
static void OS_TmrLock (void)
|
|
{
|
|
OS_ERR err;
|
|
|
|
|
|
OSMutexPend(&OSTmrMutex, 0u, OS_OPT_PEND_BLOCKING, (CPU_TS *)0, &err);
|
|
}
|
|
|
|
|
|
static void OS_TmrUnlock (void)
|
|
{
|
|
OS_ERR err;
|
|
|
|
|
|
OSMutexPost(&OSTmrMutex, OS_OPT_POST_NONE, &err);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* CREATE TIMER TASK CONDITION VARIABLE
|
|
*
|
|
* Description: Initializes a condition variable for INTERNAL use ONLY.
|
|
*
|
|
* Arguments : none
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
static void OS_TmrCondCreate (void)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
#if (OS_OBJ_TYPE_REQ > 0u)
|
|
OSTmrCond.Type = OS_OBJ_TYPE_COND; /* Mark the data structure as a condition variable. */
|
|
#endif
|
|
OSTmrCond.Mutex = &OSTmrMutex; /* Bind the timer mutex to the condition variable. */
|
|
OS_PendListInit(&OSTmrCond.PendList); /* Initialize the waiting list */
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* WAIT ON TIMER TASK CONDITION VARIABLE
|
|
*
|
|
* Description: Allows the timer task to release the global mutex and pend atomically. This ensures that
|
|
* timers are only added/removed after the timer task has processed the current list and pended
|
|
* for the next timeout. The timer task will always acquire the mutex before returning from this function.
|
|
*
|
|
* Arguments : timeout The number of ticks before the timer task will wake up.
|
|
* A value of zero signifies an indefinite pend.
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
static void OS_TmrCondWait (OS_TICK timeout)
|
|
{
|
|
OS_TCB *p_tcb;
|
|
OS_PEND_LIST *p_pend_list;
|
|
CPU_TS ts;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
#if (OS_CFG_TS_EN > 0u)
|
|
ts = OS_TS_GET(); /* Get timestamp */
|
|
OSTmrMutex.TS = ts;
|
|
#else
|
|
ts = 0u;
|
|
#endif
|
|
/* Release mutex to other tasks. */
|
|
OS_MutexGrpRemove(&OSTmrTaskTCB, &OSTmrMutex);
|
|
p_pend_list = &OSTmrMutex.PendList;
|
|
|
|
if (OSTmrTaskTCB.Prio != OSTmrTaskTCB.BasePrio) { /* Restore our original prio. */
|
|
OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(&OSTmrTaskTCB, OSTmrTaskTCB.Prio);
|
|
OSTmrTaskTCB.Prio = OSTmrTaskTCB.BasePrio;
|
|
OSPrioCur = OSTmrTaskTCB.BasePrio;
|
|
}
|
|
|
|
if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on mutex? */
|
|
OSTmrMutex.OwnerTCBPtr = (OS_TCB *)0; /* No */
|
|
OSTmrMutex.OwnerNestingCtr = 0u;
|
|
} else {
|
|
p_tcb = p_pend_list->HeadPtr; /* Yes, give mutex to new owner */
|
|
OSTmrMutex.OwnerTCBPtr = p_tcb;
|
|
OSTmrMutex.OwnerNestingCtr = 1u;
|
|
OS_MutexGrpAdd(p_tcb, &OSTmrMutex);
|
|
/* Post to mutex */
|
|
OS_Post((OS_PEND_OBJ *)((void *)&OSTmrMutex),
|
|
p_tcb,
|
|
(void *) 0,
|
|
0u,
|
|
ts);
|
|
}
|
|
|
|
OS_Pend((OS_PEND_OBJ *)((void *)&OSTmrCond), /* Pend on the condition variable. */
|
|
&OSTmrTaskTCB,
|
|
OS_TASK_PEND_ON_COND,
|
|
timeout);
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
OSSched();
|
|
|
|
CPU_CRITICAL_ENTER(); /* Either we timed out, or were signaled. */
|
|
|
|
if (OSTmrMutex.OwnerTCBPtr == (OS_TCB *)0) { /* Can we grab the mutex? */
|
|
OS_MutexGrpAdd(&OSTmrTaskTCB, &OSTmrMutex); /* Yes, no-one else pending. */
|
|
OSTmrMutex.OwnerTCBPtr = &OSTmrTaskTCB;
|
|
OSTmrMutex.OwnerNestingCtr = 1u;
|
|
CPU_CRITICAL_EXIT();
|
|
} else {
|
|
p_tcb = OSTmrMutex.OwnerTCBPtr; /* No, we need to wait for it. */
|
|
if (p_tcb->Prio > OSTmrTaskTCB.Prio) { /* See if mutex owner has a lower priority than TmrTask.*/
|
|
OS_TaskChangePrio(p_tcb, OSTmrTaskTCB.Prio);
|
|
}
|
|
|
|
OS_Pend((OS_PEND_OBJ *)((void *)&OSTmrMutex), /* Block TmrTask until it gets the Mutex. */
|
|
&OSTmrTaskTCB,
|
|
OS_TASK_PEND_ON_MUTEX,
|
|
0u);
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
OSSched();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************************
|
|
* SIGNAL THE TIMER TASK CONDITION VARIABLE
|
|
*
|
|
* Description: Used to signal the timer task when a timer is added/removed which requires the task to reload
|
|
* its timeout. We ensure that this function is always called with the timer mutex locked.
|
|
*
|
|
* Arguments : none.
|
|
*
|
|
* Returns : none
|
|
*
|
|
* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
|
|
************************************************************************************************************************
|
|
*/
|
|
|
|
static void OS_TmrCondSignal (void)
|
|
{
|
|
OS_PEND_LIST *p_pend_list;
|
|
CPU_TS ts;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
#if (OS_CFG_TS_EN > 0u)
|
|
ts = OS_TS_GET(); /* Get timestamp */
|
|
OSTmrMutex.TS = ts;
|
|
#else
|
|
ts = 0u;
|
|
#endif
|
|
|
|
p_pend_list = &OSTmrCond.PendList;
|
|
|
|
if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Timer task waiting on cond? */
|
|
CPU_CRITICAL_EXIT();
|
|
return; /* No, nothing to signal. */
|
|
} else {
|
|
/* Yes, signal the timer task. */
|
|
OS_Post((OS_PEND_OBJ *)((void *)&OSTmrCond),
|
|
&OSTmrTaskTCB,
|
|
(void *) 0,
|
|
0u,
|
|
ts);
|
|
}
|
|
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|