/* ************************************************************************************************************************ * uC/OS-II * The Real-Time Kernel * TIMER MANAGEMENT * * (c) Copyright 1992-2009, Micrium, Weston, FL * All Rights Reserved * * * File : OS_TMR.C * By : Jean J. Labrosse * Version : V2.91 * * 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 Micriµm 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. ************************************************************************************************************************ */ #include /* ************************************************************************************************************************ * 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(); } #endif #ifdef OS_SAFETY_CRITICAL_IEC61508 if (OSSafetyCriticalStartFlag == OS_TRUE) { OS_SAFETY_CRITICAL_EXCEPTION(); } #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 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(); } #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(); } #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(); } #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_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout * OS_TMR_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(); } #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(); } #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(); } #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