#include "wsf_queue.h"
|
#include "wsf_timer.h"
|
#include "mk_common.h"
|
#include "mk_misc.h"
|
// #include "mk_trace.h"
|
|
/**************************************************************************************************
|
Global Variables
|
**************************************************************************************************/
|
|
static wsfQueue_t wsfTimerTimerQueue; /*!< Timer queue */
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Remove a timer from queue. Note this function does not lock task scheduling.
|
*
|
* \param pTimer Pointer to timer.
|
*/
|
/*************************************************************************************************/
|
static void wsfTimerRemove(wsfTimer_t *pTimer)
|
{
|
wsfTimer_t *pElem;
|
wsfTimer_t *pPrev = NULL;
|
|
pElem = (wsfTimer_t *)wsfTimerTimerQueue.pHead;
|
|
/* find timer in queue */
|
while (pElem != NULL)
|
{
|
if (pElem == pTimer)
|
{
|
break;
|
}
|
pPrev = pElem;
|
pElem = pElem->pNext;
|
}
|
|
/* if timer found, remove from queue */
|
if (pElem != NULL)
|
{
|
WsfQueueRemove(&wsfTimerTimerQueue, pTimer, pPrev);
|
|
pTimer->isStarted = FALSE;
|
}
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Insert a timer into the queue sorted by the timer expiration.
|
*
|
* \param pTimer Pointer to timer.
|
* \param ticks Timer ticks until expiration.
|
* \param mode Timer work mode.
|
*/
|
/*************************************************************************************************/
|
static void wsfTimerInsert(wsfTimer_t *pTimer, uint32_t ticks, uint8_t mode)
|
{
|
wsfTimer_t *pElem;
|
wsfTimer_t *pPrev = NULL;
|
|
uint32_t lock = int_lock();
|
|
/* if timer is already running stop it first */
|
if (pTimer->isStarted)
|
{
|
wsfTimerRemove(pTimer);
|
}
|
|
pTimer->isStarted = TRUE;
|
pTimer->ticks = ticks;
|
pTimer->count = ticks;
|
pTimer->mode = mode;
|
|
pElem = (wsfTimer_t *)wsfTimerTimerQueue.pHead;
|
|
/* find insertion point in queue */
|
while (pElem != NULL)
|
{
|
if (pTimer->ticks < pElem->ticks)
|
{
|
break;
|
}
|
pPrev = pElem;
|
pElem = pElem->pNext;
|
}
|
|
WsfQueueInsert(&wsfTimerTimerQueue, pTimer, pPrev);
|
int_unlock(lock);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Return the number of ticks until the next timer expiration. Note that this
|
* function can return zero even if a timer is running, indicating a timer
|
* has expired but has not yet been serviced.
|
*
|
* \return The number of ticks until the next timer expiration.
|
*/
|
/*************************************************************************************************/
|
uint32_t WsfTimerNextExpiration(void)
|
{
|
uint32_t ticks;
|
uint32_t lock = int_lock();
|
|
if (wsfTimerTimerQueue.pHead == NULL)
|
{
|
ticks = UINT32_MAX;
|
}
|
else
|
{
|
ticks = ((wsfTimer_t *)wsfTimerTimerQueue.pHead)->ticks;
|
}
|
|
int_unlock(lock);
|
return ticks;
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Initialize the timer service. This function should only be called once
|
* upon system initialization.
|
*/
|
/*************************************************************************************************/
|
void WsfTimerInit(void)
|
{
|
WSF_QUEUE_INIT(&wsfTimerTimerQueue);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Start a timer in units of 32768Hz ticks.
|
*
|
* \param pTimer Pointer to timer.
|
* \param ticks 32768Hz ticks until expiration.
|
* \param mode Timer work mode.
|
*/
|
/*************************************************************************************************/
|
void WsfTimerStartTick(wsfTimer_t *pTimer, uint32_t ticks, uint8_t mode)
|
{
|
wsfTimerInsert(pTimer, ticks, mode);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Start a timer in units of milliseconds.
|
*
|
* \param pTimer Pointer to timer.
|
* \param ms Milliseconds until expiration.
|
* \param mode Timer work mode.
|
*/
|
/*************************************************************************************************/
|
void WsfTimerStartMs(wsfTimer_t *pTimer, uint32_t ms, uint8_t mode)
|
{
|
wsfTimerInsert(pTimer, __MS_TO_32K_CNT(ms), mode);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Stop a timer.
|
*
|
* \param pTimer Pointer to timer.
|
*/
|
/*************************************************************************************************/
|
void WsfTimerStop(wsfTimer_t *pTimer)
|
{
|
uint32_t lock = int_lock();
|
|
wsfTimerRemove(pTimer);
|
|
int_unlock(lock);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Update the timer service with the number of elapsed ticks.
|
*
|
* \param ticks Number of ticks since last update.
|
*/
|
/*************************************************************************************************/
|
void WsfTimerUpdate(uint32_t ticks)
|
{
|
wsfTimer_t *pElem;
|
|
uint32_t lock = int_lock();
|
|
pElem = (wsfTimer_t *)wsfTimerTimerQueue.pHead;
|
|
/* iterate over timer queue */
|
while (pElem != NULL)
|
{
|
/* decrement ticks while preventing underflow */
|
if (pElem->ticks > ticks)
|
{
|
pElem->ticks -= ticks;
|
}
|
else
|
{
|
pElem->ticks = 0;
|
}
|
|
if (pElem->ticks < POWER_DOWN_TIME_TICK_MIN)
|
{
|
pElem->ticks = 0;
|
/* timer expired; set task for this timer as ready */
|
WsfTaskSetReady(pElem->handlerId, WSF_TIMER_EVENT);
|
}
|
|
// LOG_INFO(TRACE_MODULE_OS, "WsfTimerUpdate %u %u %u %u\r\n", pElem->handlerId, pElem->msg.event, pElem->ticks, ticks);
|
|
pElem = pElem->pNext;
|
}
|
|
int_unlock(lock);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Service expired timers for the given task.
|
*
|
* \return Pointer to timer or NULL.
|
*/
|
/*************************************************************************************************/
|
wsfTimer_t *WsfTimerServiceExpired(void)
|
{
|
wsfTimer_t *pElem;
|
wsfTimer_t *pPrev = NULL;
|
|
uint32_t lock = int_lock();
|
|
/* find expired timers in queue */
|
pElem = (wsfTimer_t *)wsfTimerTimerQueue.pHead;
|
if ((pElem != NULL) && (pElem->ticks == 0))
|
{
|
if (pElem->mode == WSF_TIMER_PERIODIC)
|
{
|
wsfTimerInsert(pElem, pElem->count, WSF_TIMER_PERIODIC);
|
}
|
else
|
{
|
WsfQueueRemove(&wsfTimerTimerQueue, pElem, pPrev);
|
pElem->isStarted = FALSE;
|
}
|
|
int_unlock(lock);
|
return pElem;
|
}
|
|
int_unlock(lock);
|
return NULL;
|
}
|