www.pudn.com > uCOS-III.zip > os_tmr.c, change:2011-08-02,size:44988b


/* 
************************************************************************************************************************ 
*                                                      uC/OS-III 
*                                                 The Real-Time Kernel 
* 
*                                  (c) Copyright 2009-2011; Micrium, Inc.; Weston, FL 
*                           All rights reserved.  Protected by international copyright laws. 
* 
*                                                   TIMER MANAGEMENT 
* 
* File    : OS_TMR.C 
* By      : JJL 
* Version : V3.02.00 
* 
* LICENSING TERMS: 
* --------------- 
*           uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or  
*           for peaceful research.  If you plan or intend to use uC/OS-III in a commercial application/ 
*           product then, you need to contact Micrium to properly license uC/OS-III for its use in your  
*           application/product.   We provide ALL the source code for your convenience and to help you  
*           experience uC/OS-III.  The fact that the source is provided does NOT mean that you can use  
*           it commercially without paying a licensing fee. 
* 
*           Knowledge of the source code may NOT be used to develop a similar product. 
* 
*           Please help us continue to provide the embedded community with the finest software available. 
*           Your honesty is greatly appreciated. 
* 
*           You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036. 
************************************************************************************************************************ 
*/ 
 
#include <os.h> 
 
#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES 
const  CPU_CHAR  *os_tmr__c = "$Id: $"; 
#endif 
 
 
#if OS_CFG_TMR_EN > 0u 
/* 
************************************************************************************************************************ 
*                                                     CONSTANTS 
************************************************************************************************************************ 
*/ 
 
#define  OS_OPT_LINK_DLY       (OS_OPT)(0u) 
#define  OS_OPT_LINK_PERIODIC  (OS_OPT)(1u) 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                                   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 
*                                 OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the timer after you called 
*                                                                  OSSafetyCriticalStart(). 
*                                 OS_ERR_OBJ_CREATED             if the timer has already been created 
*                                 OS_ERR_OBJ_PTR_NULL            is 'p_tmr' is a NULL pointer 
*                                 OS_ERR_OBJ_TYPE                if the object type is invalid 
*                                 OS_ERR_OPT_INVALID             you specified an invalid option 
*                                 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 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) 
{ 
    CPU_SR_ALLOC(); 
 
 
 
#ifdef OS_SAFETY_CRITICAL 
    if (p_err == (OS_ERR *)0) { 
        OS_SAFETY_CRITICAL_EXCEPTION(); 
        return; 
    } 
#endif 
 
#ifdef OS_SAFETY_CRITICAL_IEC61508 
    if (OSSafetyCriticalStartFlag == DEF_TRUE) { 
        *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; 
        return; 
    } 
#endif 
 
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u 
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* 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 == (OS_TICK)0) { 
                 *p_err = OS_ERR_TMR_INVALID_PERIOD; 
                 return; 
             } 
             break; 
 
        case OS_OPT_TMR_ONE_SHOT: 
             if (dly == (OS_TICK)0) { 
                 *p_err = OS_ERR_TMR_INVALID_DLY; 
                 return; 
             } 
             break; 
 
        default: 
             *p_err = OS_ERR_OPT_INVALID; 
             return; 
    } 
#endif 
 
    CPU_CRITICAL_ENTER(); 
    p_tmr->State          = (OS_STATE           )OS_TMR_STATE_STOPPED;     /* Initialize the timer fields             */ 
    p_tmr->Type           = (OS_OBJ_TYPE        )OS_OBJ_TYPE_TMR; 
    p_tmr->NamePtr        = (CPU_CHAR          *)p_name; 
    p_tmr->Dly            = (OS_TICK            )dly; 
    p_tmr->Match          = (OS_TICK            )0; 
    p_tmr->Remain         = (OS_TICK            )0; 
    p_tmr->Period         = (OS_TICK            )period; 
    p_tmr->Opt            = (OS_OPT             )opt; 
    p_tmr->CallbackPtr    = (OS_TMR_CALLBACK_PTR)p_callback; 
    p_tmr->CallbackPtrArg = (void              *)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 
    OSTmrQty++;                                             /* Keep track of the number of timers created             */ 
 
    CPU_CRITICAL_EXIT(); 
    *p_err = OS_ERR_NONE; 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                                   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 
*                                 OS_ERR_OBJ_TYPE             'p_tmr' is not pointing to a timer 
*                                 OS_ERR_TMR_INVALID          'p_tmr' is a NULL pointer 
*                                 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    : DEF_TRUE   if the timer was deleted 
*              DEF_FALSE  if not or upon an error 
************************************************************************************************************************ 
*/ 
 
#if OS_CFG_TMR_DEL_EN > 0u 
CPU_BOOLEAN  OSTmrDel (OS_TMR  *p_tmr, 
                       OS_ERR  *p_err) 
{ 
    OS_ERR  err; 
 
 
 
#ifdef OS_SAFETY_CRITICAL 
    if (p_err == (OS_ERR *)0) { 
        OS_SAFETY_CRITICAL_EXCEPTION(); 
        return (DEF_FALSE); 
    } 
#endif 
 
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u 
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if trying to call from an ISR                      */ 
        *p_err  = OS_ERR_TMR_ISR; 
        return (DEF_FALSE); 
    } 
#endif 
 
#if OS_CFG_ARG_CHK_EN > 0u 
    if (p_tmr == (OS_TMR *)0) { 
        *p_err = OS_ERR_TMR_INVALID; 
        return (DEF_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 (DEF_FALSE); 
    } 
#endif 
 
    OSSchedLock(&err); 
#if OS_CFG_DBG_EN > 0u 
    OS_TmrDbgListRemove(p_tmr); 
#endif 
    OSTmrQty--;                                             /* One less timer                                         */ 
 
    switch (p_tmr->State) { 
        case OS_TMR_STATE_RUNNING: 
             OS_TmrUnlink(p_tmr);                           /* Remove from current wheel spoke                        */ 
             OS_TmrClr(p_tmr); 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_NONE; 
             return (DEF_TRUE); 
 
        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                                     */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_NONE; 
             return (DEF_TRUE); 
 
        case OS_TMR_STATE_UNUSED:                           /* Already deleted                                        */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INACTIVE; 
             return (DEF_FALSE); 
 
        default: 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INVALID_STATE; 
             return (DEF_FALSE); 
    } 
} 
#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  : 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 
*                           OS_ERR_OBJ_TYPE           'p_tmr' is not pointing to a timer 
*                           OS_ERR_TMR_INVALID        'p_tmr' is a NULL pointer 
*                           OS_ERR_TMR_ISR            if the call was made from an ISR 
*                           OS_ERR_TMR_INACTIVE       'p_tmr' 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 
*              OS_TmrTask() 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. 
************************************************************************************************************************ 
*/ 
 
OS_TICK  OSTmrRemainGet (OS_TMR  *p_tmr, 
                         OS_ERR  *p_err) 
{ 
    OS_TICK  remain; 
    OS_ERR   err; 
 
 
 
#ifdef OS_SAFETY_CRITICAL 
    if (p_err == (OS_ERR *)0) { 
        OS_SAFETY_CRITICAL_EXCEPTION(); 
        return ((OS_TICK)0); 
    } 
#endif 
 
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u 
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if trying to call from an ISR                      */ 
        *p_err = OS_ERR_TMR_ISR; 
        return ((OS_TICK)0); 
    } 
#endif 
 
#if OS_CFG_ARG_CHK_EN > 0u 
    if (p_tmr == (OS_TMR *)0) { 
        *p_err = OS_ERR_TMR_INVALID; 
        return ((OS_TICK)0); 
    } 
#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_TICK)0); 
    } 
#endif 
 
    OSSchedLock(&err); 
    switch (p_tmr->State) { 
        case OS_TMR_STATE_RUNNING: 
             remain        = p_tmr->Match                   /* Determine how much time is left to timeout             */ 
                           - OSTmrTickCtr; 
             p_tmr->Remain = remain; 
             OSSchedUnlock(&err); 
             *p_err        = OS_ERR_NONE; 
             return (remain); 
 
        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; 
                 } else { 
                     remain = p_tmr->Dly; 
                 } 
             } else { 
                 remain = p_tmr->Dly; 
             } 
             p_tmr->Remain = remain; 
             OSSchedUnlock(&err); 
             *p_err        = OS_ERR_NONE; 
             return (remain); 
 
        case OS_TMR_STATE_COMPLETED:                        /* Only ONE-SHOT that timed out can be in this state      */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_NONE; 
             return ((OS_TICK)0); 
 
        case OS_TMR_STATE_UNUSED: 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INACTIVE; 
             return ((OS_TICK)0); 
 
        default: 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INVALID_STATE; 
             return ((OS_TICK)0); 
    } 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                                   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 
*                           OS_ERR_OBJ_TYPE            if 'p_tmr' is not pointing to a timer 
*                           OS_ERR_TMR_INVALID 
*                           OS_ERR_TMR_INACTIVE        if the timer was not created 
*                           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    : DEF_TRUE      is the timer was started 
*              DEF_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 wheel 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) 
{ 
    OS_ERR  err; 
 
 
 
#ifdef OS_SAFETY_CRITICAL 
    if (p_err == (OS_ERR *)0) { 
        OS_SAFETY_CRITICAL_EXCEPTION(); 
        return (DEF_FALSE); 
    } 
#endif 
 
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u 
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if trying to call from an ISR                      */ 
        *p_err = OS_ERR_TMR_ISR; 
        return (DEF_FALSE); 
    } 
#endif 
 
#if OS_CFG_ARG_CHK_EN > 0u 
    if (p_tmr == (OS_TMR *)0) { 
        *p_err = OS_ERR_TMR_INVALID; 
        return (DEF_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 (DEF_FALSE); 
    } 
#endif 
 
    OSSchedLock(&err); 
    switch (p_tmr->State) { 
        case OS_TMR_STATE_RUNNING:                          /* Restart the timer                                      */ 
             OS_TmrUnlink(p_tmr);                           /* ... Stop the timer                                     */ 
             OS_TmrLink(p_tmr, OS_OPT_LINK_DLY);            /* ... Link timer to timer wheel (see Note #1).           */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_NONE; 
             return (DEF_TRUE); 
 
        case OS_TMR_STATE_STOPPED:                          /* Start the timer                                        */ 
        case OS_TMR_STATE_COMPLETED: 
             OS_TmrLink(p_tmr, OS_OPT_LINK_DLY);            /* ... Link timer to timer wheel (see Note #1).           */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_NONE; 
             return (DEF_TRUE); 
 
        case OS_TMR_STATE_UNUSED:                           /* Timer not created                                      */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INACTIVE; 
             return (DEF_FALSE); 
 
        default: 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INVALID_STATE; 
             return (DEF_FALSE); 
    } 
} 
 
/*$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_COMPLETED        the timer is in ONE-SHOT mode and has completed it's timeout 
*                  OS_TMR_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 
*                           OS_ERR_OBJ_TYPE            if 'p_tmr' is not pointing to a timer 
*                           OS_ERR_TMR_INVALID        '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). 
************************************************************************************************************************ 
*/ 
 
OS_STATE  OSTmrStateGet (OS_TMR  *p_tmr, 
                         OS_ERR  *p_err) 
{ 
    OS_STATE  state; 
    CPU_SR_ALLOC(); 
 
 
 
#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 > (OS_NESTING_CTR)0) {              /* See if trying to call from an ISR                      */ 
        *p_err = OS_ERR_TMR_ISR; 
        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 
 
    CPU_CRITICAL_ENTER(); 
    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: 
             *p_err = OS_ERR_NONE; 
             break; 
 
        default: 
             *p_err = OS_ERR_TMR_INVALID_STATE; 
             break; 
    } 
    CPU_CRITICAL_EXIT(); 
    return (state); 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                                    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 
*                               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_TMR_INACTIVE        if the timer was not created 
*                               OS_ERR_TMR_INVALID         '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    : DEF_TRUE       If we stopped the timer (if the timer is already stopped, we also return DEF_TRUE) 
*              DEF_FALSE      If not 
************************************************************************************************************************ 
*/ 
 
CPU_BOOLEAN  OSTmrStop (OS_TMR   *p_tmr, 
                        OS_OPT    opt, 
                        void     *p_callback_arg, 
                        OS_ERR   *p_err) 
{ 
    OS_TMR_CALLBACK_PTR  p_fnct; 
    OS_ERR               err; 
 
 
 
#ifdef OS_SAFETY_CRITICAL 
    if (p_err == (OS_ERR *)0) { 
        OS_SAFETY_CRITICAL_EXCEPTION(); 
        return (DEF_FALSE); 
    } 
#endif 
 
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u 
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {                        /* See if trying to call from an ISR            */ 
        *p_err = OS_ERR_TMR_ISR; 
        return (DEF_FALSE); 
    } 
#endif 
 
#if OS_CFG_ARG_CHK_EN > 0u 
    if (p_tmr == (OS_TMR *)0) { 
        *p_err = OS_ERR_TMR_INVALID; 
        return (DEF_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 (DEF_FALSE); 
    } 
#endif 
 
    OSSchedLock(&err); 
    switch (p_tmr->State) { 
        case OS_TMR_STATE_RUNNING: 
             OS_TmrUnlink(p_tmr);                                     /* Remove from current wheel spoke              */ 
             *p_err = OS_ERR_NONE; 
             switch (opt) { 
                 case OS_OPT_TMR_CALLBACK: 
                      p_fnct = p_tmr->CallbackPtr;                         /* Execute callback function ...           */ 
                      if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {              /* ... if available                        */ 
                          (*p_fnct)((void *)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: 
                      p_fnct = p_tmr->CallbackPtr;                    /* Execute callback function if available ...   */ 
                      if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { 
                          (*p_fnct)((void *)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: 
                      break; 
 
                 default: 
                     OSSchedUnlock(&err); 
                     *p_err = OS_ERR_OPT_INVALID; 
                     return (DEF_FALSE); 
             } 
             OSSchedUnlock(&err); 
             return (DEF_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(&err); 
             *p_err = OS_ERR_TMR_STOPPED; 
             return (DEF_TRUE); 
 
        case OS_TMR_STATE_UNUSED:                                     /* Timer was not created                        */ 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INACTIVE; 
             return (DEF_FALSE); 
 
        default: 
             OSSchedUnlock(&err); 
             *p_err = OS_ERR_TMR_INVALID_STATE; 
             return (DEF_FALSE); 
    } 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                                 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                                     */ 
    p_tmr->Type           = OS_OBJ_TYPE_NONE; 
    p_tmr->NamePtr        = (CPU_CHAR          *)((void *)"?TMR"); 
    p_tmr->Dly            = (OS_TICK            )0; 
    p_tmr->Match          = (OS_TICK            )0; 
    p_tmr->Remain         = (OS_TICK            )0; 
    p_tmr->Period         = (OS_TICK            )0; 
    p_tmr->Opt            = (OS_OPT             )0; 
    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; 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                         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 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                             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) 
{ 
    OS_TMR_SPOKE_IX   i; 
    OS_TMR_SPOKE     *p_spoke; 
 
 
 
#ifdef OS_SAFETY_CRITICAL 
    if (p_err == (OS_ERR *)0) { 
        OS_SAFETY_CRITICAL_EXCEPTION(); 
        return; 
    } 
#endif 
 
#if OS_CFG_DBG_EN > 0u 
    OSTmrDbgListPtr = (OS_TMR *)0; 
#endif 
 
    if (OSCfg_TmrTaskRate_Hz > (OS_RATE_HZ)0) { 
        OSTmrUpdateCnt = OSCfg_TickRate_Hz / OSCfg_TmrTaskRate_Hz; 
    } else { 
        OSTmrUpdateCnt = OSCfg_TickRate_Hz / (OS_RATE_HZ)10; 
    } 
    OSTmrUpdateCtr   = OSTmrUpdateCnt; 
 
    OSTmrTickCtr     = (OS_TICK)0; 
 
    OSTmrTaskTimeMax = (CPU_TS)0; 
 
    for (i = 0u; i < OSCfg_TmrWheelSize; i++) { 
        p_spoke                = &OSCfg_TmrWheel[i]; 
        p_spoke->NbrEntries    = (OS_OBJ_QTY)0; 
        p_spoke->NbrEntriesMax = (OS_OBJ_QTY)0; 
        p_spoke->FirstPtr      = (OS_TMR   *)0; 
    } 
 
                                                            /* ---------------- 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_INVALID; 
        return; 
    } 
 
    if (OSCfg_TmrTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) { 
        *p_err = OS_ERR_PRIO_INVALID; 
        return; 
    } 
 
    OSTaskCreate((OS_TCB     *)&OSTmrTaskTCB, 
                 (CPU_CHAR   *)((void *)"uC/OS-III Timer Task"), 
                 (OS_TASK_PTR )OS_TmrTask, 
                 (void       *)0, 
                 (OS_PRIO     )OSCfg_TmrTaskPrio, 
                 (CPU_STK    *)OSCfg_TmrTaskStkBasePtr, 
                 (CPU_STK_SIZE)OSCfg_TmrTaskStkLimit, 
                 (CPU_STK_SIZE)OSCfg_TmrTaskStkSize, 
                 (OS_MSG_QTY  )0, 
                 (OS_TICK     )0, 
                 (void       *)0, 
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 
                 (OS_ERR     *)p_err); 
} 
 
/*$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  : p_tmr          Is a pointer to the timer to insert. 
*              ----- 
* 
*              opt            Is either: 
* 
*                               OS_OPT_LINK_PERIODIC    Means to re-insert the timer after a period expired 
*                               OS_OPT_LINK_DLY         Means to insert    the timer the first time 
* 
* 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_OPT       opt) 
{ 
    OS_TMR_SPOKE     *p_spoke; 
    OS_TMR           *p_tmr0; 
    OS_TMR           *p_tmr1; 
    OS_TMR_SPOKE_IX   spoke; 
 
 
 
    p_tmr->State = OS_TMR_STATE_RUNNING; 
    if (opt == OS_OPT_LINK_PERIODIC) {                      /* Determine when timer will expire                      */ 
        p_tmr->Match = p_tmr->Period + OSTmrTickCtr; 
    } else { 
        if (p_tmr->Dly == (OS_TICK)0) { 
            p_tmr->Match = p_tmr->Period + OSTmrTickCtr; 
        } else { 
            p_tmr->Match = p_tmr->Dly    + OSTmrTickCtr; 
        } 
    } 
    spoke  = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize); 
    p_spoke = &OSCfg_TmrWheel[spoke]; 
 
    if (p_spoke->FirstPtr ==  (OS_TMR *)0) {                /* Link into timer wheel                                  */ 
        p_tmr->NextPtr      = (OS_TMR *)0; 
        p_tmr->PrevPtr      = (OS_TMR *)0; 
        p_spoke->FirstPtr   = p_tmr; 
        p_spoke->NbrEntries = 1u; 
    } else { 
        p_tmr->Remain  = p_tmr->Match                       /* Compute remaining time for timer                       */ 
                       - OSTmrTickCtr; 
        p_tmr1         = p_spoke->FirstPtr;                 /* Point to current first timer in the list               */ 
        while (p_tmr1 != (OS_TMR *)0) { 
            p_tmr1->Remain = p_tmr1->Match                  /* Compute time remaining of current timer in list        */ 
                           - OSTmrTickCtr; 
            if (p_tmr->Remain > p_tmr1->Remain) {           /* Do we need to insert AFTER current timer in list?      */ 
                if (p_tmr1->NextPtr  != (OS_TMR *)0) {      /* Yes, are we pointing at the last timer in the list?    */ 
                    p_tmr1            = p_tmr1->NextPtr;    /* No,  Point to next timer in the list                   */ 
                } else { 
                    p_tmr->NextPtr    = (OS_TMR *)0; 
                    p_tmr->PrevPtr    =  p_tmr1; 
                    p_tmr1->NextPtr   =  p_tmr;             /* Yes, timer to insert is now new last entry in the list */ 
                    p_tmr1            = (OS_TMR *)0;        /* Break loop                                             */ 
                } 
            } else {                                        /* Insert before the current timer                        */ 
                if (p_tmr1->PrevPtr == (OS_TMR *)0) {       /* Are we inserting before the first timer?               */ 
                    p_tmr->PrevPtr    = (OS_TMR *)0; 
                    p_tmr->NextPtr    = p_tmr1; 
                    p_tmr1->PrevPtr   = p_tmr; 
                    p_spoke->FirstPtr = p_tmr; 
                } else {                                    /* Insert in between 2 timers already in the list         */ 
                    p_tmr0            = p_tmr1->PrevPtr; 
                    p_tmr->PrevPtr    = p_tmr0; 
                    p_tmr->NextPtr    = p_tmr1; 
                    p_tmr0->NextPtr   = p_tmr; 
                    p_tmr1->PrevPtr   = p_tmr; 
                } 
                p_tmr1 = (OS_TMR *)0;                       /* Break loop                                             */ 
            } 
        } 
        p_spoke->NbrEntries++; 
    } 
    if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) {     /* Keep track of maximum number of entries in each spoke  */ 
        p_spoke->NbrEntriesMax = p_spoke->NbrEntries; 
    } 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                              RESET TIMER LIST PEAK DETECTOR 
* 
* Description: This function is used to reset the peak detector for the number of entries in each spoke. 
* 
* Arguments  : void 
* 
* Returns    : none 
* 
* Note(s)    : This function is INTERNAL to uC/OS-III and your application should not call it. 
************************************************************************************************************************ 
*/ 
 
void  OS_TmrResetPeak (void) 
{ 
    OS_TMR_SPOKE     *p_spoke; 
    OS_TMR_SPOKE_IX   i; 
 
 
 
    for (i = 0u; i < OSCfg_TmrWheelSize; i++) { 
        p_spoke                = (OS_TMR_SPOKE *)&OSCfg_TmrWheel[i]; 
        p_spoke->NbrEntriesMax = (OS_OBJ_QTY    )0u; 
    } 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                         REMOVE A TIMER FROM THE TIMER WHEEL 
* 
* Description: This function is called to remove the timer from the timer wheel. 
* 
* Arguments  : p_tmr          Is a pointer to the timer to remove. 
*              ----- 
* 
* 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_TMR_SPOKE    *p_spoke; 
    OS_TMR          *p_tmr1; 
    OS_TMR          *p_tmr2; 
    OS_TMR_SPOKE_IX  spoke; 
 
 
 
    spoke   = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize); 
    p_spoke = &OSCfg_TmrWheel[spoke]; 
 
    if (p_spoke->FirstPtr == p_tmr) {                       /* See if timer to remove is at the beginning of list     */ 
        p_tmr1            = (OS_TMR *)p_tmr->NextPtr; 
        p_spoke->FirstPtr = (OS_TMR *)p_tmr1; 
        if (p_tmr1 != (OS_TMR *)0) { 
            p_tmr1->PrevPtr = (OS_TMR *)0; 
        } 
    } else { 
        p_tmr1          = (OS_TMR *)p_tmr->PrevPtr;         /* Remove timer from somewhere in the list                */ 
        p_tmr2          = (OS_TMR *)p_tmr->NextPtr; 
        p_tmr1->NextPtr = p_tmr2; 
        if (p_tmr2 != (OS_TMR *)0) { 
            p_tmr2->PrevPtr = (OS_TMR *)p_tmr1; 
        } 
    } 
    p_tmr->State   = OS_TMR_STATE_STOPPED; 
    p_tmr->NextPtr = (OS_TMR *)0; 
    p_tmr->PrevPtr = (OS_TMR *)0; 
    p_spoke->NbrEntries--; 
} 
 
/*$PAGE*/ 
/* 
************************************************************************************************************************ 
*                                                 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. 
************************************************************************************************************************ 
*/ 
 
void  OS_TmrTask (void *p_arg) 
{ 
    CPU_BOOLEAN          done; 
    OS_ERR               err; 
    OS_TMR_CALLBACK_PTR  p_fnct; 
    OS_TMR_SPOKE        *p_spoke; 
    OS_TMR              *p_tmr; 
    OS_TMR              *p_tmr_next; 
    OS_TMR_SPOKE_IX      spoke; 
    CPU_TS               ts; 
    CPU_TS               ts_start; 
    CPU_TS               ts_end; 
 
 
 
    p_arg = p_arg;                                               /* Not using 'p_arg', prevent compiler warning       */ 
    while (DEF_ON) { 
        (void)OSTaskSemPend((OS_TICK )0,                         /* Wait for signal indicating time to update tmrs    */ 
                            (OS_OPT  )OS_OPT_PEND_BLOCKING, 
                            (CPU_TS *)&ts, 
                            (OS_ERR *)&err); 
 
        OSSchedLock(&err); 
        ts_start = OS_TS_GET(); 
        OSTmrTickCtr++;                                          /* Increment the current time                        */ 
        spoke    = (OS_TMR_SPOKE_IX)(OSTmrTickCtr % OSCfg_TmrWheelSize); 
        p_spoke  = &OSCfg_TmrWheel[spoke]; 
        p_tmr    = p_spoke->FirstPtr; 
        done     = DEF_FALSE; 
        while (done == DEF_FALSE) { 
            if (p_tmr != (OS_TMR *)0) { 
                p_tmr_next = (OS_TMR *)p_tmr->NextPtr;           /* Point to next tmr to update because current ...   */ 
                                                                 /* ... timer could get unlinked from the wheel.      */ 
                if (OSTmrTickCtr == p_tmr->Match) {              /* Process each timer that expires                   */ 
                    OS_TmrUnlink(p_tmr);                         /* Remove from current wheel spoke                   */ 
                    if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) { 
                        OS_TmrLink(p_tmr, 
                                   OS_OPT_LINK_PERIODIC);        /* Recalculate new position of timer in wheel        */ 
                    } else { 
                        p_tmr->State = OS_TMR_STATE_COMPLETED;   /* Indicate that the timer has completed             */ 
                    } 
                    p_fnct = p_tmr->CallbackPtr;                 /* Execute callback function if available            */ 
                    if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { 
                        (*p_fnct)((void *)p_tmr, 
                                  p_tmr->CallbackPtrArg); 
                    } 
                    p_tmr = p_tmr_next;                          /* See if next timer matches                         */ 
                } else { 
                    done  = DEF_TRUE; 
                } 
            } else { 
                done = DEF_TRUE; 
            } 
        } 
        ts_end = OS_TS_GET() - ts_start;                         /* Measure execution time of timer task              */ 
        OSSchedUnlock(&err); 
        if (ts_end > OSTmrTaskTimeMax) { 
            OSTmrTaskTimeMax = ts_end; 
        } 
    } 
} 
 
#endif