mirror of
https://github.com/QuantumLeaps/qpc.git
synced 2025-01-28 07:03:10 +08:00
1090 lines
43 KiB
C
1090 lines
43 KiB
C
/*
|
||
*********************************************************************************************************
|
||
* uC/OS-II
|
||
* The Real-Time Kernel
|
||
* TIMER MANAGEMENT
|
||
*
|
||
* (c) Copyright 1992-2013, Micrium, Weston, FL
|
||
* All Rights Reserved
|
||
*
|
||
*
|
||
* File : OS_TMR.C
|
||
* By : Jean J. Labrosse
|
||
* Version : V2.92.10
|
||
*
|
||
* LICENSING TERMS:
|
||
* ---------------
|
||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||
* If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license
|
||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||
* licensing fee.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#define MICRIUM_SOURCE
|
||
|
||
#ifndef OS_MASTER_FILE
|
||
#include <ucos_ii.h>
|
||
#endif
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* NOTES
|
||
*
|
||
* 1) Your application MUST define the following #define constants:
|
||
*
|
||
* OS_TASK_TMR_PRIO The priority of the Timer management task
|
||
* OS_TASK_TMR_STK_SIZE The size of the Timer management task's stack
|
||
*
|
||
* 2) You must call OSTmrSignal() to notify the Timer management task that it's time to update the timers.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* CONSTANTS
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#define OS_TMR_LINK_DLY 0u
|
||
#define OS_TMR_LINK_PERIODIC 1u
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* LOCAL PROTOTYPES
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static OS_TMR *OSTmr_Alloc (void);
|
||
static void OSTmr_Free (OS_TMR *ptmr);
|
||
static void OSTmr_InitTask (void);
|
||
static void OSTmr_Link (OS_TMR *ptmr, INT8U type);
|
||
static void OSTmr_Unlink (OS_TMR *ptmr);
|
||
static void OSTmr_Task (void *p_arg);
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* CREATE A TIMER
|
||
*
|
||
* Description: This function is called by your application code to create a timer.
|
||
*
|
||
* Arguments : 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_TMR_OPT_PERIODIC' as an option, when the timer
|
||
* expires, it will automatically restart with the same period.
|
||
*
|
||
* opt Specifies either:
|
||
* OS_TMR_OPT_ONE_SHOT The timer counts down only once
|
||
* OS_TMR_OPT_PERIODIC The timer counts down and then reloads itself
|
||
*
|
||
* 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 *ptmr, void *p_arg);
|
||
*
|
||
* callback_arg Is an argument (a pointer) that is passed to the callback function when it is called.
|
||
*
|
||
* pname Is a pointer to an ASCII string that is used to name the timer. Names are
|
||
* useful for debugging.
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE
|
||
* OS_ERR_TMR_INVALID_DLY you specified an invalid delay
|
||
* OS_ERR_TMR_INVALID_PERIOD you specified an invalid period
|
||
* OS_ERR_TMR_INVALID_OPT you specified an invalid option
|
||
* OS_ERR_TMR_ISR if the call was made from an ISR
|
||
* OS_ERR_TMR_NON_AVAIL if there are no free timers from the timer pool
|
||
*
|
||
* Returns : A pointer to an OS_TMR data structure.
|
||
* This is the 'handle' that your application will use to reference the timer created.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
OS_TMR *OSTmrCreate (INT32U dly,
|
||
INT32U period,
|
||
INT8U opt,
|
||
OS_TMR_CALLBACK callback,
|
||
void *callback_arg,
|
||
INT8U *pname,
|
||
INT8U *perr)
|
||
{
|
||
OS_TMR *ptmr;
|
||
|
||
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return ((OS_TMR *)0);
|
||
}
|
||
#endif
|
||
|
||
#ifdef OS_SAFETY_CRITICAL_IEC61508
|
||
if (OSSafetyCriticalStartFlag == OS_TRUE) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return ((OS_TMR *)0);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
switch (opt) { /* Validate arguments */
|
||
case OS_TMR_OPT_PERIODIC:
|
||
if (period == 0u) {
|
||
*perr = OS_ERR_TMR_INVALID_PERIOD;
|
||
return ((OS_TMR *)0);
|
||
}
|
||
break;
|
||
|
||
case OS_TMR_OPT_ONE_SHOT:
|
||
if (dly == 0u) {
|
||
*perr = OS_ERR_TMR_INVALID_DLY;
|
||
return ((OS_TMR *)0);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
*perr = OS_ERR_TMR_INVALID_OPT;
|
||
return ((OS_TMR *)0);
|
||
}
|
||
#endif
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_TMR_ISR;
|
||
return ((OS_TMR *)0);
|
||
}
|
||
OSSchedLock();
|
||
ptmr = OSTmr_Alloc(); /* Obtain a timer from the free pool */
|
||
if (ptmr == (OS_TMR *)0) {
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_NON_AVAIL;
|
||
return ((OS_TMR *)0);
|
||
}
|
||
ptmr->OSTmrState = OS_TMR_STATE_STOPPED; /* Indicate that timer is not running yet */
|
||
ptmr->OSTmrDly = dly;
|
||
ptmr->OSTmrPeriod = period;
|
||
ptmr->OSTmrOpt = opt;
|
||
ptmr->OSTmrCallback = callback;
|
||
ptmr->OSTmrCallbackArg = callback_arg;
|
||
#if OS_TMR_CFG_NAME_EN > 0u
|
||
if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */
|
||
ptmr->OSTmrName = (INT8U *)(void *)"?";
|
||
} else {
|
||
ptmr->OSTmrName = pname;
|
||
}
|
||
#endif
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (ptmr);
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* DELETE A TIMER
|
||
*
|
||
* Description: This function is called by your application code to delete a timer.
|
||
*
|
||
* Arguments : ptmr Is a pointer to the timer to stop and delete.
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE
|
||
* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
|
||
* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
|
||
* OS_ERR_TMR_ISR if the function was called from an ISR
|
||
* OS_ERR_TMR_INACTIVE if the timer was not created
|
||
* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
|
||
*
|
||
* Returns : OS_TRUE If the call was successful
|
||
* OS_FALSE If not
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
BOOLEAN OSTmrDel (OS_TMR *ptmr,
|
||
INT8U *perr)
|
||
{
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return (OS_FALSE);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
if (ptmr == (OS_TMR *)0) {
|
||
*perr = OS_ERR_TMR_INVALID;
|
||
return (OS_FALSE);
|
||
}
|
||
#endif
|
||
if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
|
||
*perr = OS_ERR_TMR_INVALID_TYPE;
|
||
return (OS_FALSE);
|
||
}
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_TMR_ISR;
|
||
return (OS_FALSE);
|
||
}
|
||
OSSchedLock();
|
||
switch (ptmr->OSTmrState) {
|
||
case OS_TMR_STATE_RUNNING:
|
||
OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
|
||
OSTmr_Free(ptmr); /* Return timer to free list of timers */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (OS_TRUE);
|
||
|
||
case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */
|
||
case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */
|
||
OSTmr_Free(ptmr); /* Return timer to free list of timers */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (OS_TRUE);
|
||
|
||
case OS_TMR_STATE_UNUSED: /* Already deleted */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INACTIVE;
|
||
return (OS_FALSE);
|
||
|
||
default:
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INVALID_STATE;
|
||
return (OS_FALSE);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* GET THE NAME OF A TIMER
|
||
*
|
||
* Description: This function is called to obtain the name of a timer.
|
||
*
|
||
* Arguments : ptmr Is a pointer to the timer to obtain the name for
|
||
*
|
||
* pdest Is a pointer to pointer to where the name of the timer will be placed.
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE The call was successful
|
||
* OS_ERR_TMR_INVALID_DEST 'pdest' is a NULL pointer
|
||
* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
|
||
* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
|
||
* OS_ERR_NAME_GET_ISR if the call was made from an ISR
|
||
* OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
|
||
* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
|
||
*
|
||
* Returns : The length of the string or 0 if the timer does not exist.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u && OS_TMR_CFG_NAME_EN > 0u
|
||
INT8U OSTmrNameGet (OS_TMR *ptmr,
|
||
INT8U **pdest,
|
||
INT8U *perr)
|
||
{
|
||
INT8U len;
|
||
|
||
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return (0u);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
if (pdest == (INT8U **)0) {
|
||
*perr = OS_ERR_TMR_INVALID_DEST;
|
||
return (0u);
|
||
}
|
||
if (ptmr == (OS_TMR *)0) {
|
||
*perr = OS_ERR_TMR_INVALID;
|
||
return (0u);
|
||
}
|
||
#endif
|
||
if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
|
||
*perr = OS_ERR_TMR_INVALID_TYPE;
|
||
return (0u);
|
||
}
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_NAME_GET_ISR;
|
||
return (0u);
|
||
}
|
||
OSSchedLock();
|
||
switch (ptmr->OSTmrState) {
|
||
case OS_TMR_STATE_RUNNING:
|
||
case OS_TMR_STATE_STOPPED:
|
||
case OS_TMR_STATE_COMPLETED:
|
||
*pdest = ptmr->OSTmrName;
|
||
len = OS_StrLen(*pdest);
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (len);
|
||
|
||
case OS_TMR_STATE_UNUSED: /* Timer is not allocated */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INACTIVE;
|
||
return (0u);
|
||
|
||
default:
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INVALID_STATE;
|
||
return (0u);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES
|
||
*
|
||
* Description: This function is called to get the number of ticks before a timer times out.
|
||
*
|
||
* Arguments : ptmr Is a pointer to the timer to obtain the remaining time from.
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE
|
||
* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
|
||
* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
|
||
* OS_ERR_TMR_ISR if the call was made from an ISR
|
||
* OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
|
||
* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
|
||
*
|
||
* Returns : The time remaining for the timer to expire. The time represents 'timer' increments.
|
||
* In other words, if OSTmr_Task() is signaled every 1/10 of a second then the returned
|
||
* value represents the number of 1/10 of a second remaining before the timer expires.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
INT32U OSTmrRemainGet (OS_TMR *ptmr,
|
||
INT8U *perr)
|
||
{
|
||
INT32U remain;
|
||
|
||
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return (0u);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
if (ptmr == (OS_TMR *)0) {
|
||
*perr = OS_ERR_TMR_INVALID;
|
||
return (0u);
|
||
}
|
||
#endif
|
||
if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
|
||
*perr = OS_ERR_TMR_INVALID_TYPE;
|
||
return (0u);
|
||
}
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_TMR_ISR;
|
||
return (0u);
|
||
}
|
||
OSSchedLock();
|
||
switch (ptmr->OSTmrState) {
|
||
case OS_TMR_STATE_RUNNING:
|
||
remain = ptmr->OSTmrMatch - OSTmrTime; /* Determine how much time is left to timeout */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (remain);
|
||
|
||
case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */
|
||
switch (ptmr->OSTmrOpt) {
|
||
case OS_TMR_OPT_PERIODIC:
|
||
if (ptmr->OSTmrDly == 0u) {
|
||
remain = ptmr->OSTmrPeriod;
|
||
} else {
|
||
remain = ptmr->OSTmrDly;
|
||
}
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
break;
|
||
|
||
case OS_TMR_OPT_ONE_SHOT:
|
||
default:
|
||
remain = ptmr->OSTmrDly;
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
break;
|
||
}
|
||
return (remain);
|
||
|
||
case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT that timed out can be in this state */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (0u);
|
||
|
||
case OS_TMR_STATE_UNUSED:
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INACTIVE;
|
||
return (0u);
|
||
|
||
default:
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INVALID_STATE;
|
||
return (0u);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* 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_STATE_RUNNING the timer is currently running
|
||
*
|
||
* Arguments : ptmr Is a pointer to the desired timer
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE
|
||
* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
|
||
* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
|
||
* OS_ERR_TMR_ISR if the call was made from an ISR
|
||
* OS_ERR_TMR_INACTIVE 'ptmr' points to a timer that is not active
|
||
* OS_ERR_TMR_INVALID_STATE if the timer is not in a valid state
|
||
*
|
||
* Returns : The current state of the timer (see description).
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
INT8U OSTmrStateGet (OS_TMR *ptmr,
|
||
INT8U *perr)
|
||
{
|
||
INT8U state;
|
||
|
||
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return (0u);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
if (ptmr == (OS_TMR *)0) {
|
||
*perr = OS_ERR_TMR_INVALID;
|
||
return (0u);
|
||
}
|
||
#endif
|
||
if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
|
||
*perr = OS_ERR_TMR_INVALID_TYPE;
|
||
return (0u);
|
||
}
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_TMR_ISR;
|
||
return (0u);
|
||
}
|
||
OSSchedLock();
|
||
state = ptmr->OSTmrState;
|
||
switch (state) {
|
||
case OS_TMR_STATE_UNUSED:
|
||
case OS_TMR_STATE_STOPPED:
|
||
case OS_TMR_STATE_COMPLETED:
|
||
case OS_TMR_STATE_RUNNING:
|
||
*perr = OS_ERR_NONE;
|
||
break;
|
||
|
||
default:
|
||
*perr = OS_ERR_TMR_INVALID_STATE;
|
||
break;
|
||
}
|
||
OSSchedUnlock();
|
||
return (state);
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* START A TIMER
|
||
*
|
||
* Description: This function is called by your application code to start a timer.
|
||
*
|
||
* Arguments : ptmr Is a pointer to an OS_TMR
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE
|
||
* OS_ERR_TMR_INVALID
|
||
* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
|
||
* OS_ERR_TMR_ISR if the call was made from an ISR
|
||
* OS_ERR_TMR_INACTIVE if the timer was not created
|
||
* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
|
||
*
|
||
* Returns : OS_TRUE if the timer was started
|
||
* OS_FALSE if an error was detected
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
BOOLEAN OSTmrStart (OS_TMR *ptmr,
|
||
INT8U *perr)
|
||
{
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return (OS_FALSE);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
if (ptmr == (OS_TMR *)0) {
|
||
*perr = OS_ERR_TMR_INVALID;
|
||
return (OS_FALSE);
|
||
}
|
||
#endif
|
||
if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
|
||
*perr = OS_ERR_TMR_INVALID_TYPE;
|
||
return (OS_FALSE);
|
||
}
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_TMR_ISR;
|
||
return (OS_FALSE);
|
||
}
|
||
OSSchedLock();
|
||
switch (ptmr->OSTmrState) {
|
||
case OS_TMR_STATE_RUNNING: /* Restart the timer */
|
||
OSTmr_Unlink(ptmr); /* ... Stop the timer */
|
||
OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (OS_TRUE);
|
||
|
||
case OS_TMR_STATE_STOPPED: /* Start the timer */
|
||
case OS_TMR_STATE_COMPLETED:
|
||
OSTmr_Link(ptmr, OS_TMR_LINK_DLY); /* ... Link timer to timer wheel */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_NONE;
|
||
return (OS_TRUE);
|
||
|
||
case OS_TMR_STATE_UNUSED: /* Timer not created */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INACTIVE;
|
||
return (OS_FALSE);
|
||
|
||
default:
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INVALID_STATE;
|
||
return (OS_FALSE);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* STOP A TIMER
|
||
*
|
||
* Description: This function is called by your application code to stop a timer.
|
||
*
|
||
* Arguments : ptmr Is a pointer to the timer to stop.
|
||
*
|
||
* opt Allows you to specify an option to this functions which can be:
|
||
*
|
||
* OS_TMR_OPT_NONE Do nothing special but stop the timer
|
||
* OS_TMR_OPT_CALLBACK Execute the callback function, pass it the
|
||
* callback argument specified when the timer
|
||
* was created.
|
||
* OS_TMR_OPT_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 ptmr->OSTmrCallbackArg.
|
||
*
|
||
* perr Is a pointer to an error code. '*perr' will contain one of the following:
|
||
* OS_ERR_NONE
|
||
* OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer
|
||
* OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR
|
||
* OS_ERR_TMR_ISR if the function was called from an ISR
|
||
* OS_ERR_TMR_INACTIVE if the timer was not created
|
||
* OS_ERR_TMR_INVALID_OPT if you specified an invalid option for 'opt'
|
||
* OS_ERR_TMR_STOPPED if the timer was already stopped
|
||
* OS_ERR_TMR_INVALID_STATE the timer is in an invalid state
|
||
* OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined
|
||
*
|
||
* Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE)
|
||
* OS_FALSE If not
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
BOOLEAN OSTmrStop (OS_TMR *ptmr,
|
||
INT8U opt,
|
||
void *callback_arg,
|
||
INT8U *perr)
|
||
{
|
||
OS_TMR_CALLBACK pfnct;
|
||
|
||
|
||
#ifdef OS_SAFETY_CRITICAL
|
||
if (perr == (INT8U *)0) {
|
||
OS_SAFETY_CRITICAL_EXCEPTION();
|
||
return (OS_FALSE);
|
||
}
|
||
#endif
|
||
|
||
#if OS_ARG_CHK_EN > 0u
|
||
if (ptmr == (OS_TMR *)0) {
|
||
*perr = OS_ERR_TMR_INVALID;
|
||
return (OS_FALSE);
|
||
}
|
||
#endif
|
||
if (ptmr->OSTmrType != OS_TMR_TYPE) { /* Validate timer structure */
|
||
*perr = OS_ERR_TMR_INVALID_TYPE;
|
||
return (OS_FALSE);
|
||
}
|
||
if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
|
||
*perr = OS_ERR_TMR_ISR;
|
||
return (OS_FALSE);
|
||
}
|
||
OSSchedLock();
|
||
switch (ptmr->OSTmrState) {
|
||
case OS_TMR_STATE_RUNNING:
|
||
OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
|
||
*perr = OS_ERR_NONE;
|
||
switch (opt) {
|
||
case OS_TMR_OPT_CALLBACK:
|
||
pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */
|
||
if (pfnct != (OS_TMR_CALLBACK)0) {
|
||
(*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg); /* Use callback arg when timer was created */
|
||
} else {
|
||
*perr = OS_ERR_TMR_NO_CALLBACK;
|
||
}
|
||
break;
|
||
|
||
case OS_TMR_OPT_CALLBACK_ARG:
|
||
pfnct = ptmr->OSTmrCallback; /* Execute callback function if available ... */
|
||
if (pfnct != (OS_TMR_CALLBACK)0) {
|
||
(*pfnct)((void *)ptmr, callback_arg); /* ... using the 'callback_arg' provided in call */
|
||
} else {
|
||
*perr = OS_ERR_TMR_NO_CALLBACK;
|
||
}
|
||
break;
|
||
|
||
case OS_TMR_OPT_NONE:
|
||
break;
|
||
|
||
default:
|
||
*perr = OS_ERR_TMR_INVALID_OPT;
|
||
break;
|
||
}
|
||
OSSchedUnlock();
|
||
return (OS_TRUE);
|
||
|
||
case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or ... */
|
||
case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_STOPPED;
|
||
return (OS_TRUE);
|
||
|
||
case OS_TMR_STATE_UNUSED: /* Timer was not created */
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INACTIVE;
|
||
return (OS_FALSE);
|
||
|
||
default:
|
||
OSSchedUnlock();
|
||
*perr = OS_ERR_TMR_INVALID_STATE;
|
||
return (OS_FALSE);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* SIGNAL THAT IT'S TIME TO UPDATE THE TIMERS
|
||
*
|
||
* Description: This function is typically called by the ISR that occurs at the timer tick rate and is
|
||
* used to signal to OSTmr_Task() that it's time to update the timers.
|
||
*
|
||
* Arguments : none
|
||
*
|
||
* Returns : OS_ERR_NONE The call was successful and the timer task was signaled.
|
||
* OS_ERR_SEM_OVF If OSTmrSignal() was called more often than OSTmr_Task() can handle
|
||
* the timers. This would indicate that your system is heavily loaded.
|
||
* OS_ERR_EVENT_TYPE Unlikely you would get this error because the semaphore used for
|
||
* signaling is created by uC/OS-II.
|
||
* OS_ERR_PEVENT_NULL Again, unlikely you would ever get this error because the semaphore
|
||
* used for signaling is created by uC/OS-II.
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
INT8U OSTmrSignal (void)
|
||
{
|
||
INT8U err;
|
||
|
||
|
||
err = OSSemPost(OSTmrSemSignal);
|
||
return (err);
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* ALLOCATE AND FREE A TIMER
|
||
*
|
||
* Description: This function is called to allocate a timer.
|
||
*
|
||
* Arguments : none
|
||
*
|
||
* Returns : a pointer to a timer if one is available
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static OS_TMR *OSTmr_Alloc (void)
|
||
{
|
||
OS_TMR *ptmr;
|
||
|
||
|
||
if (OSTmrFreeList == (OS_TMR *)0) {
|
||
return ((OS_TMR *)0);
|
||
}
|
||
ptmr = (OS_TMR *)OSTmrFreeList;
|
||
OSTmrFreeList = (OS_TMR *)ptmr->OSTmrNext;
|
||
ptmr->OSTmrNext = (OS_TCB *)0;
|
||
ptmr->OSTmrPrev = (OS_TCB *)0;
|
||
OSTmrUsed++;
|
||
OSTmrFree--;
|
||
return (ptmr);
|
||
}
|
||
#endif
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* RETURN A TIMER TO THE FREE LIST
|
||
*
|
||
* Description: This function is called to return a timer object to the free list of timers.
|
||
*
|
||
* Arguments : ptmr is a pointer to the timer to free
|
||
*
|
||
* Returns : none
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static void OSTmr_Free (OS_TMR *ptmr)
|
||
{
|
||
ptmr->OSTmrState = OS_TMR_STATE_UNUSED; /* Clear timer object fields */
|
||
ptmr->OSTmrOpt = OS_TMR_OPT_NONE;
|
||
ptmr->OSTmrPeriod = 0u;
|
||
ptmr->OSTmrMatch = 0u;
|
||
ptmr->OSTmrCallback = (OS_TMR_CALLBACK)0;
|
||
ptmr->OSTmrCallbackArg = (void *)0;
|
||
#if OS_TMR_CFG_NAME_EN > 0u
|
||
ptmr->OSTmrName = (INT8U *)(void *)"?";
|
||
#endif
|
||
|
||
ptmr->OSTmrPrev = (OS_TCB *)0; /* Chain timer to free list */
|
||
ptmr->OSTmrNext = OSTmrFreeList;
|
||
OSTmrFreeList = ptmr;
|
||
|
||
OSTmrUsed--; /* Update timer object statistics */
|
||
OSTmrFree++;
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* INITIALIZATION
|
||
* INITIALIZE THE FREE LIST OF TIMERS
|
||
*
|
||
* Description: This function is called by OSInit() to initialize the free list of OS_TMRs.
|
||
*
|
||
* Arguments : none
|
||
*
|
||
* Returns : none
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
void OSTmr_Init (void)
|
||
{
|
||
#if OS_EVENT_NAME_EN > 0u
|
||
INT8U err;
|
||
#endif
|
||
INT16U ix;
|
||
INT16U ix_next;
|
||
OS_TMR *ptmr1;
|
||
OS_TMR *ptmr2;
|
||
|
||
|
||
OS_MemClr((INT8U *)&OSTmrTbl[0], sizeof(OSTmrTbl)); /* Clear all the TMRs */
|
||
OS_MemClr((INT8U *)&OSTmrWheelTbl[0], sizeof(OSTmrWheelTbl)); /* Clear the timer wheel */
|
||
|
||
for (ix = 0u; ix < (OS_TMR_CFG_MAX - 1u); ix++) { /* Init. list of free TMRs */
|
||
ix_next = ix + 1u;
|
||
ptmr1 = &OSTmrTbl[ix];
|
||
ptmr2 = &OSTmrTbl[ix_next];
|
||
ptmr1->OSTmrType = OS_TMR_TYPE;
|
||
ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */
|
||
ptmr1->OSTmrNext = (void *)ptmr2; /* Link to next timer */
|
||
#if OS_TMR_CFG_NAME_EN > 0u
|
||
ptmr1->OSTmrName = (INT8U *)(void *)"?";
|
||
#endif
|
||
}
|
||
ptmr1 = &OSTmrTbl[ix];
|
||
ptmr1->OSTmrType = OS_TMR_TYPE;
|
||
ptmr1->OSTmrState = OS_TMR_STATE_UNUSED; /* Indicate that timer is inactive */
|
||
ptmr1->OSTmrNext = (void *)0; /* Last OS_TMR */
|
||
#if OS_TMR_CFG_NAME_EN > 0u
|
||
ptmr1->OSTmrName = (INT8U *)(void *)"?";
|
||
#endif
|
||
OSTmrTime = 0u;
|
||
OSTmrUsed = 0u;
|
||
OSTmrFree = OS_TMR_CFG_MAX;
|
||
OSTmrFreeList = &OSTmrTbl[0];
|
||
OSTmrSem = OSSemCreate(1u);
|
||
OSTmrSemSignal = OSSemCreate(0u);
|
||
|
||
#if OS_EVENT_NAME_EN > 0u /* Assign names to semaphores */
|
||
OSEventNameSet(OSTmrSem, (INT8U *)(void *)"uC/OS-II TmrLock", &err);
|
||
OSEventNameSet(OSTmrSemSignal, (INT8U *)(void *)"uC/OS-II TmrSignal", &err);
|
||
#endif
|
||
|
||
OSTmr_InitTask();
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* INITIALIZE THE TIMER MANAGEMENT TASK
|
||
*
|
||
* Description: This function is called by OSTmrInit() to create the timer management task.
|
||
* * Arguments : none
|
||
*
|
||
* Returns : none
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static void OSTmr_InitTask (void)
|
||
{
|
||
#if OS_TASK_NAME_EN > 0u
|
||
INT8U err;
|
||
#endif
|
||
|
||
|
||
#if OS_TASK_CREATE_EXT_EN > 0u
|
||
#if OS_STK_GROWTH == 1u
|
||
(void)OSTaskCreateExt(OSTmr_Task,
|
||
(void *)0, /* No arguments passed to OSTmrTask() */
|
||
&OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Top-Of-Stack */
|
||
OS_TASK_TMR_PRIO,
|
||
OS_TASK_TMR_ID,
|
||
&OSTmrTaskStk[0], /* Set Bottom-Of-Stack */
|
||
OS_TASK_TMR_STK_SIZE,
|
||
(void *)0, /* No TCB extension */
|
||
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */
|
||
#else
|
||
(void)OSTaskCreateExt(OSTmr_Task,
|
||
(void *)0, /* No arguments passed to OSTmrTask() */
|
||
&OSTmrTaskStk[0], /* Set Top-Of-Stack */
|
||
OS_TASK_TMR_PRIO,
|
||
OS_TASK_TMR_ID,
|
||
&OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u], /* Set Bottom-Of-Stack */
|
||
OS_TASK_TMR_STK_SIZE,
|
||
(void *)0, /* No TCB extension */
|
||
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */
|
||
#endif
|
||
#else
|
||
#if OS_STK_GROWTH == 1u
|
||
(void)OSTaskCreate(OSTmr_Task,
|
||
(void *)0,
|
||
&OSTmrTaskStk[OS_TASK_TMR_STK_SIZE - 1u],
|
||
OS_TASK_TMR_PRIO);
|
||
#else
|
||
(void)OSTaskCreate(OSTmr_Task,
|
||
(void *)0,
|
||
&OSTmrTaskStk[0],
|
||
OS_TASK_TMR_PRIO);
|
||
#endif
|
||
#endif
|
||
|
||
#if OS_TASK_NAME_EN > 0u
|
||
OSTaskNameSet(OS_TASK_TMR_PRIO, (INT8U *)(void *)"uC/OS-II Tmr", &err);
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* INSERT A TIMER INTO THE TIMER WHEEL
|
||
*
|
||
* Description: This function is called to insert the timer into the timer wheel. The timer is always
|
||
* inserted at the beginning of the list.
|
||
*
|
||
* Arguments : ptmr Is a pointer to the timer to insert.
|
||
*
|
||
* type Is either:
|
||
* OS_TMR_LINK_PERIODIC Means to re-insert the timer after a period expired
|
||
* OS_TMR_LINK_DLY Means to insert the timer the first time
|
||
*
|
||
* Returns : none
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static void OSTmr_Link (OS_TMR *ptmr,
|
||
INT8U type)
|
||
{
|
||
OS_TMR *ptmr1;
|
||
OS_TMR_WHEEL *pspoke;
|
||
INT16U spoke;
|
||
|
||
|
||
ptmr->OSTmrState = OS_TMR_STATE_RUNNING;
|
||
if (type == OS_TMR_LINK_PERIODIC) { /* Determine when timer will expire */
|
||
ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
|
||
} else {
|
||
if (ptmr->OSTmrDly == 0u) {
|
||
ptmr->OSTmrMatch = ptmr->OSTmrPeriod + OSTmrTime;
|
||
} else {
|
||
ptmr->OSTmrMatch = ptmr->OSTmrDly + OSTmrTime;
|
||
}
|
||
}
|
||
spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
|
||
pspoke = &OSTmrWheelTbl[spoke];
|
||
|
||
if (pspoke->OSTmrFirst == (OS_TMR *)0) { /* Link into timer wheel */
|
||
pspoke->OSTmrFirst = ptmr;
|
||
ptmr->OSTmrNext = (OS_TMR *)0;
|
||
pspoke->OSTmrEntries = 1u;
|
||
} else {
|
||
ptmr1 = pspoke->OSTmrFirst; /* Point to first timer in the spoke */
|
||
pspoke->OSTmrFirst = ptmr;
|
||
ptmr->OSTmrNext = (void *)ptmr1;
|
||
ptmr1->OSTmrPrev = (void *)ptmr;
|
||
pspoke->OSTmrEntries++;
|
||
}
|
||
ptmr->OSTmrPrev = (void *)0; /* Timer always inserted as first node in list */
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* REMOVE A TIMER FROM THE TIMER WHEEL
|
||
*
|
||
* Description: This function is called to remove the timer from the timer wheel.
|
||
*
|
||
* Arguments : ptmr Is a pointer to the timer to remove.
|
||
*
|
||
* Returns : none
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static void OSTmr_Unlink (OS_TMR *ptmr)
|
||
{
|
||
OS_TMR *ptmr1;
|
||
OS_TMR *ptmr2;
|
||
OS_TMR_WHEEL *pspoke;
|
||
INT16U spoke;
|
||
|
||
|
||
spoke = (INT16U)(ptmr->OSTmrMatch % OS_TMR_CFG_WHEEL_SIZE);
|
||
pspoke = &OSTmrWheelTbl[spoke];
|
||
|
||
if (pspoke->OSTmrFirst == ptmr) { /* See if timer to remove is at the beginning of list */
|
||
ptmr1 = (OS_TMR *)ptmr->OSTmrNext;
|
||
pspoke->OSTmrFirst = (OS_TMR *)ptmr1;
|
||
if (ptmr1 != (OS_TMR *)0) {
|
||
ptmr1->OSTmrPrev = (void *)0;
|
||
}
|
||
} else {
|
||
ptmr1 = (OS_TMR *)ptmr->OSTmrPrev; /* Remove timer from somewhere in the list */
|
||
ptmr2 = (OS_TMR *)ptmr->OSTmrNext;
|
||
ptmr1->OSTmrNext = ptmr2;
|
||
if (ptmr2 != (OS_TMR *)0) {
|
||
ptmr2->OSTmrPrev = (void *)ptmr1;
|
||
}
|
||
}
|
||
ptmr->OSTmrState = OS_TMR_STATE_STOPPED;
|
||
ptmr->OSTmrNext = (void *)0;
|
||
ptmr->OSTmrPrev = (void *)0;
|
||
pspoke->OSTmrEntries--;
|
||
}
|
||
#endif
|
||
|
||
/*$PAGE*/
|
||
/*
|
||
*********************************************************************************************************
|
||
* TIMER MANAGEMENT TASK
|
||
*
|
||
* Description: This task is created by OSTmrInit().
|
||
*
|
||
* Arguments : none
|
||
*
|
||
* Returns : none
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#if OS_TMR_EN > 0u
|
||
static void OSTmr_Task (void *p_arg)
|
||
{
|
||
INT8U err;
|
||
OS_TMR *ptmr;
|
||
OS_TMR *ptmr_next;
|
||
OS_TMR_CALLBACK pfnct;
|
||
OS_TMR_WHEEL *pspoke;
|
||
INT16U spoke;
|
||
|
||
|
||
p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
|
||
for (;;) {
|
||
OSSemPend(OSTmrSemSignal, 0u, &err); /* Wait for signal indicating time to update timers */
|
||
OSSchedLock();
|
||
OSTmrTime++; /* Increment the current time */
|
||
spoke = (INT16U)(OSTmrTime % OS_TMR_CFG_WHEEL_SIZE); /* Position on current timer wheel entry */
|
||
pspoke = &OSTmrWheelTbl[spoke];
|
||
ptmr = pspoke->OSTmrFirst;
|
||
while (ptmr != (OS_TMR *)0) {
|
||
ptmr_next = (OS_TMR *)ptmr->OSTmrNext; /* Point to next timer to update because current ... */
|
||
/* ... timer could get unlinked from the wheel. */
|
||
if (OSTmrTime == ptmr->OSTmrMatch) { /* Process each timer that expires */
|
||
OSTmr_Unlink(ptmr); /* Remove from current wheel spoke */
|
||
if (ptmr->OSTmrOpt == OS_TMR_OPT_PERIODIC) {
|
||
OSTmr_Link(ptmr, OS_TMR_LINK_PERIODIC); /* Recalculate new position of timer in wheel */
|
||
} else {
|
||
ptmr->OSTmrState = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */
|
||
}
|
||
pfnct = ptmr->OSTmrCallback; /* Execute callback function if available */
|
||
if (pfnct != (OS_TMR_CALLBACK)0) {
|
||
(*pfnct)((void *)ptmr, ptmr->OSTmrCallbackArg);
|
||
}
|
||
}
|
||
ptmr = ptmr_next;
|
||
}
|
||
OSSchedUnlock();
|
||
}
|
||
}
|
||
#endif
|