/* SPDX-License-Identifier: Apache-2.0 */
/******************************************************************************/
/**                                                                           */
/** RK0 - The Embedded Real-Time Kernel '0'                                   */
/** (C) 2026 Antonio Giacomelli <dev@kernel0.org>                             */
/**                                                                           */
/** VERSION: V0.60.0 */
/**                                                                           */
/** You may obtain a copy of the License at :                                 */
/** http://www.apache.org/licenses/LICENSE-2.0                                */
/**                                                                           */
/******************************************************************************/
/******************************************************************************/
/* COMPONENT: TIMER                                                           */
/******************************************************************************/

#define RK_SOURCE_CODE
#include "ktimer.h"
#include <ktrace.h>

#if (RK_CONF_CHANNEL == ON)
extern VOID kChannelTimeoutRequest(RK_TCB *const callerPtr);
#endif
#if (RK_CONF_MUTEX == ON)
extern VOID kMutexTimeoutWaiter(RK_TCB *const waiterPtr);
#endif
#if (RK_CONF_RENDEZVOUS == ON)
extern VOID kRendezvousTimeoutSend(RK_TCB *const senderPtr);
#endif

/******************************************************************************
 * GLOBAL TICK RETURN
 *****************************************************************************/

ULONG RK_gSysTickInterval = 0;

RK_TICK kTickGet(void)
{
    RK_CR_AREA
    RK_CR_ENTER
    RK_TICK ret = (RK_gRunTime.globalTick);
    RK_CR_EXIT
    return (ret);
}

RK_TICK kTickGetMs(VOID)
{
    RK_CR_AREA
    RK_CR_ENTER
    RK_TICK ret = 0UL;
    if (RK_gSysTickInterval != 0)
    {
        ret = (RK_gRunTime.globalTick * RK_gSysTickInterval);
    }
    else
    {
        K_PANIC("System tick interval not set");
    }
    RK_CR_EXIT
    return (ret);
}

RK_BOOL kTimeoutNodeIsArmed(RK_TIMEOUT_NODE const *node)
{
    return (((node != NULL) && (node->listRefPtr != NULL)) ? RK_TRUE
                                                           : RK_FALSE);
}

VOID kTimeoutNodeReset(RK_TIMEOUT_NODE *node)
{
    if (node == NULL)
    {
        return;
    }

    node->nextPtr = NULL;
    node->prevPtr = NULL;
    node->listRefPtr = NULL;
    node->timeoutType = 0U;
    node->timeout = 0UL;
    node->dtick = 0UL;
    node->waitingQueuePtr = NULL;
    node->waitInfo = 0U;
}

RK_ERR kTimeoutNodeDisarm(RK_TIMEOUT_NODE *node)
{
    RK_ERR err = kRemoveTimeoutNode(node);

    if (err != RK_ERR_SUCCESS)
    {
        K_PANIC("Timeout handling critical failure");
        kTimeoutNodeReset(node);
        return (err);
    }

    kTimeoutNodeReset(node);
    return (RK_ERR_SUCCESS);
}

RK_ERR kDelay(RK_TICK const ticks)
{

#if (RK_CONF_ERR_CHECK == ON)
    if (kIsISR())
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_ISR_PRIMITIVE);
        return (RK_ERR_INVALID_ISR_PRIMITIVE);
    }
    if (ticks > RK_MAX_PERIOD)
    {

        K_ERR_HANDLER(RK_ERR_INVALID_PARAM);
        return (RK_ERR_INVALID_PARAM);
    }
#endif

    RK_TICK remaining = ticks;
    RK_TICK lastObservedTick = kTickGet();

    while (remaining > 0UL)
    {
        RK_TICK now = kTickGet();
        if (now == lastObservedTick)
        {
            continue;
        }

        /*
         * emulates CPU workload. Count one unit per observed tick
         * change
         */
        lastObservedTick = now;
        --remaining;
    }

    return (RK_ERR_SUCCESS);
}

#if (RK_CONF_CALLOUT_TIMER == ON)

/******************************************************************************
 * CALLOUT TIMERS
 *****************************************************************************/
static inline RK_ERR kTimerListAdd_(RK_TIMER *kobj, RK_TICK phase,
                                    RK_TICK countTicks, RK_TIMER_CALLOUT funPtr,
                                    VOID *argsPtr, RK_OPTION reload)
{
    RK_TICK const initialDelay = phase + countTicks;

    kobj->timeoutNode.dtick = initialDelay;
    kobj->timeoutNode.timeout = initialDelay;
    kobj->timeoutNode.timeoutType = RK_TIMEOUT_CALL;
    kobj->funPtr = funPtr;
    kobj->argsPtr = argsPtr;
    kobj->reload = reload;
    kobj->phase = phase;
    kobj->period = countTicks;
    kobj->nextTime = K_TICK_ADD(kTickGet(), phase + countTicks);
    return (kTimeoutNodeAdd(&kobj->timeoutNode, initialDelay));
}

RK_ERR kTimerInit(RK_TIMER *const kobj, RK_TICK const phase,
                  RK_TICK const countTicks, RK_TIMER_CALLOUT const funPtr,
                  VOID *const argsPtr, RK_OPTION const reload)
{
    RK_CR_AREA
    RK_CR_ENTER

#if (RK_CONF_ERR_CHECK == ON)

    if ((kobj == NULL) || (funPtr == NULL))
    {
        K_ERR_HANDLER(RK_FAULT_OBJ_NULL);
        RK_CR_EXIT
        return (RK_ERR_OBJ_NULL);
    }
    if (kobj->init == RK_TRUE)
    {
        K_ERR_HANDLER(RK_FAULT_OBJ_DOUBLE_INIT);
        RK_CR_EXIT
        return (RK_ERR_OBJ_DOUBLE_INIT);
    }

    if ((countTicks == 0UL) || (countTicks > RK_MAX_PERIOD) ||
        (phase > RK_MAX_PERIOD) ||
        (phase > (RK_MAX_PERIOD - countTicks)) ||
        ((reload != RK_TIMER_ONESHOT) && (reload != RK_TIMER_RELOAD)))
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_PARAM);
        RK_CR_EXIT
        return (RK_ERR_INVALID_PARAM);
    }

#endif

    if ((countTicks == 0UL) || (countTicks > RK_MAX_PERIOD) ||
        (phase > RK_MAX_PERIOD) ||
        (phase > (RK_MAX_PERIOD - countTicks)) ||
        ((reload != RK_TIMER_ONESHOT) && (reload != RK_TIMER_RELOAD)))
    {
        RK_CR_EXIT
        return (RK_ERR_INVALID_PARAM);
    }

    RK_ERR err =
        kTimerListAdd_(kobj, phase, countTicks, funPtr, argsPtr, reload);
    if (err == 0)
    {
        kobj->init = RK_TRUE;
        kobj->objID = RK_TIMER_KOBJ_ID;
        kobj->objName[0] = '\0';
        kTraceRegisterObject(kobj, RK_TIMER_KOBJ_ID);
    }
    RK_CR_EXIT
    return (err);
}

VOID kTimerReload(RK_TIMER *kobj, RK_TICK delay)
{
    kobj->timeoutNode.timeoutType = RK_TIMEOUT_CALL;
    RK_ERR err = kTimeoutNodeAdd(&kobj->timeoutNode, delay);
    K_ASSERT(err == RK_ERR_SUCCESS);
    kTraceRecordObject(kobj, RK_TRACE_OP_RELOAD, err, delay);
}

VOID kRemoveTimerNode(RK_TIMEOUT_NODE *node)
{
    RK_ERR err = kTimeoutNodeDisarm(node);
    K_ASSERT(err == RK_ERR_SUCCESS);
}

RK_ERR kTimerCancel(RK_TIMER *const kobj)
{
    RK_CR_AREA
    RK_CR_ENTER
#if (RK_CONF_ERR_CHECK == ON)
    if (kobj == NULL)
    {
        K_ERR_HANDLER(RK_FAULT_OBJ_NULL);
        RK_CR_EXIT
        return (RK_ERR_OBJ_NULL);
    }
    if ((kobj->objID != RK_TIMER_KOBJ_ID) || (kobj->init != RK_TRUE))
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_OBJ);
        RK_CR_EXIT
        return (RK_ERR_INVALID_OBJ);
    }
#endif

    RK_TIMEOUT_NODE *node = (RK_TIMEOUT_NODE *)&kobj->timeoutNode;
    RK_ERR err = RK_ERR_SUCCESS;
    if (kTimeoutNodeIsArmed(node) == RK_TRUE)
    {
        err = kTimeoutNodeDisarm(node);
    }
    kTraceRecordObject(kobj, RK_TRACE_OP_CANCEL, err, 0UL);

    RK_CR_EXIT
    return (err);
}
#endif
/*******************************************************************************
 * SLEEP TIMER AND BLOCKING TIME-OUT
 ******************************************************************************/
RK_ERR kSleepDelay(RK_TICK ticks)
{
    RK_CR_AREA
    RK_CR_ENTER
#if (RK_CONF_ERR_CHECK == ON)
    if (kIsISR())
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_ISR_PRIMITIVE);
        RK_CR_EXIT
        return (RK_ERR_INVALID_ISR_PRIMITIVE);
    }
    if (RK_gRunPtr->status != RK_RUNNING)
    {
        K_ERR_HANDLER(RK_FAULT_TASK_INVALID_STATE);
        RK_CR_EXIT
        return (RK_ERR_TASK_INVALID_ST);
    }
    if (ticks > RK_MAX_PERIOD)
    {
        RK_CR_EXIT
        K_ERR_HANDLER(RK_FAULT_INVALID_PARAM);
        return (RK_ERR_INVALID_PARAM);
    }
#endif
    if (ticks == 0)
    {
        RK_CR_EXIT
        return (RK_ERR_TIMEOUT);
    }

    RK_TASK_SLEEP_TIMEOUT_SETUP

    RK_ERR err = kTimeoutNodeAdd(&RK_gRunPtr->timeoutNode, ticks);
    if (err != RK_ERR_SUCCESS)
    {
        kTimeoutNodeReset(&RK_gRunPtr->timeoutNode);
        RK_CR_EXIT
        return (err);
    }
    RK_gRunPtr->status = RK_SLEEPING_DELAY;
    kPendCtxSwtch();
    RK_CR_EXIT
    return (RK_ERR_SUCCESS);
}

RK_ERR kSleepRelease(RK_TICK period)
{

    RK_CR_AREA
    RK_CR_ENTER

#if (RK_CONF_ERR_CHECK == ON)

    if (period == 0)
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_PARAM);
        RK_CR_EXIT
        return (RK_ERR_INVALID_PARAM);
    }
    if ((ULONG)(period) > RK_MAX_PERIOD)
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_PARAM);
        RK_CR_EXIT
        return (RK_ERR_INVALID_PARAM);
    }

    if (kIsISR())
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_ISR_PRIMITIVE);
        RK_CR_EXIT
        return (RK_ERR_INVALID_ISR_PRIMITIVE);
    }
#endif

    if ((period == 0UL) || ((ULONG)(period) > RK_MAX_PERIOD))
    {
        RK_CR_EXIT
        return (RK_ERR_INVALID_PARAM);
    }

    /* a call to sleep release means end cycle + schedule next activation */
    /* first waketime is 0, meaning the initial baseWake for every task is */
    /* when the schedular starts, so, on the first activation of every task */
    /* the accumulated delay until the end of its computation time is taken */
    /* into account. */
    /* offsetFactor is 1 for no overrun */
    /* then, offset is factor x period.    */
    /* delay = offset+current */

    RK_TICK current = kTickGet();
    RK_TICK baseWake = RK_gRunPtr->wakeTime;
    RK_TICK elapsed = K_TICK_DELTA(current, baseWake);

    /* elapsed/period is > 0 iff */
    RK_TICK offsetFactor = ((elapsed / period) + 1);
    if (offsetFactor > 1)
    {
        RK_gRunPtr->overrunCount += 1U;
        kTraceRecordTaskOverrun(RK_TRACE_OVERRUN_RELEASE, period,
                                (elapsed - period),
                                (ULONG)(offsetFactor - 1U));
    }
    RK_TICK offset = (RK_TICK)(offsetFactor * period);
    RK_TICK nextWake = K_TICK_ADD(baseWake, offset);
    RK_TICK delay = 0;
    delay = K_TICK_DELTA(nextWake, current);
    if (delay == 0)
    {
#ifndef NDEBUG

        {
            K_PANIC("0 DELAY SLEEPRELEASE\r\n");
            return (RK_ERR_ERROR);
        }
#else
        {
            /* this is not supposed to happen, but a possible fallback is
            to set reassign delay to remaining time next phase */

            /* get remainder */
            RK_TICK rem = current - (current / period) * period;
            delay = (rem == 0UL) ? period : (period - rem);
            nextWake = K_TICK_ADD(current, delay);
        }
#endif
    }
    RK_gRunPtr->wakeTime = nextWake;
    RK_TASK_SLEEP_TIMEOUT_SETUP
    RK_ERR err = kTimeoutNodeAdd(&RK_gRunPtr->timeoutNode, delay);
    if (err != RK_ERR_SUCCESS)
    {
        kTimeoutNodeReset(&RK_gRunPtr->timeoutNode);
        RK_CR_EXIT
        return (err);
    }
    RK_gRunPtr->status = RK_SLEEPING_RELEASE;
    kPendCtxSwtch();
    RK_CR_EXIT
    return (RK_ERR_SUCCESS);
}

/* sleep for time, relative to local anchored tick */
RK_ERR kSleepUntil(RK_TICK *lastTickPtr, RK_TICK const ticks)
{
    RK_CR_AREA
    RK_CR_ENTER

#if (RK_CONF_ERR_CHECK == ON)
    if (lastTickPtr == NULL)
    {
        K_ERR_HANDLER(RK_FAULT_OBJ_NULL);
        RK_CR_EXIT
        return RK_ERR_OBJ_NULL;
    }
    if (ticks > RK_MAX_PERIOD)
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_PARAM);
        RK_CR_EXIT
        return RK_ERR_INVALID_PARAM;
    }
    if (ticks == 0UL)
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_PARAM);
        RK_CR_EXIT
        return RK_ERR_INVALID_PARAM;
    }
    if (kIsISR())
    {
        K_ERR_HANDLER(RK_FAULT_INVALID_ISR_PRIMITIVE);
        RK_CR_EXIT
        return RK_ERR_INVALID_ISR_PRIMITIVE;
    }
#endif

    if ((ticks == 0UL) || (ticks > RK_MAX_PERIOD))
    {
        RK_CR_EXIT
        return RK_ERR_INVALID_PARAM;
    }

    RK_TICK now = kTickGet();

    /* advance   */
    *lastTickPtr = K_TICK_ADD(*lastTickPtr, ticks);

    /* late or on-time  */
    if (kTickIsElapsed(*lastTickPtr, now))
    {
        RK_gRunPtr->overrunCount += 1U;
        kTraceRecordTaskOverrun(RK_TRACE_OVERRUN_UNTIL, ticks,
                                K_TICK_DELTA(now, *lastTickPtr), 0UL);
        RK_CR_EXIT
        return (RK_ERR_ELAPSED_PERIOD);
    }

    RK_TICK remaining = K_TICK_DELTA(*lastTickPtr, now);
    RK_TASK_SLEEP_TIMEOUT_SETUP
    RK_ERR err = kTimeoutNodeAdd(&RK_gRunPtr->timeoutNode, remaining);
    if (err != RK_ERR_SUCCESS)
    {
        kTimeoutNodeReset(&RK_gRunPtr->timeoutNode);
        RK_CR_EXIT
        return (err);
    }
    RK_gRunPtr->status = RK_SLEEPING_UNTIL;
    kPendCtxSwtch();
    RK_CR_EXIT
    return (RK_ERR_SUCCESS);
}

static void kTimeoutListInsertDelta_(RK_TIMEOUT_NODE **headPtr,
                                     RK_TIMEOUT_NODE *node)
{
    RK_TIMEOUT_NODE *currPtr = *headPtr;
    RK_TIMEOUT_NODE *prevPtr = NULL;

    while (currPtr != NULL && currPtr->dtick < node->dtick)
    {
        node->dtick -= currPtr->dtick;
        prevPtr = currPtr;
        currPtr = currPtr->nextPtr;
    }

    /* Link node in between prevPtr and currPtr */
    node->nextPtr = currPtr;
    node->prevPtr = prevPtr;

    if (currPtr != NULL)
    {
        currPtr->dtick -= node->dtick;
        currPtr->prevPtr = node;
    }

    if (prevPtr != NULL)
    {
        prevPtr->nextPtr = node;
    }
    else
    {
        *headPtr = node;
    }
}

RK_FORCE_INLINE static inline volatile RK_TIMEOUT_NODE **
kTimeoutNodeListRef_(RK_TIMEOUT_NODE *const node)
{
#if (RK_CONF_CALLOUT_TIMER == ON)
    if (node->timeoutType == RK_TIMEOUT_CALL)
    {
        return (&RK_gTimerListHeadPtr);
    }
#endif
    K_UNUSE(node);
    return (&RK_gTimeOutListHeadPtr);
}

/* add caller to timeout list (delta-list) */
RK_ERR kTimeoutNodeAdd(RK_TIMEOUT_NODE *timeOutNode, RK_TICK timeout)
{
    if (timeout == 0)
    {
#if (RK_CONF_ERR_CHECK == ON)
        K_ERR_HANDLER(RK_FAULT_INVALID_TIMEOUT);
#endif
        return (RK_ERR_INVALID_TIMEOUT);
    }
    if (timeout > RK_MAX_PERIOD)
    {
#if (RK_CONF_ERR_CHECK == ON)
        K_ERR_HANDLER(RK_FAULT_INVALID_TIMEOUT);
#endif
        return (RK_ERR_INVALID_TIMEOUT);
    }
#if (RK_CONF_ERR_CHECK == ON)
    if (timeOutNode == NULL)
    {
        K_ERR_HANDLER(RK_FAULT_OBJ_NULL);
        return (RK_ERR_OBJ_NULL);
    }
#endif
    if (timeOutNode->timeoutType == 0U)
    {
        K_PANIC("Timeout handling critical failure");
        kTimeoutNodeReset(timeOutNode);
        return (RK_ERR_ERROR);
    }
    if (kTimeoutNodeIsArmed(timeOutNode) != RK_FALSE)
    {
        K_PANIC("Timeout handling critical failure");
        kRemoveTimeoutNode(timeOutNode);
        kTimeoutNodeReset(timeOutNode);
        return (RK_ERR_ERROR);
    }
    if (timeOutNode->timeoutType != RK_TIMEOUT_CALL)
    {
        if (RK_gRunPtr == NULL)
        {
#if (RK_CONF_ERR_CHECK == ON)
            K_ERR_HANDLER(RK_FAULT_OBJ_NULL);
#endif
            return (RK_ERR_OBJ_NULL);
        }
        RK_gRunPtr->timeOut = RK_FALSE;
    }
    timeOutNode->timeout = timeout;
    timeOutNode->prevPtr = NULL;
    timeOutNode->nextPtr = NULL;
    timeOutNode->dtick = timeout;
    timeOutNode->listRefPtr = kTimeoutNodeListRef_(timeOutNode);

    kTimeoutListInsertDelta_((RK_TIMEOUT_NODE **)timeOutNode->listRefPtr,
                             timeOutNode);

    return (RK_ERR_SUCCESS);
}
/* Ready the task associated to a time-out node, accordingly to its time-out
 * type */

RK_FORCE_INLINE
static inline RK_ERR kTCBQEnqByWakeTime(RK_TCBQ *const kobj,
                                        RK_TCB *const tcbPtr)
{
    RK_NODE *currNodePtr = &(kobj->listDummy);

    while (currNodePtr->nextPtr != &(kobj->listDummy))
    {
        RK_TCB const *currTcbPtr = K_GET_TCB_ADDR(currNodePtr->nextPtr);
        if (currTcbPtr->wakeTime < tcbPtr->wakeTime)
        {
            break;
        }
        currNodePtr = currNodePtr->nextPtr;
    }

    RK_ERR err = kListInsertAfter(kobj, currNodePtr, &(tcbPtr->tcbNode));

    return (err);
}
RK_ERR kTimeoutNodeReady(volatile RK_TIMEOUT_NODE *node)
{
    RK_TCB *taskPtr = K_GET_CONTAINER_ADDR(node, RK_TCB, timeoutNode);

    K_ASSERT(taskPtr != NULL);

    RK_ERR err = -1;

    if (taskPtr->timeoutNode.timeoutType == RK_TIMEOUT_BLOCKING)
    {
#if (RK_CONF_CHANNEL == ON)
        if ((taskPtr->channelServerPtr != NULL) &&
            ((taskPtr->channelState == RK_CALL_QUEUED) ||
             (taskPtr->channelState == RK_CALL_ACTIVE)))
        {
            kChannelTimeoutRequest(taskPtr);
            taskPtr->timeoutNode.waitInfo = 0U;
        }
#endif
        err = kTCBQRem(taskPtr->timeoutNode.waitingQueuePtr, &taskPtr);
        if (err != RK_ERR_SUCCESS)
        {
            return (err);
        }
#if (RK_CONF_MUTEX == ON)
        if (taskPtr->waitingForMutexPtr != NULL)
        {
            kMutexTimeoutWaiter(taskPtr);
        }
#endif
        err = kTCBQEnq(&RK_gReadyQueue[taskPtr->priority], taskPtr);
        if (err != RK_ERR_SUCCESS)
        {
            return (err);
        }

        taskPtr->timeOut = RK_TRUE;
        taskPtr->status = RK_READY;
        kTimeoutNodeReset(&taskPtr->timeoutNode);
        return (err);
    }
    if (taskPtr->timeoutNode.timeoutType == RK_TIMEOUT_TIME_EVENT)
    {
        err = kTCBQEnq(&RK_gReadyQueue[taskPtr->priority], taskPtr);

        K_ASSERT(err == 0);

        if (err != RK_ERR_SUCCESS)
        {
            return (err);
        }
        /* a time event as any sleep does not change timeOut = TRUE */
        taskPtr->status = RK_READY;
        kTimeoutNodeReset(&taskPtr->timeoutNode);
        return (err);
    }
    if (taskPtr->timeoutNode.timeoutType == RK_TIMEOUT_EVENTFLAGS)
    {
        err = kTCBQEnq(&RK_gReadyQueue[taskPtr->priority], taskPtr);
        if (err != RK_ERR_SUCCESS)
        {
            return (err);
        }
        taskPtr->timeOut = RK_TRUE;
        taskPtr->status = RK_READY;
        kTimeoutNodeReset(&taskPtr->timeoutNode);
        return (err);
    }
#if (RK_CONF_RENDEZVOUS == ON)
    if (taskPtr->timeoutNode.timeoutType == RK_TIMEOUT_SYNCH_SEND)
    {
        kRendezvousTimeoutSend(taskPtr);
        err = kTCBQEnq(&RK_gReadyQueue[taskPtr->priority], taskPtr);
        if (err != RK_ERR_SUCCESS)
        {
            return (err);
        }
        taskPtr->timeOut = RK_TRUE;
        taskPtr->status = RK_READY;
        kTimeoutNodeReset(&taskPtr->timeoutNode);
        return (err);
    }
    if (taskPtr->timeoutNode.timeoutType == RK_TIMEOUT_SYNCH_RECV)
    {
        taskPtr->rendezvousRecvBufPtr = NULL;
        taskPtr->rendezvousRecvMesgBytesPtr = NULL;
        taskPtr->rendezvousRecvStatus = RK_ERR_TIMEOUT;
        err = kTCBQEnq(&RK_gReadyQueue[taskPtr->priority], taskPtr);
        if (err != RK_ERR_SUCCESS)
        {
            return (err);
        }
        taskPtr->timeOut = RK_TRUE;
        taskPtr->status = RK_READY;
        kTimeoutNodeReset(&taskPtr->timeoutNode);
        return (err);
    }
#endif

    return (err);
}

/* runs @ systick */
static volatile RK_TIMEOUT_NODE *nodeg;
UINT kHandleTimeoutList(VOID)
{

    RK_ERR waitingExp = -1;

    if ((RK_gTimeOutListHeadPtr != NULL) && (RK_gTimeOutListHeadPtr->dtick > 0))
    {
        RK_gTimeOutListHeadPtr->dtick--;
    }

    /*  possible to have a node which offset is already (dtick == 0) */
    while (RK_gTimeOutListHeadPtr != NULL && RK_gTimeOutListHeadPtr->dtick == 0)
    {
        nodeg = RK_gTimeOutListHeadPtr;
        waitingExp = kRemoveTimeoutNode((RK_TIMEOUT_NODE *)nodeg);
        K_ASSERT(waitingExp == RK_ERR_SUCCESS);
        if (waitingExp != RK_ERR_SUCCESS)
        {
            return (RK_FALSE);
        }
        waitingExp = kTimeoutNodeReady(nodeg);
    }
    return (waitingExp == RK_ERR_SUCCESS);
}
RK_ERR kRemoveTimeoutNode(RK_TIMEOUT_NODE *node)
{
    if (node == NULL)
        return (RK_ERR_NULL_TIMEOUT_NODE);

    if (kTimeoutNodeIsArmed(node) == RK_FALSE)
    {
        return (RK_ERR_ERROR);
    }

    if (node->nextPtr != NULL)
    {
        node->nextPtr->dtick += node->dtick;
        node->nextPtr->prevPtr = node->prevPtr;
    }

    if (node->prevPtr != NULL)
    {
        node->prevPtr->nextPtr = node->nextPtr;
    }
    else
    {
        *(node->listRefPtr) = node->nextPtr;
    }

    node->nextPtr = NULL;
    node->prevPtr = NULL;
    node->listRefPtr = NULL;
    node->dtick = 0UL;
    return (RK_ERR_SUCCESS);
}
