/*
 * Copyright 2020-2022 Yuntu Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*!
 * @file flexcan_driver.c
 * @version 1.4.1
 *
 * @brief FlexCAN Driver — implementation of the public API.
 *
 * This file implements all FLEXCAN_DRV_* functions declared in
 * flexcan_driver.h plus the internal helpers used by the driver.
 */

/*!
 * @page misra_violations MISRA-C:2012 violations list
 *
 * PRQA S 0326 Rule 11.6 : A cast shall not be performed between pointer to void and an arithmetic type.
 * PRQA S 0310 Rule 11.3 : Casting to different object pointer type.
 * PRQA S 3305 Rule 11.6 : Pointer cast to stricter alignment.
 * PRQA S 2996 Rule 2.2  : The result of this logical operation is always 'false'.
 */ 

#include "flexcan_hw_access.h"
#include "flexcan_irq.h"
#include "interrupt_manager.h"
#include "clock_manager.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define FLEXCAN_MB_HANDLE_RXFIFO    0U


/* CAN bit timing values */
#define FLEXCAN_NUM_TQ_MIN     8U
#define FLEXCAN_NUM_TQ_MAX    26U
#define FLEXCAN_PRESDIV_MAX  256U
#define FLEXCAN_PSEG1_MAX      8U
#define FLEXCAN_PSEG2_MIN      1U
#define FLEXCAN_PSEG2_MAX      8U
#define FLEXCAN_PROPSEG_MAX    8U
#define FLEXCAN_TSEG1_MIN      2U
#define FLEXCAN_TSEG1_MAX     17U
#define FLEXCAN_TSEG2_MIN      2U
#define FLEXCAN_TSEG2_MAX      9U
#define FLEXCAN_RJW_MAX        3U

/*******************************************************************************
 * Variables
 ******************************************************************************/

/* Table of base addresses for CAN instances. */
static CAN_Type * const g_flexcanBase[] = CAN_BASE_PTRS;
/* Tables to save CAN IRQ enum numbers defined in CMSIS header file. */
#if FEATURE_CAN_HAS_WAKE_UP_IRQ
static const IRQn_Type g_flexcanWakeUpIrqId[] = CAN_Wake_Up_IRQS;
#endif
static const IRQn_Type g_flexcanErrorIrqId[] = CAN_Error_IRQS;
static const IRQn_Type g_flexcanBusOffIrqId[] = CAN_Bus_Off_IRQS;
static const IRQn_Type g_flexcanOredMessageBufferIrqId[FEATURE_CAN_MB_IRQS_MAX_COUNT][CAN_INSTANCE_COUNT] = FEATURE_CAN_MB_IRQS;

/* Pointer to runtime state structure.*/
static flexcan_state_t * g_flexcanStatePtr[CAN_INSTANCE_COUNT] = FEATURE_FLEXCAN_STATE_PTR;


/*******************************************************************************
 * Private Functions
 ******************************************************************************/
static status_t FLEXCAN_StartSendData(
                    uint8_t instance,
                    uint8_t mb_idx,
                    const flexcan_data_info_t *tx_info,
                    uint32_t msg_id,
                    const uint8_t *mb_data,
                    bool isBlocking
                    );
static status_t FLEXCAN_StartRxMessageBufferData(
                    uint8_t instance,
                    uint8_t mb_idx,
                    flexcan_msgbuff_t *data,
                    bool isBlocking
                    );
static status_t FLEXCAN_StartRxMessageFifoData(
                    uint8_t instance,
                    flexcan_msgbuff_t *data,
                    bool isBlocking
                    );
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
static status_t FLEXCAN_StartRxMessageEnhanceFifoData(
                    uint8_t instance,
                    flexcan_msgbuff_t *data,
                    bool isBlocking
                    );
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
static void FLEXCAN_CompleteTransfer(uint8_t instance, uint32_t mb_idx);
static void FLEXCAN_CompleteRxMessageFifoData(uint8_t instance);
#if FEATURE_CAN_HAS_DMA_ENABLE
static void FLEXCAN_CompleteRxFifoDataDMA(void *parameter,
                                          dma_chn_status_t status);

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
static void FLEXCAN_CompleteRxEnhanceFifoDataDMA(void *parameter, 
                                          dma_chn_status_t status);
#endif /* FEATURE_CAN_HAS_DMA_ENABLE */
#endif
static uint32_t FLEXCAN_BitrateToTimeSeg(uint32_t bitrate,
                                         uint32_t clkFreq,
                                         flexcan_time_segment_t * timeSeg);
static inline void FLEXCAN_IRQHandlerRxFIFO(uint8_t instance, uint32_t mb_idx);
static void FLEXCAN_IRQHandlerRxMB(uint8_t instance, uint32_t mb_idx);
static inline void FLEXCAN_EnableIRQs(uint8_t instance);
#ifdef ERRATA_E10368
#if FEATURE_CAN_HAS_FD
static inline void FLEXCAN_Errata10368(uint8_t instance,
                                       const flexcan_user_config_t *data);
#endif /* FEATURE_CAN_HAS_FD */
#endif /* ERRATA_E10368 */

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
static void FLEXCAN_CompleteRxMessageEnhanceFifoData(uint8_t instance);
static uint8_t FLEXCAN_UseEnhanceRxFifoComputePayloadSize(uint8_t dlcValue);
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
/*******************************************************************************
 * Code
 ******************************************************************************/

/*!
 * @brief Set FlexCAN baudrate. This function will set up all the time segment values for classical frames or the extended time segments for the arbitration phase of FD frames. Those time segment values are passed in by the user and are based on the required baudrate.
 */
void FLEXCAN_DRV_SetBitrate(uint8_t instance, const flexcan_time_segment_t *bitrate)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(bitrate != NULL);

    CAN_Type * base = g_flexcanBase[instance];
#if FEATURE_CAN_HAS_FD
    bool fdEnabled = FLEXCAN_IsFDEnabled(base);
#endif
    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }
#if FEATURE_CAN_HAS_FD
    if (fdEnabled)
    {
        /* Set extended time segments*/
        FLEXCAN_SetExtendedTimeSegments(base, bitrate);
    }
    else
#endif
    {
        /* Set time segments*/
        FLEXCAN_SetTimeSegments(base, bitrate);
    }

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

#if FEATURE_CAN_HAS_FD
/*!
 * @brief Set FlexCAN bitrate. This function will set up all the time segment values for the data phase of FD frames. Those time segment values are passed in by the user and are based on the required baudrate.
 */
void FLEXCAN_DRV_SetBitrateCbt(uint8_t instance, const flexcan_time_segment_t *bitrate)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(bitrate != NULL);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    /* Set time segments*/
    FLEXCAN_SetFDTimeSegments(base, bitrate);
    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}
#endif

/*!
 * @brief Get FlexCAN baudrate. This function will be return the current bit rate settings for classical frames or the arbitration phase of FD frames.
 */
void  FLEXCAN_DRV_GetBitrate(uint8_t instance, flexcan_time_segment_t *bitrate)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(bitrate != NULL);

    const CAN_Type * base = g_flexcanBase[instance];
#if FEATURE_CAN_HAS_FD
    if (true == FLEXCAN_IsFDEnabled(base))
    {
        /* Get the Extended time segments*/
        FLEXCAN_GetExtendedTimeSegments(base, bitrate);
    }
    else
#endif
    {
        /* Get the time segments*/
        FLEXCAN_GetTimeSegments(base, bitrate);
    }
}

#if FEATURE_CAN_HAS_FD
/*!
 * @brief Get FlexCAN baudrate. This function will be return the current bit rate settings for the data phase of FD frames.
 */
void  FLEXCAN_DRV_GetBitrateFD(uint8_t instance, flexcan_time_segment_t *bitrate)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(bitrate != NULL);

    const CAN_Type * base = g_flexcanBase[instance];

    /* Get the time segments*/
    FLEXCAN_GetFDTimeSegments(base, bitrate);

}
#endif

/*!
 * @brief Set RX masking type. This function will set RX masking type as RX global mask or RX individual mask.
 */
void  FLEXCAN_DRV_SetRxMaskType(uint8_t instance, flexcan_rx_mask_type_t type)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    FLEXCAN_SetRxMaskType(base, type);

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Set Rx FIFO global mask as the 11-bit standard mask or the 29-bit extended mask.
 */
void FLEXCAN_DRV_SetRxFifoGlobalMask(
    uint8_t instance,
    flexcan_msgbuff_id_type_t id_type,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    flexcan_rx_fifo_id_element_format_t formatType;
    CAN_Type * base = g_flexcanBase[instance];
    uint32_t calcMask;

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (true == FLEXCAN_IsRxFifoEnabled(base))
    {
        formatType = FLEXCAN_GetRxFifoIdFormat(base);
        calcMask = FLEXCAN_GetRxFifoMask(id_type, formatType, mask);

        switch (formatType)
        {
            case FLEXCAN_RX_FIFO_ID_FORMAT_A :
                FLEXCAN_SetRxFifoGlobalMask(base, calcMask);
                break;
            case FLEXCAN_RX_FIFO_ID_FORMAT_B :
                FLEXCAN_SetRxFifoGlobalMask(base, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1)));
                break;
            case FLEXCAN_RX_FIFO_ID_FORMAT_C :
                FLEXCAN_SetRxFifoGlobalMask(base, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1) |
                                                              (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2) |
                                                              (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3)));
                break;
            default :
                /* Will Enable all filter fields mask */
                FLEXCAN_SetRxFifoGlobalMask(base, 0xFFFFFFFFU);
                break;
        }
    }
    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Set Rx Message Buffer global mask as the 11-bit standard mask or the 29-bit extended mask.
 */
void FLEXCAN_DRV_SetRxMbGlobalMask(
    uint8_t instance,
    flexcan_msgbuff_id_type_t id_type,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (id_type == FLEXCAN_MSG_ID_STD)
    {
        /* Set standard global mask for RX MB*/
        FLEXCAN_SetRxMsgBuffGlobalStdMask(base, mask);
    }
    else if (id_type == FLEXCAN_MSG_ID_EXT)
    {
        /* Set extended global mask for RX MB*/
        FLEXCAN_SetRxMsgBuffGlobalExtMask(base, mask);
    }
    else {
        /* Should not get here */
    }

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Set Rx Message Buffer 14 mask as the 11-bit standard mask or the 29-bit extended mask.
 */
void FLEXCAN_DRV_SetRxMb14Mask(
    uint8_t instance,
    flexcan_msgbuff_id_type_t id_type,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (id_type == FLEXCAN_MSG_ID_STD)
    {
        /* Set standard global mask for RX MB*/
        FLEXCAN_SetRxMsgBuff14StdMask(base, mask);
    }
    else if (id_type == FLEXCAN_MSG_ID_EXT)
    {
        /* Set extended global mask for RX MB*/
        FLEXCAN_SetRxMsgBuff14ExtMask(base, mask);
    }
    else {
        /* Should not get here */
    }

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Set Rx Message Buffer 15 mask as the 11-bit standard mask or the 29-bit extended mask.
 */
void FLEXCAN_DRV_SetRxMb15Mask(
    uint8_t instance,
    flexcan_msgbuff_id_type_t id_type,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (id_type == FLEXCAN_MSG_ID_STD)
    {
        /* Set standard global mask for RX MB*/
        FLEXCAN_SetRxMsgBuff15StdMask(base, mask);
    }
    else if (id_type == FLEXCAN_MSG_ID_EXT)
    {
        /* Set extended global mask for RX MB*/
        FLEXCAN_SetRxMsgBuff15ExtMask(base, mask);
    }
    else {
        /* Should not get here */
    }

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Set Rx individual mask as the 11-bit standard mask or the 29-bit extended mask.
 */
status_t FLEXCAN_DRV_SetRxIndividualMask(
    uint8_t instance,
    flexcan_msgbuff_id_type_t id_type,
    uint8_t mb_idx,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t ReturnStatus = STATUS_SUCCESS;

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (((uint32_t)mb_idx > FLEXCAN_GetMaxMsgBuffNum(base)) || (mb_idx >= (uint8_t)FEATURE_CAN_RXIMR_COUNT))
    {
        if (freeze == false)
        {
            FLEXCAN_ExitFreezeMode(base);
        }
        else
        {
            /* None */
        }
        ReturnStatus = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        if (false == FLEXCAN_IsRxFifoEnabled(base))
        {
            if (id_type == FLEXCAN_MSG_ID_STD)
            {
                /* Set standard individual mask*/
                FLEXCAN_SetRxIndividualStdMask(base, mb_idx, mask);
            }
            else if (id_type == FLEXCAN_MSG_ID_EXT)
            {
                /* Set extended individual mask*/
                FLEXCAN_SetRxIndividualExtMask(base, mb_idx, mask);
            }
            else
            {
                /* Should not get here */
            }
        }
        else
        {
            if (mb_idx <= FLEXCAN_GetNoOfIndividualMBsRxFIFO(base))
            {
                /* In FIFO Mode get the Id Filter Format already configured by FLEXCAN_DRV_ConfigRxFifo */
                flexcan_rx_fifo_id_element_format_t formatType = FLEXCAN_GetRxFifoIdFormat(base);
                uint32_t calcMask = FLEXCAN_GetRxFifoMask(id_type, formatType, mask);

                switch (formatType)
                {
                    case FLEXCAN_RX_FIFO_ID_FORMAT_A :
                        FLEXCAN_SetRxIndividualMask(base, mb_idx, calcMask);
                        break;
                    case FLEXCAN_RX_FIFO_ID_FORMAT_B :
                        FLEXCAN_SetRxIndividualMask(base, mb_idx, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1)));
                        break;
                    case FLEXCAN_RX_FIFO_ID_FORMAT_C :
                        FLEXCAN_SetRxIndividualMask(base, mb_idx, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1) |
                                                                            (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2) |
                                                                            (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3)));
                        break;
                    default :
                        /* Will Enable all filter fields mask */
                        FLEXCAN_SetRxIndividualMask(base, mb_idx, 0xFFFFFFFFU);
                        break;
                }
            }
            else
            {
                if (id_type == FLEXCAN_MSG_ID_STD)
                {
                    /* Set standard individual mask*/
                    FLEXCAN_SetRxIndividualStdMask(base, mb_idx, mask);
                }
                else if (id_type == FLEXCAN_MSG_ID_EXT)
                {
                    /* Set extended individual mask*/
                    FLEXCAN_SetRxIndividualExtMask(base, mb_idx, mask);
                }
                else
                {
                    /* Should not get here */
                }
            }

        }

        if (freeze == false)
        {
            FLEXCAN_ExitFreezeMode(base);
        }
        else
        {
            /* None */
        }
    }

    return ReturnStatus;
}

/*!
 * @brief Set Raw global mask Value in FIFO mode. Customer must calculate the mask value based on the reference manual.
 */
void FLEXCAN_DRV_SetRawRxFifoGlobalMask(
    uint8_t instance,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (true == FLEXCAN_IsRxFifoEnabled(base))
    {
        FLEXCAN_SetRxFifoGlobalMask(base, mask);
    }
    
    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Set Raw individual mask Value in FIFO mode. Customer must calculate the mask value based on the reference manual.
 */
status_t FLEXCAN_DRV_SetRawRxIndividualMask(
    uint8_t instance,
    uint8_t mb_idx,
    uint32_t mask)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t ReturnStatus = STATUS_SUCCESS;

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (((uint32_t)mb_idx > FLEXCAN_GetMaxMsgBuffNum(base)) || (mb_idx >= (uint8_t)FEATURE_CAN_RXIMR_COUNT))
    {
        ReturnStatus = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        FLEXCAN_SetRxIndividualMask(base, mb_idx, mask);
    }

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }

    return ReturnStatus;
}

/*!
 * @brief Computes the maximum payload size (in bytes), given a DLC field value.
 */
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
static uint8_t FLEXCAN_UseEnhanceRxFifoComputePayloadSize(
    uint8_t dlcValue)
{
    uint8_t ret = 0U;

    if (dlcValue <= 8U)
    {
        ret = dlcValue;
    }
    else
    {
        switch (dlcValue) {
        case CAN_DLC_VALUE_12_BYTES:
            ret = 12U;
            break;
        case CAN_DLC_VALUE_16_BYTES:
            ret = 16U;
            break;
        case CAN_DLC_VALUE_20_BYTES:
            ret = 20U;
            break;
        case CAN_DLC_VALUE_24_BYTES:
            ret = 24U;
            break;
        case CAN_DLC_VALUE_32_BYTES:
            ret = 32U;
            break;
        case CAN_DLC_VALUE_48_BYTES:
            ret = 48U;
            break;
        case CAN_DLC_VALUE_64_BYTES:
            ret = 64U;
            break;
        default:
            /* The argument is not a valid DLC size */
            break;
        }
    }

    return ret;
}
#endif
/*!
 * @brief This function enable FLEXCAN instance Interrupts.
 */
static inline void FLEXCAN_EnableIRQs(uint8_t instance)
{
    uint8_t i;
#if FEATURE_CAN_HAS_WAKE_UP_IRQ
    if (g_flexcanWakeUpIrqId[instance] != NotAvail_IRQn)
    {
        INT_SYS_EnableIRQ(g_flexcanWakeUpIrqId[instance]);
    }
#endif
    INT_SYS_EnableIRQ(g_flexcanErrorIrqId[instance]);
    INT_SYS_EnableIRQ(g_flexcanBusOffIrqId[instance]);
    for (i = 0; i < FEATURE_CAN_MB_IRQS_MAX_COUNT; i++)
    {
        if (g_flexcanOredMessageBufferIrqId[i][instance] != NotAvail_IRQn)
        {
            INT_SYS_EnableIRQ(g_flexcanOredMessageBufferIrqId[i][instance]);
        }
    }
}

#ifdef ERRATA_E10368
#if FEATURE_CAN_HAS_FD
/*!
 * @brief Implements errata 10368. This errata applies to mask 0N78S for MPC5748G CPU.
 */
static inline void FLEXCAN_Errata10368(uint8_t instance,
                                       const flexcan_user_config_t *data)
{
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_time_segment_t bitrate;

    if (data->fd_enable)
    {
        flexcan_msgbuff_code_status_t messageBuff={
                .code = FLEXCAN_TX_REMOTE,
                .msgIdType = FLEXCAN_MSG_ID_STD,
                .dataLen = 1U,
                .fd_enable = false,
                .fd_padding = 0U,
                .enable_brs = false
        };
        uint8_t dummy_data[16];
        /* Enable Self Reception */
        FLEXCAN_SetSelfReception(base, true);

        /* Select Loopback mode */
        FLEXCAN_SetOperationMode(base, FLEXCAN_LOOPBACK_MODE);
        /* Dummy transmission on MB0 */
        (void)FLEXCAN_SetTxMsgBuff(base, 0U, &messageBuff, 0x1U, dummy_data, false);
        FLEXCAN_SetFDEnabled(base, true);
        bitrate = data->bitrate;
        FLEXCAN_SetExtendedTimeSegments(base, &bitrate);
        bitrate = data->bitrate_cbt;
        FLEXCAN_SetFDTimeSegments(base, &bitrate);
        FLEXCAN_ExitFreezeMode(base);
        /* Wait transmission of MB0 to complete */
        while((base->IFLAG1 & CAN_IFLAG1_BUF0I_MASK) != CAN_IFLAG1_BUF0I_MASK) {};
        /* Clear Transmission Complete */
        base->IFLAG1 = CAN_IFLAG1_BUF0I_MASK;
        FLEXCAN_EnterFreezeMode(base);
    }
}
#endif /* FEATURE_CAN_HAS_FD */
#endif /* ERRATA_E10368 */

/*!
 * @brief Initialize FlexCAN driver. This function will select a source clock, reset FlexCAN module, set maximum number of message buffers, initialize all message buffers as inactive, enable RX FIFO if needed, mask all mask bits, disable all MB interrupts, enable FlexCAN normal mode, and enable all the error interrupts if needed.
 */
status_t FLEXCAN_DRV_Init(
   uint8_t instance,
   flexcan_state_t *state,
   const flexcan_user_config_t *data)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(state != NULL);
    DEV_ASSERT(g_flexcanStatePtr[instance] == NULL);

    status_t result = STATUS_SUCCESS;
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_time_segment_t bitrate;
    status_t osifStat;
    uint32_t i, j;

    if(FLEXCAN_IsEnabled(base))
    {
        /* To enter Disable Mode requires FreezMode first */
        FLEXCAN_EnterFreezeMode(base);
        FLEXCAN_Disable(base);
    }

#if FEATURE_CAN_HAS_PE_CLKSRC_SELECT
    /* Select a source clock for the FlexCAN engine */
    FLEXCAN_SelectClock(base, data->pe_clock);
#endif /* FEATURE_CAN_HAS_PE_CLKSRC_SELECT */

    /* Enable the CAN clock */
    FLEXCAN_Enable(base);

    FLEXCAN_EnterFreezeMode(base);

    /* Initialize FLEXCAN device */
    FLEXCAN_Init(base);

#ifdef ERRATA_E10368
#if FEATURE_CAN_HAS_FD
    if (FLEXCAN_InstanceHasFD(instance))
    {
        FLEXCAN_Errata10368(instance, data);
    }
    else
    {
        /* None */
    }
#endif /* FEATURE_CAN_HAS_FD */
#endif /* ERRATA_E10368 */

#if FEATURE_CAN_HAS_FD
    if (FLEXCAN_InstanceHasFD(instance))
    {
        /* Enable/Disable FD and check FD was set as expected. Setting FD as enabled
        * might fail if the current CAN instance does not support FD. */
        FLEXCAN_SetFDEnabled(base, data->fd_enable);
        if (FLEXCAN_IsFDEnabled(base) != data->fd_enable)
        {
            result = STATUS_ERROR;
        }
        else
        {
            /* If the FD feature is enabled, enable the Stuff Bit Count, in order to be
            * ISO-compliant. */
            FLEXCAN_SetStuffBitCount(base, data->fd_enable);
        }
    }
    else if (data->fd_enable)
    {
        /* Return STATUS_ERROR when instance doesn't support FD but fd_enable is set
        * to True by user. */
        result = STATUS_ERROR;
    }
    else
    {
        /* Do Nothing */
    }
#endif

    if(result == STATUS_SUCCESS)
    {   
        /* Disable the self reception feature if FlexCAN is not in loopback mode. */
        if (data->flexcanMode != FLEXCAN_LOOPBACK_MODE)
        {
            FLEXCAN_SetSelfReception(base, false);
        }

        /* Enable RxFIFO feature, if requested. 
        * This might fail if the FD mode is enabled without the Enhance Rx FIFO feature. */
        if (data->is_rx_fifo_needed)
        {
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
            /* Enable enhance rx fifo if enabled */
            if(FLEXCAN_InstanceHasEnhanceRxFIFO(instance) && data->is_enhance_rx_fifo_needed)
            {
                state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
                state->enhanceRxFifoState.isBlocking = false;
                state->enhanceRxFifoState.mb_message = NULL;

                if((data->num_enhance_rx_fifo_filters > 0U) && (data->num_enhance_rx_fifo_filters >= data->num_enhance_rx_fifo_extid_filters))
                {               
                    /* Enable enhance rx fifo,  set the filter num and extended Id filter number */
                    result = FLEXCAN_EnableEnhanceRxFifo(base, data->num_enhance_rx_fifo_filters - 1U, data->num_enhance_rx_fifo_extid_filters);
                }
                else
                {
                    result = STATUS_ERROR;
                }

                if(result != STATUS_ERROR)
                {
                    if(data->num_enhance_rx_fifo_min_messages > 0U)
                    {
                        /* Set enhance fifo water mark */
                        result = FLEXCAN_SetEnhanceRxFifoWatermark(base, data->num_enhance_rx_fifo_min_messages - 1U);
                    }
                    else
                    {
                        result = STATUS_ERROR;
                    }
                }
                else
                {
                    /* None */
                }
            }
            else
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
            {
                result = FLEXCAN_EnableRxFifo(base, (uint32_t)data->num_id_filters);
            }
        }
    }
    else
    {
        /* None */
    }

    if (result != STATUS_SUCCESS)  /* PRQA S 2992 */  /* PRQA S 2996 */
    {
        result = STATUS_ERROR;
    }   

    if(result == STATUS_SUCCESS)
    {
#if FEATURE_CAN_HAS_DMA_ENABLE
        if (data->transfer_type == FLEXCAN_RXFIFO_USING_DMA)
        {
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
            if(FLEXCAN_InstanceHasEnhanceRxFIFO(instance) && data->is_enhance_rx_fifo_needed)  
            {
                if(FLEXCAN_IsEnhanceRxFifoEnabled(base))
                {
                    FLEXCAN_SetRxFifoDMA(base, true);
                    FLEXCAN_SetEnhanceRxFifoDMALastWord(base, data->rxFifoDMALastWord);
                }
                else
                {
                    result = STATUS_ERROR;
                }
            }
            else      
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
            {
                if(FLEXCAN_IsRxFifoEnabled(base))
                {
                    FLEXCAN_SetRxFifoDMA(base, true);
                }
                else
                {
                    result = STATUS_ERROR;
                }            
            }        
        }
        else
        {
            FLEXCAN_SetRxFifoDMA(base, false);
        }
    }
#endif /* FEATURE_CAN_HAS_DMA_ENABLE */

    if(result == STATUS_SUCCESS)
    {
#if FEATURE_CAN_HAS_FD
        /* Set payload size. */
        FLEXCAN_SetPayloadSize(base, data->payload);
#endif
        result = FLEXCAN_SetMaxMsgBuffNum(base, data->max_num_mb);
        if (result != STATUS_SUCCESS)
        {
            result = result;
        }
        else
        {
            /* else */
        }
    }

    if(result == STATUS_SUCCESS)
    {
#if FEATURE_CAN_HAS_FD
        /* Set bit rate. */
        if (FLEXCAN_IsFDEnabled(base))
        {
            bitrate = data->bitrate;
            FLEXCAN_SetExtendedTimeSegments(base, &bitrate);
            bitrate = data->bitrate_cbt;
            FLEXCAN_SetFDTimeSegments(base, &bitrate);
        }
        else
#endif
        {
            bitrate = data->bitrate;
            FLEXCAN_SetTimeSegments(base, &bitrate);
        }

        /* Select mode */
        FLEXCAN_SetOperationMode(base, data->flexcanMode);

        if (data->flexcanMode != FLEXCAN_FREEZE_MODE)
        {
            FLEXCAN_ExitFreezeMode(base);
        }
        else
        {
            /* None */
        }

        state->max_num_mb = data->max_num_mb;
        for (i = 0; i < data->max_num_mb; i++)
        {
            osifStat = OSIF_SemaCreate(&state->mbs[i].mbSema, 0U);
            if (osifStat != STATUS_SUCCESS)
            {
                for (j = 0; j < i; j++)
                {
                    (void)OSIF_SemaDestroy(&state->mbs[j].mbSema);
                }
                result = STATUS_ERROR;
            }
            else
            {
                state->mbs[i].isBlocking = false;
                state->mbs[i].mb_message = NULL;
                state->mbs[i].state = FLEXCAN_MB_IDLE;
            }
        }
    }

    if(result == STATUS_SUCCESS)
    {
        /* Store transfer type and DMA channel number used in transfer */
        state->transferType = data->transfer_type;
#if FEATURE_CAN_HAS_DMA_ENABLE
        state->rxFifoDMAChannel = data->rxFifoDMAChannel;
#endif

        /* Clear Callbacks in case of autovariables garbage */
        state->callback = NULL;
        state->callbackParam = NULL;
        state->error_callback = NULL;
        state->errorCallbackParam = NULL;

        /* Save runtime structure pointers so irq handler can point to the correct state structure */
        g_flexcanStatePtr[instance] = state;

        /* Enable FlexCAN interrupts.*/
        FLEXCAN_EnableIRQs(instance);
    }            
    
    return result;
}

/*!
 * @brief Configure a Tx message buffer. This function will first check if RX FIFO is enabled. If RX FIFO is enabled, the function will make sure if the MB requested is not occupied by RX FIFO and ID filter table. Then this function will set up the message buffer fields, configure the message buffer code for Tx buffer as INACTIVE, and enable the Message Buffer interrupt.
 */
status_t FLEXCAN_DRV_ConfigTxMb(
    uint8_t instance,
    uint8_t mb_idx,
    const flexcan_data_info_t *tx_info,
    uint32_t msg_id)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(tx_info != NULL);
    
    status_t result = STATUS_SUCCESS;

    flexcan_msgbuff_code_status_t cs;
    CAN_Type * base = g_flexcanBase[instance];

    /* Check if the MB index is in range */
    if (FLEXCAN_IsOutOfRangeMbIdx(base, mb_idx))
    {
        result = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        /* Initialize transmit mb*/
        cs.dataLen = tx_info->data_length;
        cs.msgIdType = tx_info->msg_id_type;
#if FEATURE_CAN_HAS_FD
        cs.enable_brs = tx_info->enable_brs;
        cs.fd_enable = tx_info->fd_enable;
        cs.fd_padding = tx_info->fd_padding;
#endif
        cs.code = (uint32_t)FLEXCAN_TX_INACTIVE;
        result = FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, NULL, false);
    }
    return result;
}
/*!
 * @brief Configures a transmit message buffer for remote frame response. This function will first check if RX FIFO is enabled. If RX FIFO is enabled, the function will make sure if the MB requested is not occupied by the RX FIFO and ID filter table. Then this function will set up the message buffer fields, configure the message buffer code for Tx buffer as RX_RANSWER, and enable the Message Buffer interrupt.
 */
status_t FLEXCAN_DRV_ConfigRemoteResponseMb(
    uint8_t instance,
    uint8_t mb_idx,
    const flexcan_data_info_t *tx_info,
    uint32_t msg_id,
    const uint8_t *mb_data)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(tx_info != NULL);

    status_t result = STATUS_SUCCESS;

    flexcan_msgbuff_code_status_t cs;
    CAN_Type * base = g_flexcanBase[instance];

    if (mb_idx > (((base->MCR) & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT))
    {
        result =  STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        /* Initialize transmit mb*/
        cs.dataLen = tx_info->data_length;
        cs.msgIdType = tx_info->msg_id_type;
        cs.code = (uint32_t)FLEXCAN_RX_RANSWER;

        FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

        result =  FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, mb_data, tx_info->is_remote);
    }

    return result;
}

/*!
 * @brief This function sends a CAN frame using a configured message buffer. The function blocks until either the frame was sent, or the specified timeout expired.
 */
status_t FLEXCAN_DRV_SendBlocking(
    uint8_t instance,
    uint8_t mb_idx,
    const flexcan_data_info_t *tx_info,
    uint32_t msg_id,
    const uint8_t *mb_data,
    uint32_t timeout_ms)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(tx_info != NULL);

    status_t result= STATUS_SUCCESS;
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    CAN_Type * base  = g_flexcanBase[instance];

    /* Check if the MB index is in range */
    if (FLEXCAN_IsOutOfRangeMbIdx(base, mb_idx))
    {
        result =  STATUS_CAN_BUFF_OUT_OF_RANGE;
    }

    if(result != STATUS_CAN_BUFF_OUT_OF_RANGE)
    {
        result = FLEXCAN_StartSendData(instance, mb_idx, tx_info, msg_id, mb_data, true);

        if (result == STATUS_SUCCESS)
        {
            status_t status;

            /* Enable message buffer interrupt*/
            (void)FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, true);

            status = OSIF_SemaWait(&state->mbs[mb_idx].mbSema, timeout_ms);

            /* Disable message buffer interrupt */
            (void)FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, false);

            if (status == STATUS_TIMEOUT)
            {
                if (state->mbs[mb_idx].state != FLEXCAN_MB_IDLE)
                {
                    /* Clear message buffer flag */
                    FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
                    FLEXCAN_AbortTxMsgBuff(base, mb_idx);
                    uint32_t flexcan_mb_config;

    #ifndef ERRATA_E9527
                    /* Wait to finish abort operation */
                    while(FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U)
                    {
                        /* Do Nothing wait for the flag */
                    }
    #endif
                    volatile const uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, mb_idx);
                    flexcan_mb_config = * flexcan_mb;
                    /* Check if the MBs have been safely Inactivated */
                    if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT) == (uint32_t)FLEXCAN_TX_INACTIVE)
                    {
    #ifndef ERRATA_E9527
                        /* Transmission have occurred */
                        result = STATUS_SUCCESS;
    #else
                        /* Transmission have not occurred because it uses the inactivation operation */
                        if (FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U)
                        {
                            result = STATUS_TIMEOUT;
                        }
                        else
                        {
                            result = STATUS_SUCCESS;
                        }
    #endif
                    }
                    if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT) == (uint32_t)FLEXCAN_TX_ABORT)
                    {
                        /* Transmission have been aborted */
                        result = STATUS_TIMEOUT;
                    }
                    /* Clear message buffer flag */
                    FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
                    state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
                }
                else
                {
                    /* Transmission have occurred */
                    result = STATUS_SUCCESS;
                    /* add dummy wait for reset state->mbs[mb_idx].mbSema at beginning of block functions */
                    (void) OSIF_SemaWait(&state->mbs[mb_idx].mbSema, 0);
                }
            }
        }
    }
    return result;
}

/*!
 * @brief This function sends a CAN frame using a configured message buffer. The function returns immediately. If a callback is installed, it will be invoked after the frame was sent.
 */
status_t FLEXCAN_DRV_Send(
    uint8_t instance,
    uint8_t mb_idx,
    const flexcan_data_info_t *tx_info,
    uint32_t msg_id,
    const uint8_t *mb_data)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(tx_info != NULL);

    status_t result;
    CAN_Type * base = g_flexcanBase[instance];

    /* Check if the MB index is in range */
    if (FLEXCAN_IsOutOfRangeMbIdx(base, mb_idx))
    {
        result = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        result = FLEXCAN_StartSendData(instance, mb_idx, tx_info, msg_id, mb_data, false);
        if(result == STATUS_SUCCESS)
        {
            /* Enable message buffer interrupt*/
            result = FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, true);
        }
    }
    return result;
}

/*!
 * @brief Configure a Rx message buffer. This function will first check if RX FIFO is enabled. If RX FIFO is enabled, the function will make sure if the MB requested is not occupied by RX FIFO and ID filter table. Then this function will set up the message buffer fields, configure the message buffer code for Rx message buffer as NOT_USED, enable the Message Buffer interrupt, configure the message buffer code for Rx message buffer as INACTIVE, copy user's buffer into the message buffer data area, and configure the message buffer code for Rx message buffer as EMPTY.
 */
status_t FLEXCAN_DRV_ConfigRxMb(
    uint8_t instance,
    uint8_t mb_idx,
    const flexcan_data_info_t *rx_info,
    uint32_t msg_id)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(rx_info != NULL);

    status_t result = STATUS_SUCCESS;
    flexcan_msgbuff_code_status_t cs;
    CAN_Type * base = g_flexcanBase[instance];

    /* Check if the MB index is in range */
    if (FLEXCAN_IsOutOfRangeMbIdx(base, mb_idx))
    {
        result =  STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        cs.dataLen = rx_info->data_length;
        cs.msgIdType = rx_info->msg_id_type;
#if FEATURE_CAN_HAS_FD
        cs.fd_enable = rx_info->fd_enable;
#endif
        /* Clear the message buffer flag if previous remained triggered*/
        FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

        /* Initialize rx mb*/
        cs.code = (uint32_t)FLEXCAN_RX_NOT_USED;
        result = FLEXCAN_SetRxMsgBuff(base, mb_idx, &cs, msg_id);

        if (result == STATUS_SUCCESS)
        {
            /* Initialize receive MB*/
            cs.code = (uint32_t)FLEXCAN_RX_INACTIVE;
            result = FLEXCAN_SetRxMsgBuff(base, mb_idx, &cs, msg_id);
        }

        if (result == STATUS_SUCCESS)
        {
            /* Set up FlexCAN message buffer fields for receiving data*/
            cs.code = (uint32_t)FLEXCAN_RX_EMPTY;
            result = FLEXCAN_SetRxMsgBuff(base, mb_idx, &cs, msg_id);
        }

        if (result == STATUS_SUCCESS)
        {
            /* Clear the message buffer flag if previous remained triggered*/
            FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
        }
    }
    return result;
}

/*!
 * @brief Configure RX FIFO ID filter table elements. This function will configure RX FIFO ID filter table elements, and enable RX FIFO interrupts.
 */
void FLEXCAN_DRV_ConfigRxFifo(
    uint8_t instance,
    flexcan_rx_fifo_id_element_format_t id_format,
    const flexcan_id_table_t *id_filter_table)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    /* Initialize rx fifo*/
    FLEXCAN_SetRxFifoFilter(base, id_format, id_filter_table);

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
/*!
 * @brief Configure enhanced RX FIFO ID filter table elements. This function will configure enhanced RX FIFO ID filter table elements, and enable RX FIFO interrupts.
 */
void FLEXCAN_DRV_ConfigEnhanceRxFifo(
    uint8_t instance,
    const flexcan_enhance_rx_fifo_filter_table_t *id_filter_table,
    uint8_t id_filter_table_length)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    /* Initialize rx fifo*/
    FLEXCAN_SetEnchanceRxFifoFilter(base, id_filter_table,id_filter_table_length);

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }    
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

/*!
 * @brief This function receives a CAN frame into a configured message buffer. The function blocks until either a frame was received, or the specified timeout expired.
 */
status_t FLEXCAN_DRV_ReceiveBlocking(
    uint8_t instance,
    uint8_t mb_idx,
    flexcan_msgbuff_t *data,
    uint32_t timeout_ms)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result = STATUS_SUCCESS;
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    CAN_Type * base = g_flexcanBase[instance];

    /* Check if the MB index is in range */
    if (FLEXCAN_IsOutOfRangeMbIdx(base, mb_idx))
    {
        result = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        result = FLEXCAN_StartRxMessageBufferData(instance, mb_idx, data, true);

        if(result == STATUS_SUCCESS)
        {
            status_t status;

            status = OSIF_SemaWait(&state->mbs[mb_idx].mbSema, timeout_ms);

            /* Disable message buffer interrupt */
            (void)FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, false);

            if (status == STATUS_TIMEOUT)
            {
                /* Consider the MB state has been changed by interrupt as frame received */
                if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE)
                {
                    /* add dummy wait for reset state->mbs[mb_idx].mbSema at beginning of block functions */
                    (void) OSIF_SemaWait(&state->mbs[mb_idx].mbSema, 0);

                    result = STATUS_SUCCESS;
                }
                else
                {
                    result = STATUS_TIMEOUT;
                    state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
                }
            }
        }
    }
    return result;
}

/*!
 * @brief This function receives a CAN frame into a configured message buffer. The function returns immediately. If a callback is installed, it will be invoked after the frame was received and read into the specified buffer.
 */
status_t FLEXCAN_DRV_Receive(
    uint8_t instance,
    uint8_t mb_idx,
    flexcan_msgbuff_t *data)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    const CAN_Type * base = g_flexcanBase[instance];

    status_t result = STATUS_SUCCESS;

    /* Check if the MB index is in range */
    if (FLEXCAN_IsOutOfRangeMbIdx(base, mb_idx))
    {
        result = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        result = FLEXCAN_StartRxMessageBufferData(instance, mb_idx, data, false);
    }
    return result;
}

/*!
 * @brief This function receives a CAN frame using the Rx FIFO. The function blocks until either a frame was received, or the specified timeout expired.
 */
status_t FLEXCAN_DRV_RxFifoBlocking(
    uint8_t instance,
    flexcan_msgbuff_t *data,
    uint32_t timeout_ms)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result;
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    CAN_Type * base = g_flexcanBase[instance];

    result = FLEXCAN_StartRxMessageFifoData(instance, data, true);

    if (result == STATUS_SUCCESS)
    {
        result = OSIF_SemaWait(&state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mbSema, timeout_ms);

        if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS)
        {
            /* Disable RX FIFO interrupts*/
            (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, false);
            (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_WARNING, false);
            (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_OVERFLOW, false);
        }
#if FEATURE_CAN_HAS_DMA_ENABLE
        else
        {
            /* This function always return status success */
            (void)DMA_DRV_StopChannel(state->rxFifoDMAChannel);
        }
#endif

#if FEATURE_CAN_HAS_DMA_ENABLE
        if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_DMA_ERROR)
        {
            result = STATUS_ERROR;
            state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
        }
        else
#endif
        if (result == STATUS_TIMEOUT)
        {
             /* If the status is updated reception successful else report TimeOut */
            if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_IDLE)
            {
                result = STATUS_SUCCESS;
                /* add dummy wait for reset state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mbSema at beginning of block functions */
                (void) OSIF_SemaWait(&state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mbSema, 0);
            }
            else
            {
                state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
            }
        }
    }

    return result;
}

/*!
 * @brief This function receives a CAN frame using the Rx FIFO. The function returns immediately. If a callback is installed, it will be invoked after the frame was received and read into the specified buffer.
 */
status_t FLEXCAN_DRV_RxFifo(
    uint8_t instance,
    flexcan_msgbuff_t *data)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result;

    result = FLEXCAN_StartRxMessageFifoData(instance, data, false);

    return result;
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
/*!
 * @brief This function receives a CAN frame using the enhcanded Rx FIFO. The function returns immediately. If a callback is installed, it will be invoked after the frame was received and read into the specified buffer.
 */
status_t FLEXCAN_DRV_EnhanceRxFifo(
    uint8_t instance,
    flexcan_msgbuff_t *data)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result;

    result = FLEXCAN_StartRxMessageEnhanceFifoData(instance, data, false);

    return result;
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */


/*!
 * @brief Shutdown a FlexCAN module. This function will disable all FlexCAN interrupts, and disable the FlexCAN.
 */
status_t FLEXCAN_DRV_Deinit(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    const flexcan_state_t * state = g_flexcanStatePtr[instance];
    status_t result = STATUS_SUCCESS;
    status_t osifStat;
    uint32_t i;

    /* Disable FlexCAN interrupts.*/
    if (state != NULL)
    {
        if (state->error_callback != NULL)
        {
            FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_ERR, false);
            FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_RX_WARNING, false);
            FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_TX_WARNING, false);
            FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_BUSOFF, false);
        }
    }

#if FEATURE_CAN_HAS_WAKE_UP_IRQ
    if (g_flexcanWakeUpIrqId[instance] != NotAvail_IRQn)
    {
        INT_SYS_DisableIRQ(g_flexcanWakeUpIrqId[instance]);
    }
#endif
    INT_SYS_DisableIRQ(g_flexcanErrorIrqId[instance]);
    INT_SYS_DisableIRQ(g_flexcanBusOffIrqId[instance]);
    for (i = 0; i < FEATURE_CAN_MB_IRQS_MAX_COUNT; i++)
    {
        if (g_flexcanOredMessageBufferIrqId[i][instance] != NotAvail_IRQn)
        {
            INT_SYS_DisableIRQ(g_flexcanOredMessageBufferIrqId[i][instance]);
        }
    }

    if(FLEXCAN_IsEnabled(g_flexcanBase[instance]))
    {
        /* Enter Freeze Mode Required before to enter Disabled Mode */
        FLEXCAN_EnterFreezeMode(g_flexcanBase[instance]);
        /* Disable FlexCAN.*/
        FLEXCAN_Disable(g_flexcanBase[instance]);
        /* Check if the state have been initialized */
    }

    if (state != NULL)
    {
        for (i = 0; i < state->max_num_mb; i++)
        {
            osifStat = OSIF_SemaDestroy(&state->mbs[i].mbSema);
            if (osifStat != STATUS_SUCCESS)
            {
                result = STATUS_ERROR;
            }
        }
    }

    if (result == STATUS_SUCCESS)
    {
        /* Clear state pointer that is checked by FLEXCAN_DRV_Init */
        g_flexcanStatePtr[instance] = NULL;
    }

    return result;
}

#if FEATURE_CAN_HAS_FD
/*!
 * @brief Enables/Disables the Transceiver Delay Compensation feature and sets the Transceiver Delay Compensation Offset.
 */
void FLEXCAN_DRV_SetTDCOffset(uint8_t instance, bool enable, uint8_t offset)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    /* Enable/Disable TDC and set the TDC Offset */
    FLEXCAN_SetTDCOffset(base, enable, offset);

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Gets the value of the Transceiver Delay Compensation.
 */
uint8_t FLEXCAN_DRV_GetTDCValue(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    uint8_t result = 0U;

    const CAN_Type * base = g_flexcanBase[instance];
#if defined (CAN_CTRL2_BTE_MASK)
    result = (uint8_t)((base->ETDC & CAN_ETDC_ETDCVAL_MASK) >> CAN_ETDC_ETDCVAL_SHIFT);
#else
    result = (uint8_t)((base->FDCTRL & CAN_FDCTRL_TDCVAL_MASK) >> CAN_FDCTRL_TDCVAL_SHIFT);
#endif
    return result;
}

/*!
 * @brief Gets the value of the TDC Fail flag.
 */
bool FLEXCAN_DRV_GetTDCFail(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    bool result = false;

    const CAN_Type * base = g_flexcanBase[instance];
#if defined (CAN_CTRL2_BTE_MASK)
    result = (((base->ETDC & CAN_ETDC_ETDCFAIL_MASK) >> CAN_ETDC_ETDCFAIL_SHIFT) != 0u);
#else
    result =  (((base->FDCTRL & CAN_FDCTRL_TDCFAIL_MASK) >> CAN_FDCTRL_TDCFAIL_SHIFT) != 0U);
#endif
    return result;
}

/*!
 * @brief Clears the TDC Fail flag.
 */
void FLEXCAN_DRV_ClearTDCFail(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
#if defined (CAN_CTRL2_BTE_MASK)
    base->ETDC = base->ETDC | CAN_ETDC_ETDCFAIL_MASK;
#else
    base->FDCTRL = base->FDCTRL | CAN_FDCTRL_TDCFAIL_MASK;
#endif
}
#endif

/*!
 * @brief Process IRQHandler in case of RxFIFO mode selection for CAN interface.
 */
static inline void FLEXCAN_IRQHandlerRxFIFO(uint8_t instance, uint32_t mb_idx)
{
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    if (mb_idx == FEATURE_CAN_RXFIFO_FRAME_AVAILABLE)
    {
        if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_RX_BUSY)
        {
            /* Get RX FIFO field values */
            FLEXCAN_ReadRxFifo(base, state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message);

            FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

            state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;

            /* Invoke callback */
            if (state->callback != NULL)
            {
                state->callback(instance,
                                FLEXCAN_EVENT_RXFIFO_COMPLETE,
                                FLEXCAN_MB_HANDLE_RXFIFO,
                                state);
            }

            if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_IDLE)
            {
                /* Complete receive data */
                FLEXCAN_CompleteRxMessageFifoData(instance);
            }
        }
    }
    else if (mb_idx == FEATURE_CAN_RXFIFO_WARNING)
    {
        FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

        /* Invoke callback */
        if (state->callback != NULL)
        {
            state->callback(instance,
                            FLEXCAN_EVENT_RXFIFO_WARNING,
                            FLEXCAN_MB_HANDLE_RXFIFO,
                            state);
        }
    }
    else if (mb_idx == FEATURE_CAN_RXFIFO_OVERFLOW)
    {
        FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

        /* Invoke callback */
        if (state->callback != NULL)
        {
            state->callback(instance,
                            FLEXCAN_EVENT_RXFIFO_OVERFLOW,
                            FLEXCAN_MB_HANDLE_RXFIFO,
                            state);
        }
    }
    else
    {
        /* Do Nothing */
    }

}

/*!
 * @brief Process IRQHandler in case of Rx MessageBuffer selection for CAN interface.
 */
static void FLEXCAN_IRQHandlerRxMB(uint8_t instance, uint32_t mb_idx)
{
     CAN_Type * base = g_flexcanBase[instance];
     flexcan_state_t * state = g_flexcanStatePtr[instance];

     /* Lock RX message buffer and RX FIFO*/
     FLEXCAN_LockRxMsgBuff(base, mb_idx);

     /* Get RX MB field values*/
     FLEXCAN_GetMsgBuff(base, mb_idx, state->mbs[mb_idx].mb_message);

    /* Clear the proper flag in the IFLAG register */
    FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
    /* the CODE field is updated with an incorrect value when MBx is locked by software for more than 20 CAN bit times and FIFO enable */
    if ((FLEXCAN_IsRxFifoEnabled(base)) && (((state->mbs[mb_idx].mb_message->cs & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT) == (uint32_t)FLEXCAN_RX_INACTIVE))
    {
        /* Update the cs code for next sequence move in MB.
        A CPU write into the C/S word also unlocks the MB */
        volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, mb_idx);
        *flexcan_mb &= ~CAN_CS_CODE_MASK;
        *flexcan_mb |= (((uint32_t)FLEXCAN_RX_EMPTY) << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;
    }
    else
    {
        /* Unlock RX message buffer and RX FIFO*/
        FLEXCAN_UnlockRxMsgBuff(base);
    }

     state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;

     /* Invoke callback */
     if (state->callback != NULL)
     {
         state->callback(instance, FLEXCAN_EVENT_RX_COMPLETE, mb_idx, state);
     }

     if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE)
     {
         /* Complete receive data */
         FLEXCAN_CompleteTransfer(instance, mb_idx);
     }
}

/*!
 * @brief BusOff and Tx/Rx Warning interrupt handler for FLEXCAN. This handler only provides a error status report and invokes the user callback, and then clears the interrupt flags. This is not a public API as it is called whenever an interrupt occurs.
 */
void FLEXCAN_ORed_IRQHandler(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    /* Invoke callback */
    if (state->error_callback != NULL)
    {
        if ((base->ESR1 & CAN_ESR1_BOFFDONEINT_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_BUS_OFF_DONE_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_TXWRN_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_TX_WARNING_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_RXWRN_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_RX_WARNING_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_BOFFINT_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_BUS_OFF_ENTER_EVENT, state);
        }
    }

    /* Clear all BusOff and Tx/Rx Warning interrupts in ESR1 register */
    FLEXCAN_ClearBusOffIntStatusFlag(base);
}

/*!
 * @brief Interrupt handler for FLEXCAN. This handler read data from MB or FIFO, and then clear the interrupt flags. This is not a public API as it is called whenever an interrupt occurs.
 */
void FLEXCAN_IRQHandler(uint8_t instance, uint8_t mb_idx_start, uint8_t mb_idx_end)  /* PRQA S 4700 */
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    uint32_t flag_reg = 0;
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
    bool instanceHasEnhanceRxFIFO = false;
    bool isEnhanceRxFifoEnabled = false;
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
    /* Get the interrupts that are enabled and ready */
    uint32_t mb_idx;
    for (mb_idx = mb_idx_start; mb_idx <=mb_idx_end; mb_idx++)
    {
        flag_reg = FLEXCAN_GetMsgBuffIntStatusFlag(base, mb_idx);
        if((flag_reg & (uint32_t)1)== (uint32_t)1)
        {
            break;
        }
    }

    /* Check Tx/Rx interrupt flag and clear the interrupt */
    if(flag_reg != 0U)
    {
        if (FLEXCAN_IsRxFifoEnabled(base) && (mb_idx <= FEATURE_CAN_RXFIFO_OVERFLOW))
        {
            FLEXCAN_IRQHandlerRxFIFO(instance, mb_idx);
        }
        else
        {
            /* Check mailbox completed reception */
            if (state->mbs[mb_idx].state == FLEXCAN_MB_RX_BUSY)
            {
                FLEXCAN_IRQHandlerRxMB(instance, mb_idx);
            }
        }

        /* Check mailbox completed transmission */
        if (state->mbs[mb_idx].state == FLEXCAN_MB_TX_BUSY)
        {
            if (state->mbs[mb_idx].isRemote)
            {
                /* If the frame was a remote frame, clear the flag only if the response was
                 * not received yet. If the response was received, leave the flag set in order
                 * to be handled when the user calls FLEXCAN_DRV_RxMessageBuffer. */
                flexcan_msgbuff_t mb;
                FLEXCAN_LockRxMsgBuff(base, mb_idx);
                FLEXCAN_GetMsgBuff(base, mb_idx, &mb);
                FLEXCAN_UnlockRxMsgBuff(base);

                if (((mb.cs & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT) == (uint32_t)FLEXCAN_RX_EMPTY)
                {
                    FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
                }
            }
            else
            {
                FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
            }

            state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;

            /* Invoke callback */
            if (state->callback != NULL)
            {
                state->callback(instance, FLEXCAN_EVENT_TX_COMPLETE, mb_idx, state);
            }

            if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE)
            {
                /* Complete transmit data */
                FLEXCAN_CompleteTransfer(instance, mb_idx);
            }
        }

        if (FLEXCAN_GetMsgBuffIntStatusFlag(base, mb_idx) != 0U)
        {
            if (FLEXCAN_IsRxFifoEnabled(base) && (mb_idx <= FEATURE_CAN_RXFIFO_OVERFLOW))
            {
                if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_IDLE)
                {
                /* In case of desynchronized status of the MB to avoid trapping in ISR
                 * clear the MB flag */
                FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
                }
            }
            else
            {
                if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE)
                {
                    /* In case of desynchronized status of the MB to avoid trapping in ISR
                     * clear the MB flag */
                    FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
                }
            }
        }
    }
    else
    {
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
        instanceHasEnhanceRxFIFO = FLEXCAN_InstanceHasEnhanceRxFIFO(instance);
        if(instanceHasEnhanceRxFIFO)
        {
            isEnhanceRxFifoEnabled = FLEXCAN_IsEnhanceRxFifoEnabled(base);

            /* Check enhance fifo interrups if instance has enhance fifo feature and enabled */
            if(isEnhanceRxFifoEnabled)
            {
                uint8_t enhanceRxFifoAvailbale = FLEXCAN_GetEnhanceRxFIFODataAvailableStatusFlag(base);
                uint8_t enhanceRxFifoOverflow = FLEXCAN_GetEnhanceRxFIFOOverflowStatusFlag(base);
                uint8_t enhanceRxFifoWatermark = FLEXCAN_GetEnhanceRxFIFOWatermarkIndStatusFlag(base);
                if ((enhanceRxFifoOverflow != 0U) || (enhanceRxFifoWatermark != 0U) || (enhanceRxFifoAvailbale != 0U))
                {
                    FLEXCAN_EnhanceRxFifo_IRQHandler(instance);
                }
            }
        }
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

#if FEATURE_CAN_HAS_PRETENDED_NETWORKING    
        /* The pretending Network Feature is present on all CPUs
         * only on FLEXCAN Instance 0 - inly for YTM32B1L */
        if (instance == 0U)
        {
            uint8_t wtof = FLEXCAN_GetWTOF(base);
            uint8_t wumf = FLEXCAN_GetWUMF(base);

            /* Check if wake-up event occurred */
            if ((wtof != 0U) || (wumf != 0U))
            {
                FLEXCAN_WakeUpHandler(instance);
            }
        }
#endif /* FEATURE_CAN_HAS_PRETENDED_NETWORKING */

    }
    return;
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
void FLEXCAN_EnhanceRxFifo_IRQHandler(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    if((FLEXCAN_GetEnhanceRxFIFODataAvailableStatusFlag(base)) != 0U)
    {
        if(state->enhanceRxFifoState.state == FLEXCAN_MB_RX_BUSY)
        {
            FLEXCAN_ReadEnhanceRxFifo(base, state->enhanceRxFifoState.mb_message);
            FLEXCAN_ClearEnhanceRxFIFODataAvailableStatusFlag(base);

            if((FLEXCAN_GetEnhanceRxFIFODataAvailableStatusFlag(base)) == 0U){
                state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
            }           
            /* Invoke callback */
            if (state->callback != NULL)
            {
                state->callback(instance,
                                FLEXCAN_EVENT_ENHANCE_RXFIFO_AVAILABLEDATA,
                                FLEXCAN_MB_HANDLE_ENHANCE_RXFIFO,
                                state);
            }

            if (state->enhanceRxFifoState.state == FLEXCAN_MB_IDLE)
            {
                /* Complete receive data */
                FLEXCAN_CompleteRxMessageEnhanceFifoData(instance);
            }       
        }
    }
    if((FLEXCAN_GetEnhanceRxFIFOOverflowStatusFlag(base)) != 0U)
    {
        FLEXCAN_ClearEnhanceRxFIFOOverflowStatusFlag(base);
        /* Invoke callback */
        if (state->callback != NULL)
        {
            state->callback(instance,
                            FLEXCAN_EVENT_ENHANCE_RXFIFO_OVERFLOW,
                            FLEXCAN_MB_HANDLE_ENHANCE_RXFIFO,
                            state);
        }
    }
    if((FLEXCAN_GetEnhanceRxFIFOWatermarkIndStatusFlag(base)) != 0U)
    {
        FLEXCAN_ClearEnhanceRxFIFOWatermarkIndStatusFlag(base);
        /* Invoke callback */
        if (state->callback != NULL)
        {
            state->callback(instance,
                            FLEXCAN_EVENT_ENHANCE_RXFIFO_WATERMARK,
                            FLEXCAN_MB_HANDLE_ENHANCE_RXFIFO,
                            state);
        }
    }
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */


/*!
 * @brief Error interrupt handler for FLEXCAN. This handler read data from MB or FIFO, and then clear the interrupt flags. This is not a public API as it is called whenever an interrupt occurs.
 */
void FLEXCAN_Error_IRQHandler(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    /* Invoke callback */
    if (state->error_callback != NULL)
    {
        if ((base->ESR1 & CAN_ESR1_ERROVR_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_ERROR_OVERRUN_EVENT, state);
        }
#if FEATURE_CAN_HAS_FD
        if ((base->ESR1 & CAN_ESR1_ERRINT_FAST_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_FD_DATA_BIT_ERROR_EVENT, state);
        }
#endif
#if (defined (YTM32B1L_SERIES))    
        if ((base->ESR1 & CAN_ESR1_BOFFDONEINT_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_BUS_OFF_DONE_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_TXWRN_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_TX_WARNING_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_RXWRN_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_RX_WARNING_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_BOFFINT_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_BUS_OFF_ENTER_EVENT, state);
        }
#endif
        if ((base->ESR1 & CAN_ESR1_ERRINT_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_BIT_ERROR_EVENT, state);
        }
        if ((base->ESR1 & CAN_ESR1_WAKINT_MASK)!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_WAKEUP_EVENT, state);
        }
#if FEATURE_CAN_HAS_RAM_ECC
        if ((base->ERRSR & (CAN_ERRSR_FANCEIF_MASK | CAN_ERRSR_HANCEIF_MASK))!= (uint32_t)0)
        {
            state->error_callback(instance, FLEXCAN_RAM_ECC_ERROR_EVENT, state);
        }
#endif
    }

    /* Clear all other interrupts in ESR1 register (Error, Wakeup) */
    FLEXCAN_ClearErrIntStatusFlag(base);
}

#if FEATURE_CAN_HAS_WAKE_UP_IRQ
#if FEATURE_CAN_HAS_SELF_WAKE_UP
/*!
 * @brief Enable self wake up
 */
void FLEXCAN_DRV_EnableSelfWakeUp(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

     (void)FLEXCAN_SetSelfWakeUp(base,true);
}

/*!
 * @brief Disable self wake up
 */
void FLEXCAN_DRV_DisableSelfWakeUp(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

     (void)FLEXCAN_SetSelfWakeUp(base,false);
}
#endif

/*!
 * @brief Wake up handler for FLEXCAN. This handler verifies the event which caused the wake up and invokes the user callback, if configured. This is not a public API as it is called whenever an wake up event occurs.
 */
void FLEXCAN_WakeUpHandler(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    (void)instance;

#if FEATURE_CAN_HAS_PRETENDED_NETWORKING
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];
        if (FLEXCAN_IsPNEnabled(base))
        {
            if (FLEXCAN_GetWTOF(base) != 0U)
            {
                FLEXCAN_ClearWTOF(base);
                /* Invoke callback */
                if (state->callback != NULL)
                {
                    state->callback(instance, FLEXCAN_EVENT_WAKEUP_TIMEOUT, 0U, state);
                }
            }
            if (FLEXCAN_GetWUMF(base) != 0U)
            {
                FLEXCAN_ClearWUMF(base);
                /* Invoke callback */
                if (state->callback != NULL)
                {
                    state->callback(instance, FLEXCAN_EVENT_WAKEUP_MATCH, 0U, state);
                }
            }
        }
#elif FEATURE_CAN_HAS_SELF_WAKE_UP
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    if(FLEXCAN_GetWAKINT(base) != 0U)
    {
        FLEXCAN_ClearWAKINT(base);
        if (state->callback != NULL)
        {
            state->callback(instance, FLEXCAN_EVENT_SELF_WAKEUP, 0U, state);
        }
    }
#endif /* FEATURE_CAN_HAS_SELF_WAKE_UP */
}
#endif /* FEATURE_CAN_HAS_WAKE_UP_IRQ */

/*!
 * @brief This function returns whether the previous FLEXCAN receive is completed. When performing a non-blocking receive, the user can call this function to ascertain the state of the current receive progress: in progress (or busy) or complete (success).
 */
status_t FLEXCAN_DRV_GetTransferStatus(uint8_t instance, uint8_t mb_idx)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    const flexcan_state_t * state = g_flexcanStatePtr[instance];
    status_t status;
    flexcan_mb_state_t mb_state;

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
    if(mb_idx == FLEXCAN_MB_HANDLE_ENHANCE_RXFIFO)
    {
        mb_state = state->enhanceRxFifoState.state;
    }
    else
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
    {
        mb_state = state->mbs[mb_idx].state;
    }

    if (mb_state == FLEXCAN_MB_IDLE)
    {
        status = STATUS_SUCCESS;
    }
#if FEATURE_CAN_HAS_DMA_ENABLE
    else if (mb_state == FLEXCAN_MB_DMA_ERROR)
    {
        status = STATUS_ERROR;
    }
#endif
    else
    {
        status = STATUS_BUSY;
    }    
    
    return status;
}

/*!
 * @brief Reports various error conditions detected in the reception and transmission of a CAN frame and some general status of the device.
 */
uint32_t FLEXCAN_DRV_GetErrorStatus(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    const CAN_Type * base = g_flexcanBase[instance];

    return ((uint32_t)(base->ESR1));
}

/*!
 * @brief Abort an ongoing transfer on the specified message buffer.
 */
status_t FLEXCAN_DRV_AbortTransfer(uint8_t instance, uint8_t mb_idx)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result = STATUS_SUCCESS;
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    CAN_Type * base = g_flexcanBase[instance];

    /* Check if a transfer is running. */
    if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE)
    {
        result = STATUS_CAN_NO_TRANSFER_IN_PROGRESS;
    }
    else
    {
        if (state->mbs[mb_idx].state == FLEXCAN_MB_TX_BUSY)
        {
            /* Stop the running transfer. */
            FLEXCAN_CompleteTransfer(instance, mb_idx);
            /* Clear message buffer flag */
            FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
            FLEXCAN_AbortTxMsgBuff(base, mb_idx);
            uint32_t flexcan_mb_config;

#ifndef ERRATA_E9527
            /* Wait to finish abort operation */
            while(FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U)
            {
                /* Do Nothing wait for the flag */
            }
#endif
            volatile const uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, mb_idx);
            flexcan_mb_config = * flexcan_mb;
            /* Check if the MBs have been safely Inactivated */
            if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT) == (uint32_t)FLEXCAN_TX_INACTIVE)
            {
#ifndef ERRATA_E9527
                /* Transmission have occurred */
                result = STATUS_CAN_NO_TRANSFER_IN_PROGRESS;
#else
                /* Transmission have not occurred because it uses the inactivation operation */
                if (FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U)
                {
                    result = STATUS_SUCCESS;
                }
                else
                {
                    result = STATUS_CAN_NO_TRANSFER_IN_PROGRESS;
                }
#endif
            }
            if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT) == (uint32_t)FLEXCAN_TX_ABORT)
            {
                /* Transmission have been aborted */
                    result = STATUS_SUCCESS;
            }
            /* Clear message buffer flag */
            FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
            state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
        }
        else
        {
            if (state->mbs[mb_idx].state == FLEXCAN_MB_RX_BUSY)
            {
                /* Stop the running transfer. */
                FLEXCAN_CompleteTransfer(instance, mb_idx);

                if(FLEXCAN_IsRxFifoEnabled(base) == true)
                {

                    /* Get the number of RX FIFO Filters*/
                    uint32_t val1 = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
                    /* Get the number if MBs occupied by RX FIFO and ID filter table*/
                    /* the Rx FIFO occupies the memory space originally reserved for MB0-5*/
                    /* Every number of RFFN means 8 number of RX FIFO filters*/
                    /* and every 4 number of RX FIFO filters occupied one MB*/
                    uint32_t val2 = RxFifoOcuppiedLastMsgBuff(val1);
                    if(mb_idx > val2)
                    {
                        /* This operation is not allowed for MB that are part of RxFIFO */
                        FLEXCAN_ResetRxMsgBuff(base, mb_idx);
                    }
                    if (mb_idx == FLEXCAN_MB_HANDLE_RXFIFO)
                    {
                        /* Disable RX FIFO interrupts*/
                        (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, false);
#if FEATURE_CAN_HAS_DMA_ENABLE
                        if (state->transferType == FLEXCAN_RXFIFO_USING_DMA)
                        {
                            (void) DMA_DRV_StopChannel(state->rxFifoDMAChannel);
                        }
#endif
                    }
                }
                else
                {
                    /* This operation is not allowed for MB that are part of RxFIFO */
                    FLEXCAN_ResetRxMsgBuff(base, mb_idx);
                }
            }

            if (FLEXCAN_GetMsgBuffIntStatus(base, mb_idx) == 1U)
            {
                /* Stop the running transfer. */
                FLEXCAN_CompleteTransfer(instance, mb_idx);
                /* Clear message buffer flag */
                FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
            }
        }
    }

    return result;
}

/*!
 * @brief Initiate (start) a transmit by beginning the process of sending data. This is not a public API as it is called from other driver functions.
 */
static status_t FLEXCAN_StartSendData(
                    uint8_t instance,
                    uint8_t mb_idx,
                    const flexcan_data_info_t *tx_info,
                    uint32_t msg_id,
                    const uint8_t *mb_data,
                    bool isBlocking
                    )
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(tx_info != NULL);

    status_t result;
    flexcan_msgbuff_code_status_t cs;
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    CAN_Type * base = g_flexcanBase[instance];

    if(mb_idx >= FLEXCAN_GetMaxMbNum(base))
    {
        result = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else if (state->mbs[mb_idx].state != FLEXCAN_MB_IDLE)
    {
        result = STATUS_BUSY;
    }
    else
    {
        /* Clear message buffer flag */
        FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

        state->mbs[mb_idx].state = FLEXCAN_MB_TX_BUSY;
        state->mbs[mb_idx].isBlocking = isBlocking;
        state->mbs[mb_idx].isRemote = tx_info->is_remote;

        cs.dataLen = tx_info->data_length;
        cs.msgIdType = tx_info->msg_id_type;

    #if FEATURE_CAN_HAS_FD
        cs.fd_enable = tx_info->fd_enable;
        cs.fd_padding = tx_info->fd_padding;
        cs.enable_brs = tx_info->enable_brs;
    #endif

        if (tx_info->is_remote)
        {
            cs.code = (uint32_t)FLEXCAN_TX_REMOTE;
        }
        else
        {
            cs.code = (uint32_t)FLEXCAN_TX_DATA;
        }
        result = FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, mb_data, false);

        if (result != STATUS_SUCCESS)
        {
            state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
        }
    }
    return result;
}

/*!
 * @brief Initiate (start) a receive by beginning the process of receiving data and enabling the interrupt. This is not a public API as it is called from other driver functions.
 */
static status_t FLEXCAN_StartRxMessageBufferData(
                    uint8_t instance,
                    uint8_t mb_idx,
                    flexcan_msgbuff_t *data,
                    bool isBlocking
                    )
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result = STATUS_SUCCESS;
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    /* Check if the MB index is in range */
    if(mb_idx >= FLEXCAN_GetMaxMbNum(base))
    {
        result = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }
    else
    {
        /* Check if RX FIFO is enabled*/
        if (FLEXCAN_IsRxFifoEnabled(base) == true)
        {
            uint32_t val1, val2;
            /* Get the number of RX FIFO Filters*/
            val1 = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
            /* Get the number if MBs occupied by RX FIFO and ID filter table*/
            /* the Rx FIFO occupies the memory space originally reserved for MB0-5*/
            /* Every number of RFFN means 8 number of RX FIFO filters*/
            /* and every 4 number of RX FIFO filters occupied one MB*/
            val2 = RxFifoOcuppiedLastMsgBuff(val1);

            if (mb_idx <= val2)
            {
                result = STATUS_CAN_BUFF_OUT_OF_RANGE;
            }
            else
            {
                /* None */
            }
        }
    }
    if(result == STATUS_SUCCESS)
    {
        /* Start receiving mailbox */
        if(state->mbs[mb_idx].state != FLEXCAN_MB_IDLE)
        {
            result = STATUS_BUSY;
        }
        else
        {
            state->mbs[mb_idx].state = FLEXCAN_MB_RX_BUSY;
            state->mbs[mb_idx].mb_message = data;
            state->mbs[mb_idx].isBlocking = isBlocking;

            /* Enable MB interrupt*/
            result = FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, true);

            if (result != STATUS_SUCCESS)
            {
                state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
            }
        }
    }
    return result;
}


/*!
 * @brief Initiate (start) a receive by beginning the process of receiving data and enabling the interrupt. This is not a public API as it is called from other driver functions.
 */
static status_t FLEXCAN_StartRxMessageFifoData(
                    uint8_t instance,
                    flexcan_msgbuff_t *data,
                    bool isBlocking
                    )
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result = STATUS_SUCCESS;
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];
#if FEATURE_CAN_HAS_DMA_ENABLE
    status_t dmaStat;

    if (state->transferType == FLEXCAN_RXFIFO_USING_DMA)
    {
        if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_DMA_ERROR)
        {
            /* Check if FIFO has Pending Request that generated error,
             * the RxFIFO need to be empty to activate DMA */
            if (FLEXCAN_GetBuffStatusFlag(base,FEATURE_CAN_RXFIFO_FRAME_AVAILABLE) == (uint8_t)1U)
            {
                /* Enter CAN in freeze Mode to allow FIFO Clear */
                FLEXCAN_EnterFreezeMode(base);

                FLEXCAN_ClearFIFO(base);
                do
                {   /* Read Offset 0x8C to clear DMA pending request */
                    (void) base->RAM[3];
                }
                while (FLEXCAN_GetBuffStatusFlag(base,FEATURE_CAN_RXFIFO_FRAME_AVAILABLE) == (uint8_t)1U);

                /* Return CAN to normal Mode */
                FLEXCAN_ExitFreezeMode(base);
            }
            /* Change status of MB to be reconfigured with DMA transfer */
            state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
        }
    }
#endif /* FEATURE_CAN_HAS_DMA_ENABLE */

    /* Start receiving fifo */
    if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state != FLEXCAN_MB_IDLE)
    {
        result = STATUS_BUSY;
    }
    else if(!FLEXCAN_IsRxFifoEnabled(base))/* Check if RxFIFO feature is enabled */
    {
        result = STATUS_ERROR;
    }
    else
    {
        state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_RX_BUSY;

        state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].isBlocking = isBlocking;

        /* This will get filled by the interrupt handler */
        state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message = data;

        if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS)
        {
            /* Enable RX FIFO interrupts*/
            (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_WARNING, true);
            (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_OVERFLOW, true);
            (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, true);
        }
#if FEATURE_CAN_HAS_DMA_ENABLE
        if (state->transferType == FLEXCAN_RXFIFO_USING_DMA)
        {
            status_t dmaStatus;

            dmaStatus = DMA_DRV_InstallCallback(state->rxFifoDMAChannel,
                                                FLEXCAN_CompleteRxFifoDataDMA,
                                                (void *)((uint32_t)instance));/* PRQA S 0326 */

            if (dmaStatus != STATUS_SUCCESS)
            {
                state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
                result = STATUS_ERROR;
            }
            else
            {
                dmaStatus = DMA_DRV_ConfigSingleBlockTransfer(state->rxFifoDMAChannel,
                                                                DMA_TRANSFER_MEM2MEM,
                                                                (uint32_t)(base->RAM),
                                                                (uint32_t)(state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message),
                                                                DMA_TRANSFER_SIZE_4B,
                                                                16U);

                if (dmaStatus != STATUS_SUCCESS)
                {
                    state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
                    result = STATUS_ERROR;
                }
                else
                {
                    DMA_DRV_DisableRequestsOnTransferComplete(state->rxFifoDMAChannel, true);

                    dmaStat = DMA_DRV_StartChannel(state->rxFifoDMAChannel);
                    if (dmaStat != STATUS_SUCCESS)
                    {
                        state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
                        result = STATUS_ERROR;
                    }
                }
            }
        }
    }
#endif

    return result;
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
static status_t FLEXCAN_StartRxMessageEnhanceFifoData(
                    uint8_t instance,
                    flexcan_msgbuff_t *data,
                    bool isBlocking
                    )
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    status_t result = STATUS_SUCCESS;
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    uint32_t dma_transfer_size = (uint32_t)(((base->ERFCR & CAN_ERFCR_DMALW_MASK) >> CAN_ERFCR_DMALW_SHIFT)+ 1U)* 4U;

#if FEATURE_CAN_HAS_DMA_ENABLE
    status_t dmaStat;
#endif /* FEATURE_CAN_HAS_DMA_ENABLE */

    if(state->enhanceRxFifoState.state != FLEXCAN_MB_IDLE)
    {
        result = STATUS_BUSY;
    }
    else if (!FLEXCAN_IsEnhanceRxFifoEnabled(base))
    {
        result = STATUS_ERROR;
    }
    else
    {
        state->enhanceRxFifoState.state = FLEXCAN_MB_RX_BUSY;
        state->enhanceRxFifoState.isBlocking = isBlocking;
        state->enhanceRxFifoState.mb_message = data;
        /* Enable enhance RX FIFO interrupts */
        if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS)
        {
            FLEXCAN_SetEnhanceRxFIFOOverflowINT(base,true);
            FLEXCAN_SetEnhanceRxFIFOWatermarkIndINT(base,true);
            FLEXCAN_SetEnhanceRxFIFODataAvailableINT(base,true);
            result = STATUS_SUCCESS;
        }
        else if(state->transferType == FLEXCAN_RXFIFO_USING_DMA)
        {
#if FEATURE_CAN_HAS_DMA_ENABLE

            dmaStat = DMA_DRV_InstallCallback(state->rxFifoDMAChannel,
                                                FLEXCAN_CompleteRxEnhanceFifoDataDMA,
                                                (void *)((uint32_t)instance));/* PRQA S 0326 */

            if (dmaStat != STATUS_SUCCESS)
            {
                state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
                result = STATUS_ERROR;
            }
            else
            {
                dmaStat = DMA_DRV_ConfigSingleBlockTransfer(state->rxFifoDMAChannel,
                                                                DMA_TRANSFER_MEM2MEM,
                                                                (uint32_t)((uint32_t)g_flexcanBase[instance] + FLEXCAN_ENHANCE_RX_FIFO_DATA_REGION_OFFSET),
                                                                (uint32_t)(state->enhanceRxFifoState.mb_message),
                                                                DMA_TRANSFER_SIZE_4B,
                                                                dma_transfer_size);

                if (dmaStat != STATUS_SUCCESS)
                {
                    state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
                    result = STATUS_ERROR;
                }
                else
                {
                    DMA_DRV_DisableRequestsOnTransferComplete(state->rxFifoDMAChannel, true);

                    dmaStat = DMA_DRV_StartChannel(state->rxFifoDMAChannel);
                    if (dmaStat != STATUS_SUCCESS)
                    {
                        state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
                        result = STATUS_ERROR;
                    }
                }
            }
        }
#endif
        else
        {
            result = STATUS_UNSUPPORTED;
        }  
    }
    return result;
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */


/*!
 * @brief Finish up a transmit by completing the process of sending data and disabling the interrupt. This is not a public API as it is called from other driver functions.
 */
static void FLEXCAN_CompleteTransfer(uint8_t instance, uint32_t mb_idx)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    /* Disable the transmitter data register empty interrupt */
    (void)FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, false);

    /* Update the information of the module driver state */
    if (state->mbs[mb_idx].isBlocking)
    {
        (void)OSIF_SemaPost(&state->mbs[mb_idx].mbSema);
    }
    state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
}

#if FEATURE_CAN_HAS_DMA_ENABLE
/*!
 * @brief Finish up a DMA transfer (this is just a wrapper over FLEXCAN_DRV_CompleteRxMessageFifoData). This is not a public API as it is called from other driver functions.
 */
static void FLEXCAN_CompleteRxFifoDataDMA(void *parameter, dma_chn_status_t status)
{
    uint32_t instance = (uint32_t)parameter;/* PRQA S 0326 */
    
    if(status == DMA_CHN_ERROR)
    {
        flexcan_state_t * state = g_flexcanStatePtr[instance];
        state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_DMA_ERROR;

        if  (state->callback != NULL)
        {
            state->callback((uint8_t)instance,
                            FLEXCAN_EVENT_DMA_ERROR,
                            FLEXCAN_MB_HANDLE_RXFIFO,
                            state);
        }
    }
    FLEXCAN_CompleteRxMessageFifoData((uint8_t)instance);
}


#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
static void FLEXCAN_CompleteRxEnhanceFifoDataDMA(void *parameter, dma_chn_status_t status)
{
    uint32_t instance = (uint32_t)parameter;/* PRQA S 0326 */

    if(status == DMA_CHN_ERROR)
    {
        flexcan_state_t * state = g_flexcanStatePtr[instance];
        state->enhanceRxFifoState.state = FLEXCAN_MB_DMA_ERROR;

        if  (state->callback != NULL)
        {
            state->callback((uint8_t)instance,
                            FLEXCAN_EVENT_DMA_ERROR,
                            FLEXCAN_MB_HANDLE_ENHANCE_RXFIFO,
                            state);
        }
    }
    FLEXCAN_CompleteRxMessageEnhanceFifoData((uint8_t)instance);
}
#endif /* FEATURE_CAN_HAS_DMA_ENABLE */
#endif

/*!
 * @brief Finish up a receive by completing the process of receiving data and disabling the interrupt. This is not a public API as it is called from other driver functions.
 */
static void FLEXCAN_CompleteRxMessageFifoData(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS)
    {
        /* Disable RX FIFO interrupts*/
        (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, false);
        (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_WARNING, false);
        (void)FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_OVERFLOW, false);
    }
#if FEATURE_CAN_HAS_DMA_ENABLE
    else
    {
        if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state != FLEXCAN_MB_DMA_ERROR)
        {
            flexcan_msgbuff_t *fifo_message = state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message;
            uint32_t *msgData_32 = (uint32_t *)fifo_message->data;/* PRQA S 0310 */ /* PRQA S 3305 */

            (void) DMA_DRV_StopChannel(state->rxFifoDMAChannel);
            /* Adjust the ID if it is not extended */
            if (((fifo_message->cs) & CAN_CS_IDE_MASK) == 0U)
            {
                fifo_message->msgId = fifo_message->msgId >> CAN_ID_STD_SHIFT;
            }
            /* Extract the data length */
            fifo_message->dataLen = (uint8_t)((fifo_message->cs & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
            /* Reverse the endianness */
            FlexcanSwapBytesInWord(msgData_32[0], msgData_32[0]);
            FlexcanSwapBytesInWord(msgData_32[1], msgData_32[1]);
        }
    }
#endif
    /* Clear fifo message*/
    state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message = NULL;

#if FEATURE_CAN_HAS_DMA_ENABLE
    if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state != FLEXCAN_MB_DMA_ERROR)
    {
        state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
        if ((state->callback != NULL) && (state->transferType == FLEXCAN_RXFIFO_USING_DMA))
        {
            state->callback(instance,
                            FLEXCAN_EVENT_DMA_COMPLETE,
                            FLEXCAN_MB_HANDLE_RXFIFO,
                            state);
        }
    }
#else
    state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
#endif

    /* Update status for receive by using fifo*/
    if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].isBlocking == true)
    {
        if ((state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_IDLE)
#if FEATURE_CAN_HAS_DMA_ENABLE
            || (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_DMA_ERROR)
#endif
           )
        {
            status_t status = OSIF_SemaPost(&state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mbSema);
            DEV_ASSERT(status == STATUS_SUCCESS);
            (void)status;
        }
    }
}


#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
/*!
 * @brief Finish up a receive by completing the process of receiving data and disabling the interrupt. This is not a public API as it is called from other driver functions.
 */
static void FLEXCAN_CompleteRxMessageEnhanceFifoData(uint8_t instance)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];
    uint8_t EnhanceRxFifoDataByte = 0U;
    uint32_t EnhanceRxFifoDataWord = 0U;

    if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS)
    {
        /* Disable ehnhanc RX FIFO interrupts */
        FLEXCAN_SetEnhanceRxFIFOOverflowINT(base,false);
        FLEXCAN_SetEnhanceRxFIFOWatermarkIndINT(base,false);
        FLEXCAN_SetEnhanceRxFIFODataAvailableINT(base,false);
    } 

#if FEATURE_CAN_HAS_DMA_ENABLE
    else if (state->transferType == FLEXCAN_RXFIFO_USING_DMA)
    {
        if (state->enhanceRxFifoState.state != FLEXCAN_MB_DMA_ERROR)
        {
            flexcan_msgbuff_t *fifo_message = state->enhanceRxFifoState.mb_message;
            uint32_t *msgData_32 = (uint32_t *)fifo_message->data;/* PRQA S 0310 */ /* PRQA S 3305 */

            (void) DMA_DRV_StopChannel(state->rxFifoDMAChannel);
            /* Adjust the ID if it is not extended */
            if (((fifo_message->cs) & CAN_CS_IDE_MASK) == 0U)
            {
                fifo_message->msgId = fifo_message->msgId >> CAN_ID_STD_SHIFT;
            }
            /* Extract the data length */
            fifo_message->dataLen = (uint8_t)((fifo_message->cs & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);

            EnhanceRxFifoDataByte = FLEXCAN_UseEnhanceRxFifoComputePayloadSize(fifo_message->dataLen);
            /* Reverse the endianness */
            /* Copy MB[0] data field into user's buffer */
            for (uint8_t i = 0U; i < EnhanceRxFifoDataByte; i += 4U)
            {
                EnhanceRxFifoDataWord = msgData_32[i >> 2U];  /* PRQA S 2983 */
                FlexcanSwapBytesInWord(EnhanceRxFifoDataWord, msgData_32[i >> 2U]);
            }
        }
    }
#endif

    state->enhanceRxFifoState.mb_message = NULL;

#if FEATURE_CAN_HAS_DMA_ENABLE
    if (state->enhanceRxFifoState.state != FLEXCAN_MB_DMA_ERROR)
    {
        state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
        if ((state->callback != NULL) && (state->transferType == FLEXCAN_RXFIFO_USING_DMA))
        {
            state->callback(instance,
                            FLEXCAN_EVENT_DMA_COMPLETE,
                            FLEXCAN_MB_HANDLE_ENHANCE_RXFIFO,
                            state);
        }
    }
#else
    state->enhanceRxFifoState.state = FLEXCAN_MB_IDLE;
#endif

    /* Update status for receive by using enhance RX FIFO*/
    if (state->enhanceRxFifoState.isBlocking == true)
    {
        if (state->enhanceRxFifoState.state == FLEXCAN_MB_IDLE)
        {
            status_t status = OSIF_SemaPost(&state->enhanceRxFifoState.mbSema);
            DEV_ASSERT(status == STATUS_SUCCESS);
            (void)status;
        }
    }
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

/*!
 * @brief Installs a callback function for the IRQ handler.
 */
void FLEXCAN_DRV_InstallEventCallback(uint8_t instance,
                                      flexcan_callback_t callback,
                                      void *callbackParam)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    flexcan_state_t * state = g_flexcanStatePtr[instance];

    state->callback = callback;
    state->callbackParam = callbackParam;
}

/*!
 * @brief Installs an error callback function for the IRQ handler and enables/disables error interrupts.
 */
void FLEXCAN_DRV_InstallErrorCallback(uint8_t instance,
                                      flexcan_error_callback_t callback,
                                      void *callbackParam)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];
    flexcan_state_t * state = g_flexcanStatePtr[instance];

    state->error_callback = callback;
    state->errorCallbackParam = callbackParam;

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (callback != NULL)
    {
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_ERR, true);
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_RX_WARNING, true);
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_TX_WARNING, true);
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_BUSOFF, true);
    }
    else
    {
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_ERR, false);
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_RX_WARNING, false);
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_TX_WARNING, false);
        FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_BUSOFF, false);
    }
    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

#if FEATURE_CAN_HAS_PRETENDED_NETWORKING

/*!
 * @brief Configures Pretended Networking settings.
 */
void FLEXCAN_DRV_ConfigPN(uint8_t instance, bool enable, const flexcan_pn_config_t *pnConfig)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

    CAN_Type * base = g_flexcanBase[instance];

    bool freeze = FLEXCAN_GetFreezeMode(base);

    if (freeze == false)
    {
        FLEXCAN_EnterFreezeMode(base);
    }

    if (enable)
    {
        FLEXCAN_ConfigPN(base, pnConfig);
#if FEATURE_CAN_HAS_SELF_WAKE_UP
        (void)FLEXCAN_SetSelfWakeUp(base, false);
#endif
    }

    FLEXCAN_SetPN(base, enable);

    if (freeze == false)
    {
        FLEXCAN_ExitFreezeMode(base);
    }
}

/*!
 * @brief Extracts one of the frames which triggered the wake up event.
 */
void FLEXCAN_DRV_GetWMB(uint8_t instance, uint8_t wmbIndex, flexcan_msgbuff_t *wmb)
{
    DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
    DEV_ASSERT(wmb != NULL);
    const CAN_Type *base  =  g_flexcanBase[instance];
    uint32_t *tmp, wmbData;

    tmp = (uint32_t *)&wmb->data[0];
    wmbData = base->WMB[wmbIndex].WMBn_D03;
    FlexcanSwapBytesInWord(wmbData, *tmp);

    tmp = (uint32_t *)&wmb->data[4];
    wmbData = base->WMB[wmbIndex].WMBn_D47;
    FlexcanSwapBytesInWord(wmbData, *tmp);

    wmb->cs = base->WMB[wmbIndex].WMBn_CS;

    if ((wmb->cs & CAN_CS_IDE_MASK) != 0U)
    {
        wmb->msgId = base->WMB[wmbIndex].WMBn_ID;
    }
    else
    {
        wmb->msgId = base->WMB[wmbIndex].WMBn_ID >> CAN_ID_STD_SHIFT;
    }

    wmb->dataLen = (uint8_t)((wmb->cs & CAN_CS_DLC_MASK) >> 16);
}

#endif /* FEATURE_CAN_HAS_PRETENDED_NETWORKING */

/*!
 * @brief Check the Sample value
 */
static inline uint32_t FLEXCAN_CheckDsample(uint32_t tmpSample, uint32_t samplePoint)
{
    uint32_t result = 0U;
    if (tmpSample > samplePoint)
    {
        result = (tmpSample - samplePoint);
    }
    else
    {
        result = (samplePoint - tmpSample);
    }
    return result;
}

/*!
 * @brief Check the Bitrate value
 */
static inline uint32_t FLEXCAN_CheckdBitrate(uint32_t tmpBitrate, uint32_t bitrate)
{
    uint32_t result = 0U;
    if (tmpBitrate > bitrate)
    {
        result = (tmpBitrate - bitrate);
    }
    else
    {
        result = (bitrate - tmpBitrate);        
    }
    return result;
}

/*!
 * @brief Check the JumpWidth value
 */
static inline uint32_t FLEXCAN_CheckJumpwidth(uint32_t pseg1)
{
    uint32_t result = 0U;    
    if (pseg1 < FLEXCAN_RJW_MAX)
    {
        result = pseg1;
    }
    else
    {
        result = FLEXCAN_RJW_MAX;    
    }
    return result;
}

/*!
 * @brief Calculate Tseg value
 */
static inline void FLEXCAN_ProccessTSeg(uint32_t * tSeg1, uint32_t * tSeg2)
{
    /* Adjust time segment 1 and time segment 2 */
    while ((*tSeg1 >= FLEXCAN_TSEG1_MAX) || (*tSeg2 < FLEXCAN_TSEG2_MIN))
    {
        *tSeg2 = *tSeg2 + 1U;
        *tSeg1 = *tSeg1 - 1U;
    }
}

/*!
 * @brief Calculate Pseg value
 */
static inline void FLEXCAN_ProccessPSeg(uint32_t * tmpPropseg, uint32_t * tmpPseg1)
{
    while (*tmpPropseg <= 0U)
    {
        *tmpPropseg = *tmpPropseg + 1U;
        *tmpPseg1 = *tmpPseg1 - 1U;
    }

    while (*tmpPropseg >= FLEXCAN_PROPSEG_MAX)
    {
        *tmpPropseg = *tmpPropseg - 1U;
        *tmpPseg1 = *tmpPseg1 + 1U;
    }
}
/*!
 * @brief Converts a bitrate (kbit/s) in time segment values for standard CAN frame.
 */
static uint32_t FLEXCAN_BitrateToTimeSeg(uint32_t bitrate,
                                         uint32_t clkFreq,
                                         flexcan_time_segment_t * timeSeg)
{
    uint32_t dBitrate, tmpBitrate, dBitrateMin, tmpPresdiv, tmpSample,
             dSampleMin, dSample, samplePoint, numTq, pseg1, pseg2, propseg,
             presdiv, tSeg1, tSeg2, tmpPseg1, tmpPseg2, tmpPropseg;

    presdiv = 0U;
    propseg = 0U;
    pseg1 = 0U;
    pseg2 = 0U;

    dSampleMin = 100U;
    dBitrateMin = 1000000U;
    samplePoint = 88U;

    for (tmpPresdiv = 0U; tmpPresdiv < FLEXCAN_PRESDIV_MAX; tmpPresdiv++) {

        /* Compute the number of time quanta in 1 bit time */
        numTq = clkFreq / ((tmpPresdiv + 1U) * bitrate);
        /* Compute the real bitrate resulted */
        tmpBitrate = clkFreq / ((tmpPresdiv + 1U) * numTq);

        /* The number of time quanta in 1 bit time must be lower than the one supported */
        if ((numTq >= FLEXCAN_NUM_TQ_MIN) && (numTq < FLEXCAN_NUM_TQ_MAX))
        {
            /* Compute time segments based on the value of the sampling point */
            tSeg1 = (numTq * samplePoint / 100U) - 1U;
            tSeg2 = numTq - 1U - tSeg1;

            /* Adjust time segment 1 and time segment 2 */
            FLEXCAN_ProccessTSeg(&tSeg1, &tSeg2);

            tmpPseg2 = tSeg2 - 1U;

            /* Start from pseg1 = pseg2 and adjust until propseg is valid */
            tmpPseg1 = tmpPseg2;
            tmpPropseg = tSeg1 - tmpPseg1 - 2U;

            FLEXCAN_ProccessPSeg(&tmpPropseg, &tmpPseg1);


            if (((tSeg1 >= FLEXCAN_TSEG1_MAX) || (tSeg2 >= FLEXCAN_TSEG2_MAX) || (tSeg2 < FLEXCAN_TSEG2_MIN) || (tSeg1 < FLEXCAN_TSEG1_MIN)) ||
               ((tmpPropseg >= FLEXCAN_PROPSEG_MAX) || (tmpPseg1 >= FLEXCAN_PSEG1_MAX) || (tmpPseg2 < FLEXCAN_PSEG2_MIN) || (tmpPseg2 >= FLEXCAN_PSEG2_MAX))) /*PRQA S 2996*/
            {
                continue;
            }

            tmpSample = ((tSeg1 + 1U) * 100U) / numTq;
            dSample = FLEXCAN_CheckDsample(tmpSample , samplePoint);
            dBitrate = FLEXCAN_CheckdBitrate(tmpBitrate , bitrate);

            if ((dBitrate < dBitrateMin) ||
                ((dBitrate == dBitrateMin) && (dSample < dSampleMin)))
            {
                dSampleMin = dSample;
                dBitrateMin = dBitrate;
                pseg1 = tmpPseg1;
                pseg2 = tmpPseg2;
                presdiv = tmpPresdiv;
                propseg = tmpPropseg;

                if ((dBitrate == 0U) && (dSample <= 1U))
                {
                    break;
                }
            }
        }
    }

    timeSeg->phaseSeg1 = pseg1;
    timeSeg->phaseSeg2 = pseg2;
    timeSeg->preDivider = presdiv;
    timeSeg->propSeg = propseg;
    timeSeg->rJumpwidth = FLEXCAN_CheckJumpwidth(pseg1);

    return tmpBitrate;
}

/*!
 * @brief Gets the default configuration structure
 */
uint32_t FLEXCAN_DRV_GetDefaultConfig(flexcan_user_config_t * config)
{
    /* Checks input parameter. */
    DEV_ASSERT(config != NULL);

    uint32_t clkFreq, bitrate;
    flexcan_time_segment_t timeSeg;

    /* Get the PE clock frequency */
    (void)CLOCK_SYS_GetFreq(FEATURE_CAN_PE_OSC_CLK_NAME, &clkFreq);
    /* Means Clock Gate is off */
    DEV_ASSERT(clkFreq > 0U);
    /* Time segments computed for PE bitrate = 500 Kbit/s, sample point = 87.5 */
    bitrate = FLEXCAN_BitrateToTimeSeg(500000U, clkFreq, &timeSeg);

    /* Maximum number of message buffers */
    config->max_num_mb = 16;
    /* Rx FIFO is disabled */
    config->is_rx_fifo_needed = false;
    /* Number of Rx FIFO ID filters */
    config->num_id_filters = FLEXCAN_RX_FIFO_ID_FILTERS_8;
    /* Normal operation mode */
    config->flexcanMode = FLEXCAN_NORMAL_MODE;
#if FEATURE_CAN_HAS_PE_CLKSRC_SELECT
    /* Protocol engine clock is System Oscillator div 2 */
    config->pe_clock = FLEXCAN_CLK_SOURCE_OSC;
#endif
    /* Time segments for the arbitration phase */
    config->bitrate = timeSeg;
#if FEATURE_CAN_HAS_FD
    /* Payload size */
    config->payload = FLEXCAN_PAYLOAD_SIZE_8;
    /* Flexible data rate is disabled */
    config->fd_enable = false;
    /* Time segments for the data phase of FD frames */
    config->bitrate_cbt = timeSeg;
#endif
    /* Rx FIFO transfer type */
    config->transfer_type = FLEXCAN_RXFIFO_USING_INTERRUPTS;
#if FEATURE_CAN_HAS_DMA_ENABLE
    /* Rx FIFO DMA channel */
    config->rxFifoDMAChannel = 0U;
#endif

    return bitrate;
}

/*******************************************************************************
 * EOF
 ******************************************************************************/
