/*
 * Copyright 2020-2023 Yuntu Microelectronics co.,ltd
 * All rights reserved.
 *
 * YUNTU Confidential. This software is owned or controlled by YUNTU and may
 * only be used strictly in accordance with the applicable license terms. By expressly
 * accepting such terms or by downloading, installing, activating and/or otherwise
 * using the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms. If you do not agree to be
 * bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software. The production use license in
 * Section 2.3 is expressly granted for this software.
 */

/*=================================================================================================
 *                                        INCLUDE FILES
========================================================================·=========================*/
#include "cantp_fifo.h"
#include "cantp_cfg.h"

#define STRUCT_LEN (sizeof(cantp_fifo_info_type_t) + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN) /* every fifo struct used space */
#define TOTAL_BYTES ((STRUCT_LEN) * (CANTP_FIFO_USE_NUM) + TOTAL_FIFO_BYTES)

#define PDU_BUFFER_SIZE (100)

#define AddCounter(fifoLen, cnt)                                       \
do {                                                                   \
    (*(cnt))++;                                                        \
    if(*(cnt) >= (fifoLen))                                            \
    {                                                                  \
        *(cnt) -= (fifoLen);                                           \
    }                                                                  \
} while(0)

#define AddWriteCounter(nodePtr)                                       \
do {                                                                   \
    AddCounter(nodePtr->len, &(nodePtr->writeCnt));                    \
} while(0)

#define CheckAndChangeWriteFIFOStatus(nodePtr)                         \
do {                                                                   \
    if((nodePtr)->writeCnt == (nodePtr)->readCnt)                      \
    {                                                                  \
        (nodePtr)->fifoStatus = FIFO_FULL;                             \
    }                                                                  \
    else                                                               \
    {                                                                  \
        (nodePtr)->fifoStatus = FIFO_USING;                            \
    }                                                                  \
} while(0u)

#define AddReadCounter(nodePtr)                                        \
do {                                                                   \
    AddCounter(nodePtr->len, &(nodePtr->readCnt));                     \
} while(0)

#define CheckAndChangeReadFIFOStatus(nodePtr)                          \
do {                                                                   \
    if((nodePtr)->writeCnt == (nodePtr)->readCnt)                      \
    {                                                                  \
        (nodePtr)->fifoStatus = FIFO_EMPTY;                            \
    }                                                                  \
    else                                                               \
    {                                                                  \
        (nodePtr)->fifoStatus = FIFO_USING;                            \
    }                                                                  \
} while(0u)

#define CycleAlign(cnt, len, align)                                    \
do {                                                                   \
    if(cnt + align < len)                                              \
    {                                                                  \
        cnt = cnt + align;                                             \
    }                                                                  \
    else                                                               \
    {                                                                  \
        cnt = 0;                                                       \
    }                                                                  \
} while(0u)
#define CycleOffset(offset, len) (offset > len ? offset - len : offset)
/*==================================================================================================
 *                                         LOCAL VARIABLES
==================================================================================================*/
/* This variable is all data applied for fifo */
static unsigned char CanTp_Fifo_totalArray[TOTAL_BYTES] = {0};
/* can used fifo len */
static cantp_u32 CanTp_Fifo_totalLeftLen = TOTAL_BYTES;

static cantp_fifo_info_type_t* CanTp_Fifo_headArray[CANTP_FIFO_NUM];
/*==================================================================================================
 *                                         LOCAL FUNCTIONS
==================================================================================================*/

/*==================================================================================================
 *                                         GLOBAL FUNCTIONS
==================================================================================================*/
cantp_fifo_res_type CanTp_Fifo_ApplyFifo(cantp_fifo_length_type fifoId, cantp_fifo_length_type fifoLen)
{
    cantp_fifo_info_type_t * nodePtr = (cantp_fifo_info_type_t *)0u;
    cantp_u32 fifoUsedLength = 0u;
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    do
    {
        if (fifoId >= CANTP_FIFO_NUM)
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }
        if (CanTp_Fifo_headArray[fifoId] != CANTP_NULL)
        {
            res = CANTP_FIFO_RES_ERRO_REGISTERED_SECOND;
            break;
        }
        fifoUsedLength =
            (cantp_fifo_length_type)(
                (unsigned char *)((cantp_fifo_info_type_t *)(&CanTp_Fifo_totalArray[TOTAL_BYTES - CanTp_Fifo_totalLeftLen]) + 1u) -
                (unsigned char *)(&CanTp_Fifo_totalArray[TOTAL_BYTES - CanTp_Fifo_totalLeftLen])
            );
        fifoUsedLength += fifoLen;
        fifoUsedLength += (sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN);
        if (fifoUsedLength > CanTp_Fifo_totalLeftLen)
        {
            res = CANTP_FIFO_RES_OVERFLOW;
            break;
        }
        nodePtr = (cantp_fifo_info_type_t *)(&CanTp_Fifo_totalArray[TOTAL_BYTES - CanTp_Fifo_totalLeftLen]);
        nodePtr->id = fifoId;
        nodePtr->len = fifoLen;
        nodePtr->readCnt = 0U;
        nodePtr->writeCnt = 0U;
        nodePtr->lastMsgInfoPtr = CANTP_NULL;
        nodePtr->beginAddr =
            (unsigned char *)((cantp_fifo_info_type_t *)(&CanTp_Fifo_totalArray[TOTAL_BYTES - CanTp_Fifo_totalLeftLen]) + 1u);
        nodePtr->fifoStatus = FIFO_EMPTY;
        CanTp_Fifo_totalLeftLen -= fifoUsedLength;
        CanTp_Fifo_headArray[fifoId] = nodePtr;
    } while (CANTP_FALSE);
    return res;
}

cantp_fifo_res_type CanTp_Fifo_PopPduData(cantp_fifo_id_type fifoId, cantp_fifo_length_type len, unsigned char * ptr)
{
    cantp_fifo_info_type_t *nodePtr = (cantp_fifo_info_type_t *)0u;
    cantp_fifo_length_type idx = 0u;
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    do
    {
        /* Fifo id check */
        if (fifoId > CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }

        if (CANTP_NULL == ptr)
        {
            res = CANTP_FIFO_RES_NULL_POINTER;
            break;
        }
        nodePtr = CanTp_Fifo_headArray[fifoId];
        if (FIFO_EMPTY == nodePtr->fifoStatus)
        {
            res = CANTP_FIFO_RES_EMPTY;
            break;
        }
        cantp_fifo_msg_info_type_t* msgInfoPtr =
            (cantp_fifo_msg_info_type_t*)(nodePtr->beginAddr + nodePtr->readCnt);

        if (msgInfoPtr->copiedLoc + len > msgInfoPtr->pduInfo.sduLength)
        {
            res = CANTP_FIFO_RES_NOT_ENOUGH_DATA_TO_COPY;
            return res;
        }

        cantp_u16 offset = msgInfoPtr->copiedLoc + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;
        for (idx = 0u; idx < len; idx++)
        {
            cantp_u16 loc = nodePtr->readCnt + offset + idx;
            if (loc >= nodePtr->len)
            {
                loc -= nodePtr->len;
            }
            ptr[idx] = (nodePtr->beginAddr)[loc];
        }

        msgInfoPtr->copiedLoc += len;
    } while (CANTP_FALSE);
    return res;
}

cantp_fifo_res_type CanTp_Fifo_GetSdu(cantp_fifo_id_type fifoId, pdu_info_type_t* pduInfoPtr)
{
    cantp_fifo_info_type_t *nodePtr = (cantp_fifo_info_type_t *)0u;
    cantp_fifo_length_type idx = 0u;
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    do
    {
        /* Fifo id check */
        if (fifoId > CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }

        if (CANTP_NULL == pduInfoPtr)
        {
            res = CANTP_FIFO_RES_NULL_POINTER;
            break;
        }
        nodePtr = CanTp_Fifo_headArray[fifoId];
        if (FIFO_EMPTY == nodePtr->fifoStatus)
        {
            res = CANTP_FIFO_RES_EMPTY;
            break;
        }
        cantp_fifo_msg_info_type_t* msgInfoPtr =
            (cantp_fifo_msg_info_type_t*)(nodePtr->beginAddr + nodePtr->readCnt);

        if (msgInfoPtr->pduInfo.sduLength > pduInfoPtr->sduLength)
        {
            res = CANTP_FIFO_RES_MEM_NOT_ENOUGH;
            break;
        }
        cantp_u16 offset = sizeof(cantp_fifo_msg_info_type_t);
        if (pduInfoPtr->metaDataPtr != CANTP_NULL)
        {
            for (idx = 0u; idx < META_DATA_LEN; idx++)
            {
                cantp_u16 loc = nodePtr->readCnt + offset + idx;
                if (loc >= nodePtr->len)
                {
                    loc -= nodePtr->len;
                }
                pduInfoPtr->metaDataPtr[idx] = (nodePtr->beginAddr)[loc];
            }
        }
        offset = sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;
        for (idx = 0u; idx < msgInfoPtr->pduInfo.sduLength; idx++)
        {
            cantp_u16 loc = nodePtr->readCnt + offset + idx;
            if (loc >= nodePtr->len)
            {
                loc -= nodePtr->len;
            }
            pduInfoPtr->sduDataPtr[idx] = (nodePtr->beginAddr)[loc];
        }
        pduInfoPtr->sduLength = msgInfoPtr->pduInfo.sduLength;
    } while (CANTP_FALSE);
    return res;
}

cantp_fifo_msg_info_type_t* CanTp_Fifo_GetMsgPtr(cantp_fifo_id_type fifoId)
{
    cantp_fifo_info_type_t *nodePtr = (cantp_fifo_info_type_t *)0u;
    if (fifoId >= CANTP_FIFO_NUM)
    {
        return CANTP_NULL;
    }
    nodePtr = CanTp_Fifo_headArray[fifoId];
    return (cantp_fifo_msg_info_type_t*)(&(nodePtr->beginAddr)[nodePtr->readCnt]);
}

cantp_fifo_res_type CanTp_Fifo_PushSdu(cantp_fifo_id_type fifoId, const pdu_info_type_t* pduInfoPtr)
{
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    do
    {
        /* Fifo id check */
        if (fifoId > CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }
        if (pduInfoPtr->sduDataPtr == CANTP_NULL)
        {
            res = CANTP_FIFO_RES_NULL_POINTER;
        }
        if (pduInfoPtr->sduLength == 0U)
        {
            res = CANTP_FIFO_RES_NO_MSG;
            break;
        }
        cantp_fifo_info_type_t * nodePtr = CanTp_Fifo_headArray[fifoId];
        cantp_fifo_length_type idx = 0u;
        cantp_fifo_length_type leftLen = 0u;
        cantp_fifo_msg_info_type_t tempMsg;
        cantp_u8 * ptr = (cantp_u8 *)(&tempMsg);
        leftLen = CanTp_Fifo_GetCanWriteLen(fifoId);

        cantp_fifo_length_type needWriteLen =
            pduInfoPtr->sduLength + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;

#if (CANTP_FIFO_ALIGN == STD_ON) 
        cantp_u8 alignDataLen = (4U - (pduInfoPtr->sduLength % 4U)) & 0b11;
        needWriteLen += alignDataLen;
#endif
        /* Fifo overflow check */
        if (needWriteLen > leftLen)
        {
            res = CANTP_FIFO_RES_OVERFLOW;
            break;
        }


        /* CanStack_MsgInfo init */
        tempMsg.isTransmitting = CANTP_FALSE;
        tempMsg.copiedLoc = 0U;

        cantp_fifo_length_type offset;
        if (CANTP_NULL == pduInfoPtr->metaDataPtr)                    // Pdu may not contain meta data
        {
            tempMsg.pduInfo.metaDataPtr = CANTP_NULL;
        }
        else
        {
            offset = nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t);
            offset = CycleOffset(offset, nodePtr->len);
            tempMsg.pduInfo.metaDataPtr = &(nodePtr->beginAddr)[offset];
        }

        offset = nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;
        offset = CycleOffset(offset, nodePtr->len);
        tempMsg.pduInfo.sduDataPtr = &(nodePtr->beginAddr)[offset];

        tempMsg.pduInfo.sduLength = pduInfoPtr->sduLength;

        nodePtr->lastMsgInfoPtr =
            (cantp_fifo_msg_info_type_t*)(&(nodePtr->beginAddr)[nodePtr->writeCnt]);

        if (nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t) > nodePtr->len)
        {
            /**
             * The msgInfoPtr needs to be written to contiguous memory to ensure correct subsequent usage.
             * Therefore, there is additional memory allocated for each FIFO to ensure that the msgInfoPtr
             * can be stored contiguously.
             */
            for (idx = 0U; idx < sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN; idx++)
            {
                (nodePtr->beginAddr)[nodePtr->writeCnt + idx] = ptr[idx];
            }
        }
        for (idx = 0U; idx < sizeof(cantp_fifo_msg_info_type_t); idx++)   // write Msg info
        {
            (nodePtr->beginAddr)[nodePtr->writeCnt] = ptr[idx];
            AddWriteCounter(nodePtr);
        }

        ptr = pduInfoPtr->metaDataPtr;
        for (idx = 0U; idx < META_DATA_LEN; idx++)                  // write meta data
        {
            if (CANTP_NULL != ptr)
            {
                (nodePtr->beginAddr)[nodePtr->writeCnt] = ptr[idx];
            }
            AddWriteCounter(nodePtr);
        }

        ptr = pduInfoPtr->sduDataPtr;
        for (idx = 0U; idx < pduInfoPtr->sduLength; idx++)          // write sdu data
        {
            (nodePtr->beginAddr)[nodePtr->writeCnt] = ptr[idx];
            AddWriteCounter(nodePtr);
        }
#if (CANTP_FIFO_ALIGN == STD_ON) 
        cantp_u8 align = (4U - (nodePtr->writeCnt % 4U)) & 0b11;
        CycleAlign(nodePtr->writeCnt, nodePtr->len, align);
#endif
        /* check and change write FIFO status */
        CheckAndChangeWriteFIFOStatus(nodePtr);
    } while (CANTP_FALSE);
    return res;
}

cantp_fifo_res_type CanTp_Fifo_StartSdu(cantp_fifo_id_type fifoId, const pdu_info_type_t* pduInfoPtr)
{
    cantp_fifo_info_type_t * nodePtr = CanTp_Fifo_headArray[fifoId];
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    /* Fifo id check */
    if (fifoId > CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
    {
        res = CANTP_FIFO_RES_INVALID_FIFOID;
        return res;
    }

    /* Overflow check */
    cantp_u16 leftLen = CanTp_Fifo_GetCanWriteLen(fifoId);
    cantp_fifo_length_type needWriteLen = 
        pduInfoPtr->sduLength + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;
#if (CANTP_FIFO_ALIGN == STD_ON) 
    cantp_u8 alignDataLen = (4U - (pduInfoPtr->sduLength % 4U)) & 0b11U;
    needWriteLen += alignDataLen;
#endif
    if (leftLen < needWriteLen)
    {
        res = CANTP_FIFO_RES_OVERFLOW;
        return res;
    }

    /* Sdu Check */
    if (nodePtr->lastMsgInfoPtr != CANTP_NULL &&
            nodePtr->lastMsgInfoPtr->isTransmitting == CANTP_TRUE )
    {
        res = CANTP_FIFO_RES_PDU_IS_TRANSMITTING;
        return res;
    }
    cantp_fifo_length_type idx = 0u;
    cantp_fifo_msg_info_type_t tempMsg;
    cantp_fifo_length_type offset;
    cantp_u8 * ptr = (cantp_u8 *)(&tempMsg);
    // prepare Temp msgInfoPtr
    tempMsg.isTransmitting = CANTP_TRUE;
    tempMsg.copiedLoc = 0U;

    // Meta data ptr in pduInfoPtr
    if (CANTP_NULL == pduInfoPtr->metaDataPtr)
    {
        tempMsg.pduInfo.metaDataPtr = CANTP_NULL;
    }
    else
    {
        /* Cycle */
        offset = nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t);
        offset = CycleOffset(offset, nodePtr->len);
        tempMsg.pduInfo.metaDataPtr = &(nodePtr->beginAddr)[offset];
    }

    // data ptr in pduInfoPtr
    offset = nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;
    offset = CycleOffset(offset, nodePtr->len);
    tempMsg.pduInfo.sduDataPtr = &(nodePtr->beginAddr)[offset];

    // data length in pduInfoPtr
    tempMsg.pduInfo.sduLength = pduInfoPtr->sduLength;


    // update lastMsgInfoPtr for later copy data to fifo
    nodePtr->lastMsgInfoPtr = (cantp_fifo_msg_info_type_t*)(&(nodePtr->beginAddr)[nodePtr->writeCnt]);
    /* This msg may be abort in the future, so don't change the write cnt */
    cantp_fifo_length_type tempWriteAddr = nodePtr->writeCnt;

    // write Msg info
    if (nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t) > nodePtr->len)
    {
        /**
         * The msgInfoPtr needs to be written to contiguous memory to ensure correct subsequent usage.
         * Therefore, there is additional memory allocated for each FIFO to ensure that the msgInfoPtr
         * can be stored contiguously.
         */
        for (idx = (nodePtr->len - nodePtr->writeCnt); idx < sizeof(cantp_fifo_msg_info_type_t); idx++)
        {
            (nodePtr->beginAddr)[nodePtr->writeCnt + idx] = ptr[idx];
        }
    }
    for (idx = 0U; idx < sizeof(cantp_fifo_msg_info_type_t); idx++)
    {
        (nodePtr->beginAddr)[nodePtr->writeCnt] = ptr[idx];
        AddWriteCounter(nodePtr);
    }

    // write meta data
    ptr = pduInfoPtr->metaDataPtr;
    for (idx = 0U; idx < META_DATA_LEN; idx++)
    {
        if (CANTP_NULL != ptr)
        {
            (nodePtr->beginAddr)[nodePtr->writeCnt] = ptr[idx];
        }
        AddWriteCounter(nodePtr);
    }
    nodePtr->writeCnt = tempWriteAddr;
    return res;
}

cantp_fifo_res_type CanTp_Fifo_PopSdu(cantp_fifo_id_type fifoId)
{
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    cantp_fifo_info_type_t * nodePtr = (cantp_fifo_info_type_t *)0U;
    do
    {
        if (fifoId >= CANTP_FIFO_NUM|| CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }
        nodePtr = CanTp_Fifo_headArray[fifoId];

        /* Transmitting sdu will not change write cnt */
        if (FIFO_EMPTY == nodePtr->fifoStatus)
        {
            res = CANTP_FIFO_RES_NO_SDU_IN_FIFO;
            break;
        }
        /* Transmitted sdu will change write cnt, some sdu is received */
        cantp_fifo_msg_info_type_t* msgInfoPtr =
            (cantp_fifo_msg_info_type_t*) (nodePtr->beginAddr + nodePtr->readCnt);
        if (nodePtr->lastMsgInfoPtr == msgInfoPtr)
        {
            nodePtr->lastMsgInfoPtr = CANTP_NULL;
        }
        cantp_fifo_length_type pduLength = msgInfoPtr->pduInfo.sduLength;
        cantp_fifo_length_type msgLen = sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN + pduLength;
        nodePtr->readCnt = nodePtr->readCnt + msgLen;
        if (nodePtr->readCnt >= nodePtr->len)
        {
            nodePtr->readCnt -= nodePtr->len;
        }
#if (CANTP_FIFO_ALIGN == STD_ON) 
        cantp_u8 align = (4U - (nodePtr->readCnt % 4U)) & 0b11U;
        CycleAlign(nodePtr->readCnt, nodePtr->len, align);
#endif
        CheckAndChangeReadFIFOStatus(nodePtr);
    } while (CANTP_FALSE);

    return res;
}

cantp_fifo_res_type CanTp_Fifo_PushPduData(cantp_fifo_id_type fifoId, cantp_fifo_length_type len, cantp_u8* ptr)
{
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    do
    {
        if (fifoId >= CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }
        cantp_fifo_info_type_t * nodePtr = (cantp_fifo_info_type_t *)0U;
        nodePtr = CanTp_Fifo_headArray[fifoId];
        cantp_fifo_msg_info_type_t* msgInfoPtr = nodePtr->lastMsgInfoPtr;
        if (CANTP_NULL == msgInfoPtr || msgInfoPtr->isTransmitting == CANTP_FALSE)
        {
            res = CANTP_FIFO_RES_PDU_IS_NOT_TRANSMITTING;
            break;
        }
        if (len + msgInfoPtr->copiedLoc > msgInfoPtr->pduInfo.sduLength)
        {
            res = CANTP_FIFO_RES_OVERFLOW;
            break;
        }
        for (cantp_u8 idx = 0U; idx < len; idx++)
        {
            cantp_fifo_length_type offset = nodePtr->writeCnt + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN +
                                            msgInfoPtr->copiedLoc + idx;
            if(offset >= nodePtr->len)
            {
                offset -= nodePtr->len;
            }
            nodePtr->beginAddr[offset] = ptr[idx];
        }
        msgInfoPtr->copiedLoc += len;
    } while (CANTP_FALSE);

    return res;
}

cantp_fifo_res_type CanTp_Fifo_FinishSdu(cantp_fifo_id_type fifoId, cantp_core_res_type sduRes)
{
    cantp_fifo_info_type_t * nodePtr = (cantp_fifo_info_type_t *)0U;
    cantp_fifo_res_type res = CANTP_FIFO_RES_SUCCESS;
    do
    {
        /* Fifo id check */
        if (fifoId >= CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            res = CANTP_FIFO_RES_INVALID_FIFOID;
            break;
        }
        nodePtr = CanTp_Fifo_headArray[fifoId];
        /* Fifo Msg pduInfoPtr check */
        cantp_fifo_msg_info_type_t* msgInfoPtr = nodePtr->lastMsgInfoPtr;
        if (CANTP_NULL == msgInfoPtr)
        {
            res = CANTP_FIFO_RES_PDU_IS_NOT_TRANSMITTING;
            break;
        }

        /* Finish transmit */
        msgInfoPtr->isTransmitting = CANTP_FALSE;
        nodePtr->lastMsgInfoPtr = CANTP_NULL;
        if (CANTP_CORE_N_OK != sduRes)
        {
            /* Cancel transmit or some error happens */
            break;
        }

        /* Check whether the copied len is equal to sdu data length */
        if (msgInfoPtr->copiedLoc != msgInfoPtr->pduInfo.sduLength)
        {
            res = CANTP_FIFO_RES_NOT_ENOUGH_DATA_COPIED;
            break;
        }

        nodePtr->writeCnt += msgInfoPtr->copiedLoc + sizeof(cantp_fifo_msg_info_type_t) + META_DATA_LEN;
        if (nodePtr->writeCnt >= nodePtr->len)
        {
            nodePtr->writeCnt -= nodePtr->len;
        }
#if (CANTP_FIFO_ALIGN == STD_ON) 
        cantp_u8 align = (4U - (nodePtr->writeCnt % 4U)) & 0b11U;
        CycleAlign(nodePtr->writeCnt, nodePtr->len, align);
#endif
        CheckAndChangeWriteFIFOStatus(nodePtr);
        /* Complete receiving, ready to pop */
        msgInfoPtr->copiedLoc = 0;
    } while (CANTP_FALSE);

    return res;
}

cantp_u16 CanTp_Fifo_GetCanWriteLen(cantp_fifo_id_type fifoId)
{
    if (fifoId > CANTP_FIFO_NUM) return 0;
    cantp_fifo_info_type_t* nodePtr = CanTp_Fifo_headArray[fifoId];
    cantp_fifo_length_type len;
    if (FIFO_USING == nodePtr->fifoStatus)
    {
        len =
            (nodePtr->readCnt > nodePtr->writeCnt) ?
            (nodePtr->readCnt - nodePtr->writeCnt) :
            (nodePtr->len + nodePtr->readCnt - nodePtr->writeCnt);
    }
    else if (FIFO_EMPTY == nodePtr->fifoStatus)
    {
        len = nodePtr->len;
    }
    else
    {
        len = (cantp_fifo_length_type)0u;
    }
    return len;
}

cantp_fifo_info_type_t** CanTp_Fifo_GetFifoArray()
{
    return CanTp_Fifo_headArray;
}

cantp_bool CanTp_Fifo_IsWaitTx(cantp_fifo_id_type fifoId, cantp_u32* pendingLength)
{
    cantp_fifo_info_type_t * nodePtr = (cantp_fifo_info_type_t *)0U;
    cantp_bool res = CANTP_FALSE;
    do
    {
        /* Fifo id check */
        if (fifoId >= CANTP_FIFO_NUM || CANTP_NULL == CanTp_Fifo_headArray[fifoId])
        {
            /* CANTP_FIFO_RES_INVALID_FIFOID */
            break;
        }
        nodePtr = CanTp_Fifo_headArray[fifoId];

        if (nodePtr->fifoStatus == FIFO_EMPTY || nodePtr->lastMsgInfoPtr == CANTP_NULL)
        {
            break;
        }
        cantp_fifo_msg_info_type_t* msgInfoPtr = (cantp_fifo_msg_info_type_t*)(nodePtr->beginAddr + nodePtr->readCnt);
        *pendingLength = msgInfoPtr->pduInfo.sduLength - msgInfoPtr->copiedLoc;
        res = CANTP_TRUE;
    } while (CANTP_FALSE);

    return res;
}

cantp_fifo_res_type ResetFifo()
{
    /* Clear CanTp_Fifo_headArray item to CANTP_NULL */
    for (cantp_u16 idx = 0U; idx < CANTP_FIFO_NUM; idx++)
    {
        CanTp_Fifo_headArray[idx] = CANTP_NULL;
        CanTp_Fifo_totalLeftLen = TOTAL_BYTES;
    }
    /* Clear all fifo data to 0 */
    for (cantp_u16 idx = 0U; idx < TOTAL_BYTES; idx++)
    {
        CanTp_Fifo_totalArray[idx] = 0x5DU;
    }
    return CANTP_FIFO_RES_SUCCESS;
}
