chen
2024-11-08 cc432b761c884a0bd8e9d83db0a4e26109fc08b1
keil/include/components/wsf/sources/port/baremetal/wsf_timer.c
对比新文件
@@ -0,0 +1,414 @@
/*************************************************************************************************/
/*!
 *  \file   wsf_timer.c
 *
 *  \brief  Timer service.
 *
 *  Copyright (c) 2009-2019 Arm Ltd. All Rights Reserved.
 *
 *  Copyright (c) 2019-2020 Packetcraft, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/*************************************************************************************************/
#include "wsf_types.h"
#include "wsf_queue.h"
#include "wsf_timer.h"
#include "wsf_assert.h"
#include "wsf_cs.h"
#include "wsf_trace.h"
#include "pal_sys.h"
/**************************************************************************************************
  Macros
**************************************************************************************************/
#if (WSF_MS_PER_TICK == 10)
/*! \brief  WSF timer ticks per second. */
#define WSF_TIMER_TICKS_PER_SEC (1000 / WSF_MS_PER_TICK)
/* convert seconds to timer ticks */
#define WSF_TIMER_SEC_TO_TICKS(sec) (WSF_TIMER_TICKS_PER_SEC * (sec))
/* convert milliseconds to timer ticks */
#define WSF_TIMER_MS_TO_TICKS(ms) ((ms) / WSF_MS_PER_TICK)
#else
#error "WSF_TIMER_MS_TO_TICKS and WSF_TIMER_SEC_TO_TICKS not defined for WSF_MS_PER_TICK"
#endif
/*! \brief  Minimum RTC ticks required to go into sleep. */
#define WSF_TIMER_MIN_MS_FOR_POWERDOWN (2)
#define WSF_TIMER_MAX_MS_FOR_POWERDOWN (10000)
/**************************************************************************************************
  Global Variables
**************************************************************************************************/
static wsfQueue_t wsfTimerTimerQueue; /*!< Timer queue */
/*! \brief  Last SysTick value read. */
static uint32_t wsfTimerSysTickcLastTick = 0;
/*************************************************************************************************/
/*!
 *  \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, wsfTimerTicks_t ticks, uint8_t mode)
{
    wsfTimer_t *pElem;
    wsfTimer_t *pPrev = NULL;
    /* task schedule lock */
    uint32_t lock = WsfTaskLock();
    /* 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;
    }
    /* insert timer into queue */
    WsfQueueInsert(&wsfTimerTimerQueue, pTimer, pPrev);
    /* task schedule unlock */
    WsfTaskUnlock(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.
 *
 *  \param  pTimerRunning   Returns TRUE if a timer is running, FALSE if no timers running.
 *
 *  \return The number of ticks until the next timer expiration.
 */
/*************************************************************************************************/
static wsfTimerTicks_t WsfTimerNextExpiration(bool_t *pTimerRunning)
{
    wsfTimerTicks_t ticks;
    /* task schedule lock */
    uint32_t lock = WsfTaskLock();
    if (wsfTimerTimerQueue.pHead == NULL)
    {
        *pTimerRunning = FALSE;
        ticks = 0;
    }
    else
    {
        *pTimerRunning = TRUE;
        ticks = ((wsfTimer_t *)wsfTimerTimerQueue.pHead)->ticks;
    }
    /* task schedule unlock */
    WsfTaskUnlock(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 seconds.
 *
 *  \param  pTimer  Pointer to timer.
 *  \param  sec     Seconds until expiration.
 *  \param  mode    Timer work mode.
 */
/*************************************************************************************************/
void WsfTimerStartSec(wsfTimer_t *pTimer, wsfTimerTicks_t sec, uint8_t mode)
{
    WSF_TRACE_INFO2("WsfTimerStartSec pTimer:0x%x ticks:%u", (uint32_t)pTimer, WSF_TIMER_SEC_TO_TICKS(sec));
    /* insert timer into queue */
    wsfTimerInsert(pTimer, WSF_TIMER_SEC_TO_TICKS(sec), 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, wsfTimerTicks_t ms, uint8_t mode)
{
    WSF_TRACE_INFO2("WsfTimerStartMs pTimer:0x%x ticks:%u", (uint32_t)pTimer, WSF_TIMER_MS_TO_TICKS(ms));
    /* insert timer into queue */
    wsfTimerInsert(pTimer, WSF_TIMER_MS_TO_TICKS(ms), mode);
}
/*************************************************************************************************/
/*!
 *  \brief  Stop a timer.
 *
 *  \param  pTimer  Pointer to timer.
 */
/*************************************************************************************************/
void WsfTimerStop(wsfTimer_t *pTimer)
{
    WSF_TRACE_INFO1("WsfTimerStop pTimer:0x%x", pTimer);
    /* task schedule lock */
    uint32_t lock = WsfTaskLock();
    wsfTimerRemove(pTimer);
    /* task schedule unlock */
    WsfTaskUnlock(lock);
}
/*************************************************************************************************/
/*!
 *  \brief  Update the timer service with the number of elapsed ticks.
 *
 *  \param  ticks  Number of ticks since last update.
 */
/*************************************************************************************************/
void WsfTimerUpdate(wsfTimerTicks_t ticks)
{
    wsfTimer_t *pElem;
    /* task schedule lock */
    uint32_t lock = WsfTaskLock();
    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;
            /* timer expired; set task for this timer as ready */
            WsfTaskSetReady(pElem->handlerId, WSF_TIMER_EVENT);
        }
        pElem = pElem->pNext;
    }
    /* task schedule unlock */
    WsfTaskUnlock(lock);
}
/*************************************************************************************************/
/*!
 *  \brief  Service expired timers for the given task.
 *
 *  \param  taskId      Task ID.
 *
 *  \return Pointer to timer or NULL.
 */
/*************************************************************************************************/
wsfTimer_t *WsfTimerServiceExpired(wsfTaskId_t taskId)
{
    wsfTimer_t *pElem;
    wsfTimer_t *pPrev = NULL;
    /* Unused parameters */
    (void)taskId;
    /* task schedule lock */
    uint32_t lock = WsfTaskLock();
    /* 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
        {
            /* remove timer from queue */
            WsfQueueRemove(&wsfTimerTimerQueue, pElem, pPrev);
            pElem->isStarted = FALSE;
        }
        /* task schedule unlock */
        WsfTaskUnlock(lock);
        WSF_TRACE_INFO1("Timer expired pTimer:0x%x", pElem);
        /* return timer */
        return pElem;
    }
    /* task schedule unlock */
    WsfTaskUnlock(lock);
    return NULL;
}
/*************************************************************************************************/
/*!
 *  \brief  Function for checking if there is an active timer and if there is enough time to
 *          go to sleep and going to sleep.
 */
/*************************************************************************************************/
uint8_t WsfTimerSleepCheck(uint32_t *sleep_ms)
{
    wsfTimerTicks_t nextExpiration;
    /* If PAL system is busy, no need to sleep. */
    if (PalSysIsBusy())
    {
        // active
        return 0;
    }
    bool_t running;
    nextExpiration = WsfTimerNextExpiration(&running);
    if (running)
    {
        uint32_t awake = WSF_MS_PER_TICK * nextExpiration;
        uint32_t elapsed = PalSysTickElapse();
        /* if we have time to sleep before timer expiration */
        if ((awake - elapsed) > WSF_TIMER_MIN_MS_FOR_POWERDOWN)
        {
            *sleep_ms = awake - elapsed;
            // Power down
            return 2;
        }
        else
        {
            /* Not enough time to go to powerdown. Let the system sleep. */
            // Sleep
            return 1;
        }
    }
    else
    {
        *sleep_ms = WSF_TIMER_MAX_MS_FOR_POWERDOWN;
        // Power down
        return 2;
    }
}
//*****************************************************************************
//
// Calculate the elapsed time, and update the WSF software timers.
//
//*****************************************************************************
void WsfTimerUpdateTicks(void)
{
    uint32_t ui32CurrentTick, ui32ElapsedTicks;
    //
    // Read the continuous systick.
    //
    ui32CurrentTick = PalSysTickGet();
    //
    // Figure out how long it has been since the last time we've read the
    // continuous systick.
    //
    if (ui32CurrentTick > wsfTimerSysTickcLastTick)
    {
        ui32ElapsedTicks = ui32CurrentTick - wsfTimerSysTickcLastTick;
    }
    else
    {
        ui32ElapsedTicks = 0xffffffff - wsfTimerSysTickcLastTick + ui32CurrentTick;
    }
    WsfTimerUpdate(ui32ElapsedTicks);
    wsfTimerSysTickcLastTick = ui32CurrentTick;
}