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

/*!
 * @file flexcan_hw_access.c
 * @version 1.4.1
 *
 * @brief FlexCAN Hardware Access Layer — non-inline register operations.
 *
 * Implements the non-inline functions for FlexCAN register access,
 * including module initialization, message buffer configuration, Rx
 * FIFO management, Enhanced Rx FIFO, and Pretended Networking setup.
 */

/*!
 * @page misra_violations MISRA-C:2012 violations list
 *
 * PRQA S 0310 Rule 11.3 : Casting to different object pointer type.
 *
 * PRQA S 0311 Rule 11.8 : Dangerous pointer cast results in loss of const qualification.
 *
 * PRQA S 2983 Rule 2.2  : TThis assignment is redundant. The value of this object is never subsequently used.
 *
 * PRQA S 2985 Rule 2.2 :  This operation is redundant. The value of the result is always 
 *                         that of the left-hand operand.
 *
 * PRQA S 3305 Rule 11.6 : Pointer cast to stricter alignment.
 *
 * PRQA S 4700 CMN  0.2  : 4700 Metric value out of threshold range: %s.
 *
 * PRQA S 3206 Rule 2.7  : The parameter '%1s' is not used in this function.
 *
 * PRQA S 0488 Rule 18.4  : Performing pointer arithmetic.
 *
 * PRQA S 0489 Rule 18.4  : The integer value 1 is being added or subtracted from a pointer..
 */

#include "flexcan_hw_access.h"
#include "interrupt_manager.h"

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

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

#define FLEXCAN_ALL_INT (0x3B0006U) /*!< Masks for wakeup, error, bus off*/
#define BUS_OFF_INT     (0xB0004U)  /*!< Masks for busOff, Tx/Rx Warning */
#if !(defined(YTM32B1L_SERIES))
#define ERROR_INT (0x300002U) /*!< Masks for ErrorOvr, ErrorFast, Error */
#endif

#define RxFifoFilterTableOffset 0x18U

#define FlexCanRxFifoAcceptRemoteFrame 1UL
#define FlexCanRxFifoAcceptExtFrame    1UL

/*******************************************************************************
 * Private Functions
 ******************************************************************************/

static uint8_t FLEXCAN_ComputeDLCValue(uint8_t payloadSize);
static uint8_t FLEXCAN_ComputePayloadSize(uint8_t dlcValue);
static void FLEXCAN_ClearRAM(CAN_Type *base);
#if (defined(YTM32B1L_SERIES))
static uint32_t FLEXCAN_DeserializeUint32(const uint8_t *buffer);

static uint32_t FLEXCAN_DeserializeUint32(const uint8_t *buffer)
{
    uint32_t value = 0U;
    value = (uint32_t)buffer[3] << 24U;
    value |= (uint32_t)buffer[2] << 16U;
    value |= (uint32_t)buffer[1] << 8U;
    value |= (uint32_t)buffer[0];
    return value;
}

inline static uint32_t FLEXCAN_DataTransferTxMsgBuff(volatile uint32_t *flexcan_mb_data_32,
                                                     const flexcan_msgbuff_code_status_t *cs,
                                                     const uint8_t *msgData);
#endif

/* Determines the RxFIFO Filter element number */
#define RxFifoFilterElementNum(x) (((x) + 1U) * 8U)

/*!
 * @brief Calculate the Global Mask as format ID type in FIFO Mode. Based on the ID format type and Mask Type will calculate the and set accordingly the Rx FIFO Individual\Global Mask register.
 */
uint32_t
FLEXCAN_GetRxFifoMask(flexcan_msgbuff_id_type_t id_type, flexcan_rx_fifo_id_element_format_t formatType, uint32_t mask)
{
    uint32_t val = 0U;

    switch (formatType)
    {
        case (FLEXCAN_RX_FIFO_ID_FORMAT_A):
            /* Set RTR bit encoded as bit 31 and IDE bit encoded as bit 30 in mask */
            val = mask & ((1UL << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_RTR_SHIFT) |
                          (1UL << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_IDE_SHIFT));
            if (id_type == FLEXCAN_MSG_ID_STD)
            {
                /* Set standard global mask for RX FIFO and IDE will be 1 and check the FIFO filter ide */
                val |= ((mask << FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_STD_SHIFT) &
                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_STD_MASK);
            }
            else if (id_type == FLEXCAN_MSG_ID_EXT)
            {
                /* Set extended global mask for RX FIFO and IDE will be 0 and don't check the FIFO filter ide */
                val |= ((mask << FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_EXT_SHIFT) &
                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_EXT_MASK);
            }
            else
            {
                /* Should not get here */
            }
            break;
        case (FLEXCAN_RX_FIFO_ID_FORMAT_B):
            /* Set RTR bit encoded as bit 31 and IDE bit encoded as bit 30 in mask */
            val = mask & ((1UL << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_RTR_SHIFT) |
                          (1UL << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_IDE_SHIFT));
            if (id_type == FLEXCAN_MSG_ID_STD)
            {
                /* Set standard global mask for RX FIFO  */
                val |= ((mask & FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_STD_MASK)
                        << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_STD_SHIFT1);
            }
            else if (id_type == FLEXCAN_MSG_ID_EXT)
            {
                /* Set extended global mask for RX FIFO  */
                val |= ((mask & FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_MASK1)
                        << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1);
            }
            else
            {
                /* Should not get here */
            }
            break;
        case (FLEXCAN_RX_FIFO_ID_FORMAT_C):
            if ((id_type == FLEXCAN_MSG_ID_EXT) || (id_type == FLEXCAN_MSG_ID_STD))
            {
                val = ((mask & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_MASK) << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1);
            }
            else
            {
                /* Should not get here */
            }
            break;
        default:
            /* FLEXCAN_RX_FIFO_ID_FORMAT_D not supported */
            /* Should not get here */
            break;
    } /* End Switch */

    return val;
}

/*!
 * @brief Computes the DLC field value, given a payload size (in bytes).
 */
static uint8_t FLEXCAN_ComputeDLCValue(uint8_t payloadSize)
{
    uint32_t ret = 0xFFU; /* 0,  1,  2,  3,  4,  5,  6,  7,  8, */
    static const uint8_t payload_code[65] = { 0U,
                                              1U,
                                              2U,
                                              3U,
                                              4U,
                                              5U,
                                              6U,
                                              7U,
                                              8U,
                                              /* 9 to 12 payload have DLC Code 12 Bytes */
                                              CAN_DLC_VALUE_12_BYTES,
                                              CAN_DLC_VALUE_12_BYTES,
                                              CAN_DLC_VALUE_12_BYTES,
                                              CAN_DLC_VALUE_12_BYTES,
                                              /* 13 to 16 payload have DLC Code 16 Bytes */
                                              CAN_DLC_VALUE_16_BYTES,
                                              CAN_DLC_VALUE_16_BYTES,
                                              CAN_DLC_VALUE_16_BYTES,
                                              CAN_DLC_VALUE_16_BYTES,
                                              /* 17 to 20 payload have DLC Code 20 Bytes */
                                              CAN_DLC_VALUE_20_BYTES,
                                              CAN_DLC_VALUE_20_BYTES,
                                              CAN_DLC_VALUE_20_BYTES,
                                              CAN_DLC_VALUE_20_BYTES,
                                              /* 21 to 24 payload have DLC Code 24 Bytes */
                                              CAN_DLC_VALUE_24_BYTES,
                                              CAN_DLC_VALUE_24_BYTES,
                                              CAN_DLC_VALUE_24_BYTES,
                                              CAN_DLC_VALUE_24_BYTES,
                                              /* 25 to 32 payload have DLC Code 32 Bytes */
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              CAN_DLC_VALUE_32_BYTES,
                                              /* 33 to 48 payload have DLC Code 48 Bytes */
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              CAN_DLC_VALUE_48_BYTES,
                                              /* 49 to 64 payload have DLC Code 64 Bytes */
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES,
                                              CAN_DLC_VALUE_64_BYTES };

    if (payloadSize <= 64U)
    {
        ret = payload_code[payloadSize];
    }
    else
    {
        /* The argument is not a valid payload size will return 0xFF*/
    }

    return (uint8_t)ret;
}

/*!
 * @brief Computes the maximum payload size (in bytes), given a DLC field value.
 */
static uint8_t FLEXCAN_ComputePayloadSize(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;
}

/*!
 * @brief Computes the maximum RAM size occupied by MBs.
 */
uint32_t FLEXCAN_GetMaxMbNum(const CAN_Type *base)
{
    uint32_t i = 0;
    uint32_t ret = 0;
    static CAN_Type *const flexcanBase[] = CAN_BASE_PTRS;
    static const uint32_t maxMbNum[] = FEATURE_CAN_MAX_MB_NUM_ARRAY;

#if (CAN_INSTANCE_COUNT > 1U)
    for (i = 0; i < CAN_INSTANCE_COUNT; i++)
#endif
    {
        if (base == flexcanBase[i])
        {
            ret = maxMbNum[i];
        }
    }

    return ret;
}

/*!
 * @brief Clears FlexCAN memory positions that require initialization.
 */
static void FLEXCAN_ClearRAM(CAN_Type *base)
{
    uint32_t databyte;
    uint32_t maxMbNum;
    volatile uint32_t *RAM = base->RAM;

    /* Clear RXMGMASK,RX14MASK,RX15MASK,RXFGMASK Regions*/
    base->RXMGMASK = 0xFFFFFFFFU;
    base->RX14MASK = 0xFFFFFFFFU;
    base->RX15MASK = 0xFFFFFFFFU;
    base->RXFGMASK = 0xFFFFFFFFU;

    /* Clear MB region */
    /* Get max mailbox number */
    maxMbNum = FLEXCAN_GetMaxMbNum(base);
    for (databyte = 0U; databyte < (4U * maxMbNum); databyte++)
    {
        RAM[databyte] = 0x0U;
    }

    /* Clear RX Individual Mask Regions for RXIMRn */
    for (databyte = 0U; databyte < maxMbNum; databyte++)
    {
        base->RXIMR[databyte] = 0xFFFFFFFFU;
    }

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
    /* Clear enhance fifo filter table if target has enhance fifo feature*/
    if (FLEXCAN_HasEnhanceRxFIFO(base))
    {
        /* Clear enhanced Rx FIFO filter table */
        RAM = (volatile uint32_t *)((uint32_t)base + (uint32_t)FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_OFFSET);
        for (databyte = 0U; databyte < FEATURE_CAN_ERFFELn_COUNT; databyte++)
        {
            RAM[databyte] = 0xFFFFFFFFU;
        }
    }
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

#if FEATURE_CAN_HAS_HR_TIMESTAMP
    /* Clear High-resolution Time Stamp Regions if target has HRTIMESTAMP */
    if (FLEXCAN_HasHRTIMESTAMP(base))
    {
        for (databyte = 0U; databyte < maxMbNum; databyte++)
        {
            base->HR_TIME_STAMPn[databyte] = 0x0U;
        }
    }
#endif /* FEATURE_CAN_HAS_HR_TIMESTAMP */

#if FEATURE_CAN_HAS_RAM_ECC
    base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_WRMFRZ_MASK) | CAN_CTRL2_WRMFRZ(1U);

    RAM = (volatile uint32_t *)((uint32_t)base + 0xA80U);
    for (databyte = 0U; databyte < 6U; databyte++)
    {
        RAM[databyte] = 0x0U;
    }
    /* Clean SMB of Classical CAN */
    RAM = (volatile uint32_t *)((uint32_t)base + 0xAB0U);
    for (databyte = 0U; databyte < 12U; databyte++)
    {
        RAM[databyte] = 0x0U;
    }
    /* Clear SMB region in CANFD mode */
    RAM = (volatile uint32_t *)((uint32_t)base + 0xF28U);
    for (databyte = 0U; databyte < 54U; databyte++)
    {
        RAM[databyte] = 0x0U;
    }

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
    /* Clear enhance fifo if target has enhance fifo feature and ECC on */
    if (FLEXCAN_HasEnhanceRxFIFO(base))
    {
        /* Clear enhanced Rx FIFO data region */
        RAM = (volatile uint32_t *)((uint32_t)base + (uint32_t)FLEXCAN_ENHANCE_RX_FIFO_DATA_REGION_OFFSET);
        for (databyte = 0U; databyte < (20U * FEATURE_CAN_ENHANCE_RX_FIFO_COUNT); databyte++)
        {
            RAM[databyte] = 0x0U;
        }
    }
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

#if FEATURE_CAN_HAS_HR_TIMESTAMP
    /* Clear High-resolution Time Stamp Regions if target has HRTIMESTAMP */
    if (FLEXCAN_HasHRTIMESTAMP(base))
    {
        /* Clear High-resolution Time Stamp Regions for Rx SMB */
        *(volatile uint32_t *)((uint32_t)base + 0xC20U) = 0x0U;
        *(volatile uint32_t *)((uint32_t)base + 0xC24U) = 0x0U;
    }
#endif /* FEATURE_CAN_HAS_HR_TIMESTAMP */

    /* Clear WRMFRZ bit in CTRL2 Register to restrict write access to memory */
    base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_WRMFRZ_MASK) | CAN_CTRL2_WRMFRZ(0U);
#endif /* FEATURE_CAN_HAS_RAM_ECC */
}

/*******************************************************************************
 * Code
 ******************************************************************************/

/*!
 * @brief Returns the start of a MB area, based on its index.
 */
volatile uint32_t *FLEXCAN_GetMsgBuffRegion(CAN_Type *base, uint32_t msgBuffIdx)
{
#if FEATURE_CAN_HAS_FD
    uint8_t payload_size = FLEXCAN_GetPayloadSize(base);
#else
    uint8_t payload_size = 8U;
#endif

    uint8_t arbitration_field_size = 8U;
    uint32_t ramBlockSize = 512U;
    uint32_t ramBlockOffset;

    uint8_t mb_size = (uint8_t)(payload_size + arbitration_field_size);
    uint8_t maxMbNum = (uint8_t)(ramBlockSize / mb_size);

    ramBlockOffset = 128U * (msgBuffIdx / (uint32_t)maxMbNum);

    /* Multiply the MB index by the MB size (in words) */
    uint32_t mb_index = ramBlockOffset + ((msgBuffIdx % (uint32_t)maxMbNum) * ((uint32_t)mb_size >> 2U));

    return &(base->RAM[mb_index]);
}

/*!
 * @brief Enable FlexCAN module. This function will enable FlexCAN module.
 */
void FLEXCAN_Enable(CAN_Type *base)
{
    /* Check for low power mode */
    if (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 1U)
    {
        /* Enable clock */
        base->MCR = (base->MCR & ~CAN_MCR_MDIS_MASK) | CAN_MCR_MDIS(0U);
    }
}

/*!
 * @brief Disable FlexCAN module. This function will disable FlexCAN module.
 */
void FLEXCAN_Disable(CAN_Type *base)
{
    /* To access the memory mapped registers */
    /* Entre disable mode (hard reset). */
    if (((base->MCR & CAN_MCR_MDIS_MASK) >> CAN_MCR_MDIS_SHIFT) == 0U)
    {
        /* Clock disable (module) */
        base->MCR = (base->MCR & ~CAN_MCR_MDIS_MASK) | CAN_MCR_MDIS(1U);

        /* Wait until disable mode acknowledged */
        while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 0U)
        {
        }
    }
}

/*!
 * @brief Initialize FlexCAN module. This function will reset FlexCAN module, set maximum number of message buffers, initialize all message buffers as inactive, enable RX FIFO if needed, mask all mask bits, and disable all MB interrupts.
 */
void FLEXCAN_Init(CAN_Type *base)
{
    /* Reset the FLEXCAN */
    base->MCR = (base->MCR & ~CAN_MCR_SOFTRST_MASK) | CAN_MCR_SOFTRST(1U);

    /* Wait for reset cycle to complete */
    while (((base->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT) != 0U)
    {
    }

    /* Enable abort */
#ifndef ERRATA_E9527
    /* Avoid Abort Transmission, use Inactive MB */
    base->MCR = (base->MCR & ~CAN_MCR_AEN_MASK) | CAN_MCR_AEN(1U);
#endif

    /* Clear FlexCAN memory */
    FLEXCAN_ClearRAM(base);

    /* Disable all MB interrupts */
    (base->IMASK1) = 0x0U;
    /* Clear all MB interrupt flags */
    (base->IFLAG1) = CAN_IMASK1_BUF31TO0M_MASK;

#if FEATURE_CAN_MAX_MB_NUM > 32U
    if (FLEXCAN_GetMaxMbNum(base) > 32U)
    {
        (base->IMASK2) = 0x0;
        (base->IFLAG2) = CAN_IMASK2_BUF63TO32M_MASK;
    }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 64U
    if (FLEXCAN_GetMaxMbNum(base) > 64U)
    {
        (base->IMASK3) = 0x0;
        (base->IFLAG3) = CAN_IMASK3_BUF95TO64M_MASK;
    }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 96U
    if (FLEXCAN_GetMaxMbNum(base) > 96U)
    {
        (base->IMASK4) = 0x0;
        (base->IFLAG4) = CAN_IMASK4_BUF127TO96M_MASK;
    }
#endif
    /* Clear all error interrupt flags */
    (base->ESR1) = FLEXCAN_ALL_INT;
}

#if (defined(YTM32B1L_SERIES))
/*!
 * @brief Transfer Payload data in message buffer, in case of unaligned buffer it makes a byte alignment. This function is private.
 */
inline static uint32_t FLEXCAN_DataTransferTxMsgBuff(volatile uint32_t *flexcan_mb_data_32, /* PRQA S 4700, 3206 */
                                                     const flexcan_msgbuff_code_status_t *cs,
                                                     const uint8_t *msgData)
{
    uint32_t databyte;
    const uint32_t *msgData_32 = (const uint32_t *)msgData; /* PRQA S 0310, 3305 */

    /* Check if the buffer address is aligned */
    if (((uint32_t)msgData_32 & 0x3U) != 0U)
    {
        for (databyte = 0U; databyte < (cs->dataLen & ~3U); databyte += 4U)
        {
            uint32_t x = FLEXCAN_DeserializeUint32(&msgData[databyte]);
            FlexcanSwapBytesInWord(x, flexcan_mb_data_32[databyte >> 2U]);
        }
    }
    else
    {
        for (databyte = 0U; databyte < (cs->dataLen & ~3U); databyte += 4U)
        {
            FlexcanSwapBytesInWord(msgData_32[databyte >> 2U], flexcan_mb_data_32[databyte >> 2U]);
        }
    }
    return databyte;
}
#endif /* defined(YTM32B1L_SERIES) */

/*!
 * @brief Configure a message buffer for transmission. 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 copy user's buffer into the message buffer data area and configure the message buffer as required for transmission.
 */
status_t FLEXCAN_SetTxMsgBuff(/* PRQA S 4700 */
                              CAN_Type *base,
                              uint32_t msgBuffIdx,
                              const flexcan_msgbuff_code_status_t *cs,
                              uint32_t msgId,
                              const uint8_t *msgData,
                              const bool isRemote)
{
    DEV_ASSERT(cs != NULL);

    uint32_t val1;
    uint32_t val2;
    uint32_t flexcan_mb_config = 0U;
    uint32_t databyte;
    uint8_t dlc_value;
    status_t stat = STATUS_SUCCESS;

    volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);

    volatile uint32_t *flexcan_mb_id = &flexcan_mb[1];
    volatile uint8_t *flexcan_mb_data = (volatile uint8_t *)(&flexcan_mb[2]);
    volatile uint32_t *flexcan_mb_data_32 = &flexcan_mb[2];
    const uint32_t *msgData_32 = (const uint32_t *)msgData; /* PRQA S 0310, 3305 */

    if (msgBuffIdx > (((base->MCR) & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT))
    {
        stat = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }

    /* Check if RX FIFO is enabled*/
    if (((base->MCR & CAN_MCR_RFEN_MASK) >> CAN_MCR_RFEN_SHIFT) != 0U)
    {
        /* 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 (msgBuffIdx <= val2)
        {
            stat = STATUS_CAN_BUFF_OUT_OF_RANGE;
        }
    }

    if (stat == STATUS_SUCCESS)
    {
#if FEATURE_CAN_HAS_FD
        /* Make sure the BRS bit will not be ignored */
        if (FLEXCAN_IsFDEnabled(base) && cs->enable_brs)
        {
            base->FDCTRL = (base->FDCTRL & ~CAN_FDCTRL_FDRATE_MASK) | CAN_FDCTRL_FDRATE(1U);
        }
        /* Check if the Payload Size is smaller than the payload configured */
        DEV_ASSERT((uint8_t)cs->dataLen <= FLEXCAN_GetPayloadSize(base));
#else
        DEV_ASSERT((uint8_t)cs->dataLen <= 8U);
#endif

        /* Compute the value of the DLC field */
        dlc_value = FLEXCAN_ComputeDLCValue((uint8_t)cs->dataLen);

        /* Copy user's buffer into the message buffer data area */
        if (msgData != NULL)
        {
            uint8_t payload_size = FLEXCAN_ComputePayloadSize(dlc_value);

#if (defined(YTM32B1L_SERIES))
            (void)msgData_32;
            databyte = FLEXCAN_DataTransferTxMsgBuff(flexcan_mb_data_32, cs, msgData);
#else
            for (databyte = 0; databyte < (cs->dataLen & ~3U); databyte += 4U)
            {
                FlexcanSwapBytesInWord(msgData_32[databyte >> 2U], flexcan_mb_data_32[databyte >> 2U]);
            }
#endif
            for (; databyte < cs->dataLen; databyte++)
            {
                flexcan_mb_data[FlexcanSwapBytesInWordIndex(databyte)] = msgData[databyte];
            }
            /* Add padding, if needed */
            for (databyte = cs->dataLen; databyte < payload_size; databyte++)
            {
                flexcan_mb_data[FlexcanSwapBytesInWordIndex(databyte)] = cs->fd_padding;
            }
        }

        /* Clean up the arbitration field area */
        *flexcan_mb = 0;
        *flexcan_mb_id = 0;

        /* Set the ID according the format structure */
        if (cs->msgIdType == FLEXCAN_MSG_ID_EXT)
        {
            /* ID [28-0] */
            *flexcan_mb_id &= ~(CAN_ID_STD_MASK | CAN_ID_EXT_MASK);
            *flexcan_mb_id |= (msgId & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK));

            /* Set IDE and SRR bit*/
            flexcan_mb_config |= CAN_CS_IDE_MASK | CAN_CS_SRR_MASK;
        }
        if (cs->msgIdType == FLEXCAN_MSG_ID_STD)
        {
            /* ID[28-18] */
            *flexcan_mb_id &= ~CAN_ID_STD_MASK;
            *flexcan_mb_id |= (msgId << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;

            /* make sure IDE and SRR are not set */
            flexcan_mb_config &= ~(CAN_CS_IDE_MASK | CAN_CS_SRR_MASK);
        }

        /* Set the length of data in bytes */
        flexcan_mb_config |= ((uint32_t)dlc_value << CAN_CS_DLC_SHIFT) & CAN_CS_DLC_MASK;

        /* Set MB CODE */
        if (cs->code != (uint32_t)FLEXCAN_TX_NOT_USED)
        {
            if (cs->code == (uint32_t)FLEXCAN_TX_REMOTE)
            {
                /* Set RTR bit */
                flexcan_mb_config |= CAN_CS_RTR_MASK;
            }
            else
            {
                if (isRemote == true)
                {
                    /* Set RTR bit */
                    flexcan_mb_config |= CAN_CS_RTR_MASK;
                }
            }

            /* Set the code */
            if (cs->fd_enable)
            {
                flexcan_mb_config |= ((cs->code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK) | CAN_MB_EDL_MASK;
            }
            else
            {
                flexcan_mb_config |= (cs->code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;
            }

            if (cs->enable_brs)
            {
                flexcan_mb_config |= CAN_MB_BRS_MASK;
            }

            *flexcan_mb = flexcan_mb_config;
        }
    }

    return stat;
}

/*!
 * @brief Writes the abort code into the CODE field of the requested Tx message buffer.
 */
void FLEXCAN_AbortTxMsgBuff(CAN_Type *base, uint32_t msgBuffIdx)
{
    uint32_t flexcan_mb_config = 0;
    uint32_t code = FLEXCAN_TX_ABORT;

    volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
    flexcan_mb_config = *flexcan_mb;

    /* Reset the code */
    flexcan_mb_config &= (~CAN_CS_CODE_MASK);

    /* Write the abort code */
#ifdef ERRATA_E9527
    /* Use instead Abort Code the Inactive Code */
    code = FLEXCAN_TX_INACTIVE;
#endif
    flexcan_mb_config |= (code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;

    *flexcan_mb = flexcan_mb_config;
}

/*!
 * @brief Writes the Inactive Rx code into the CODE field of the requested Rx message buffer and restore the MB to active Rx. This will force even the unlock of the RxMB.
 */
void FLEXCAN_ResetRxMsgBuff(CAN_Type *base, uint32_t msgBuffIdx)
{
    uint32_t flexcan_mb_config = 0U;
    uint32_t code = FLEXCAN_RX_INACTIVE;

    volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
    flexcan_mb_config = *flexcan_mb;

    /* Reset the code and unlock the MB */
    flexcan_mb_config &= (~CAN_CS_CODE_MASK);
    flexcan_mb_config |= (code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK; /* PRQA S 2985 */
    *flexcan_mb = flexcan_mb_config;

    /* Reconfigure The MB as left by RxMBconfig */
    code = FLEXCAN_RX_EMPTY;
    flexcan_mb_config &= (~CAN_CS_CODE_MASK); /* PRQA S 2985 */
    flexcan_mb_config |= (code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;
    *flexcan_mb = flexcan_mb_config;
}

/*!
 * @brief Configure a message buffer for receiving. 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 configure the message buffer as required for receiving.
 */
status_t
FLEXCAN_SetRxMsgBuff(CAN_Type *base, uint32_t msgBuffIdx, const flexcan_msgbuff_code_status_t *cs, uint32_t msgId)
{
    DEV_ASSERT(cs != NULL);

    uint32_t val1;
    uint32_t val2;
    uint32_t flexcan_mb_config = 0;

    volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
    volatile uint32_t *flexcan_mb_id = &flexcan_mb[1];
    status_t stat = STATUS_SUCCESS;

    if (msgBuffIdx > (((base->MCR) & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT))
    {
        stat = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }

    /* Check if RX FIFO is enabled */
    if (((base->MCR & CAN_MCR_RFEN_MASK) >> CAN_MCR_RFEN_SHIFT) != 0U)
    {
        /* 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 (msgBuffIdx <= val2)
        {
            stat = STATUS_CAN_BUFF_OUT_OF_RANGE;
        }
    }

    if (stat == STATUS_SUCCESS)
    {
        /* Clean up the arbitration field area */
        *flexcan_mb = 0;
        *flexcan_mb_id = 0;

        /* Set the ID according the format structure */
        if (cs->msgIdType == FLEXCAN_MSG_ID_EXT)
        {
            /* Set IDE */
            flexcan_mb_config |= CAN_CS_IDE_MASK;

            /* Clear SRR bit */
            flexcan_mb_config &= ~CAN_CS_SRR_MASK;

            /* ID [28-0] */
            *flexcan_mb_id &= ~(CAN_ID_STD_MASK | CAN_ID_EXT_MASK);
            *flexcan_mb_id |= (msgId & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK));
        }
        if (cs->msgIdType == FLEXCAN_MSG_ID_STD)
        {
            /* Make sure IDE and SRR are not set */
            flexcan_mb_config &= ~(CAN_CS_IDE_MASK | CAN_CS_SRR_MASK);

            /* ID[28-18] */
            *flexcan_mb_id &= ~CAN_ID_STD_MASK;
            *flexcan_mb_id |= (msgId << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;
        }

        /* Set MB CODE */
        if (cs->code != (uint32_t)FLEXCAN_RX_NOT_USED)
        {
            flexcan_mb_config |= (cs->code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;
            *flexcan_mb = flexcan_mb_config;
        }
    }

    return stat;
}

/*!
 * @brief Get a message buffer field values. 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 get the message buffer field values and copy the MB data field into user's buffer.
 */
void FLEXCAN_GetMsgBuff(/* PRQA S 4700 */
                        CAN_Type *base,
                        uint32_t msgBuffIdx,
                        flexcan_msgbuff_t *msgBuff)
{
    DEV_ASSERT(msgBuff != NULL);

    uint8_t i;

    volatile const uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
    volatile const uint32_t *flexcan_mb_id = &flexcan_mb[1];
    volatile const uint8_t *flexcan_mb_data = (volatile const uint8_t *)(&flexcan_mb[2]);
    volatile const uint32_t *flexcan_mb_data_32 = &flexcan_mb[2];
    uint32_t *msgBuff_data_32 = (uint32_t *)(msgBuff->data); /* PRQA S 0310, 3305 */
    uint32_t mbWord;

    uint8_t flexcan_mb_dlc_value = (uint8_t)(((*flexcan_mb) & CAN_CS_DLC_MASK) >> 16);
    uint8_t payload_size = FLEXCAN_ComputePayloadSize(flexcan_mb_dlc_value);

#if FEATURE_CAN_HAS_FD
    if (payload_size > FLEXCAN_GetPayloadSize(base))
    {
        payload_size = FLEXCAN_GetPayloadSize(base);
    }
#endif /* FEATURE_CAN_HAS_FD */

    msgBuff->dataLen = payload_size;

    /* Get a MB field values */
    msgBuff->cs = *flexcan_mb;

    if ((msgBuff->cs & CAN_CS_IDE_MASK) != 0U)
    {
        msgBuff->msgId = (*flexcan_mb_id);
    }
    else
    {
        msgBuff->msgId = (*flexcan_mb_id) >> CAN_ID_STD_SHIFT;
    }
#if (defined(YTM32B1L_SERIES))
    /* Check if the buffer address is aligned */
    if (((uint32_t)msgBuff_data_32 & 0x3U) != 0U)
    {
        /* Copy MB data field into user's buffer */
        for (i = 0U; i < (payload_size & ~3U); i += 4U)
        {
            mbWord = flexcan_mb_data_32[i >> 2U];
            uint8_t index;
            uint32_t x;
            const uint8_t *p;
            FlexcanSwapBytesInWord(mbWord, x);
            p = (uint8_t *)&x;
            for (index = 0; index < 4U; index++)
            {
                msgBuff->data[i + index] = p[index];
            }
        }
    }
    else
    {
        for (i = 0U; i < (payload_size & ~3U); i += 4U)
        {
            mbWord = flexcan_mb_data_32[i >> 2U]; /* PRQA S 2983 */
            FlexcanSwapBytesInWord(mbWord, msgBuff_data_32[i >> 2U]);
        }
    }
#else
    for (i = 0U; i < (payload_size & ~3U); i += 4U)
    {
        mbWord = flexcan_mb_data_32[i >> 2U]; /* PRQA S 2983 */
        FlexcanSwapBytesInWord(mbWord, msgBuff_data_32[i >> 2U]);
    }
#endif
    for (; i < payload_size; i++)
    { /* Max allowed value for index is 63 */
        msgBuff->data[i] = flexcan_mb_data[FlexcanSwapBytesInWordIndex(i)];
    }
}

/*!
 * @brief Lock the RX message buffer. This function will lock the RX message buffer.
 */
void FLEXCAN_LockRxMsgBuff(CAN_Type *base, uint32_t msgBuffIdx)
{
    volatile const uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);

    /* Lock the mailbox by reading it */
    (void)*flexcan_mb;
}

/*!
 * @brief Enable Rx FIFO feature. This function will enable the Rx FIFO feature.
 */
status_t FLEXCAN_EnableRxFifo(CAN_Type *base, uint32_t numOfFilters)
{
    uint32_t i;
    uint16_t noOfMbx = (uint16_t)FLEXCAN_GetMaxMbNum(base);
    status_t stat = STATUS_SUCCESS;

#if FEATURE_CAN_HAS_FD
    /* RxFIFO cannot be enabled if FD is enabled */
    if (FLEXCAN_IsFDEnabled(base))
    {
        stat = STATUS_ERROR;
    }

    if (stat == STATUS_SUCCESS)
#endif
    {
        /* Enable RX FIFO */
        base->MCR = (base->MCR & ~CAN_MCR_RFEN_MASK) | CAN_MCR_RFEN(1U);
        /* Set the number of the RX FIFO filters needed */
        base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_RFFN_MASK) |
                      ((numOfFilters << CAN_CTRL2_RFFN_SHIFT) & CAN_CTRL2_RFFN_MASK);
        /* RX FIFO global mask, take in consideration all filter fields*/
        (base->RXFGMASK) = CAN_RXFGMASK_FGM_MASK;

        for (i = (uint32_t)0; i < noOfMbx; i++)
        {
            if (i < ((numOfFilters + (uint32_t)1) * (uint32_t)8))
            {
                /* RX fifo individual mask */
                base->RXIMR[i] = CAN_RXIMR_MI_MASK;
            }
            else
            {
                /* RX mb individual mask */
                base->RXIMR[i] = (CAN_RXIMR_MI_MASK << CAN_ID_EXT_SHIFT) & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK);
            }
        }
    }

    return stat;
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
/*!
 * @brief Enable enhanced Rx FIFO feature. This function will enable the enhanced Rx FIFO feature.
 */
status_t FLEXCAN_EnableEnhanceRxFifo(CAN_Type *base, uint32_t numOfFilters, uint32_t numOfExtendedIDFilters)
{
    status_t stat = STATUS_ERROR;
    DEV_ASSERT(base != NULL);
    DEV_ASSERT(numOfFilters < 64U);
    DEV_ASSERT(numOfExtendedIDFilters < 127U);
    if (FLEXCAN_HasEnhanceRxFIFO(base))
    {
        /* Enhance RxFIFO cannot be enabled if legacy RxFIFO is enabled */
        if (FLEXCAN_IsRxFifoEnabled(base))
        {
            stat = STATUS_ERROR;
        }
        else
        {
            /* Enable enhance RX FIFO */
            base->ERFCR = (base->ERFCR & ~CAN_ERFCR_ERFEN_MASK) | CAN_ERFCR_ERFEN(1U);
            /* reset Rx FIFO engine, clear enhanced Rx FIFO content */
            base->ERFSR = (base->ERFSR & ~CAN_ERFSR_ERFCLR_MASK) | CAN_ERFSR_ERFCLR(1U);
            /* clear flags */
            base->ERFSR = (base->ERFSR & ~CAN_ERFSR_ERFUFW_MASK) | CAN_ERFSR_ERFUFW(1U);
            base->ERFSR = (base->ERFSR & ~CAN_ERFSR_ERFOVF_MASK) | CAN_ERFSR_ERFOVF(1U);
            base->ERFSR = (base->ERFSR & ~CAN_ERFSR_ERFWMI_MASK) | CAN_ERFSR_ERFWMI(1U);
            base->ERFSR = (base->ERFSR & ~CAN_ERFSR_ERFDA_MASK) | CAN_ERFSR_ERFDA(1U);
            /* Set the number of the enhance RX FIFO filters needed */
            base->ERFCR = (base->ERFCR & ~CAN_ERFCR_NFE_MASK) |
                          ((numOfFilters << CAN_ERFCR_NFE_SHIFT) & CAN_ERFCR_NFE_MASK);
            /* Set the extended ID filter number of the enhance RX FIFO needed */
            base->ERFCR = (base->ERFCR & ~CAN_ERFCR_NEXIF_MASK) |
                          ((numOfExtendedIDFilters << CAN_ERFCR_NEXIF_SHIFT) & CAN_ERFCR_NEXIF_MASK);
            stat = STATUS_SUCCESS;
        }
    }

    return stat;
}

/*!
 * @brief Set enhanced Rx FIFO watermark value. This function will set the enhanced Rx FIFO watermark value.
 */
status_t FLEXCAN_SetEnhanceRxFifoWatermark(CAN_Type *base, uint32_t watermark)
{
    status_t stat = STATUS_ERROR;
    DEV_ASSERT(base != NULL);
    DEV_ASSERT(watermark < 20U);
    if (FLEXCAN_HasEnhanceRxFIFO(base))
    {
        if (FLEXCAN_IsRxFifoEnabled(base))
        {
            stat = STATUS_ERROR;
        }
        else
        {
            /* Set the enhanced Rx FIFO Watermark */
            base->ERFCR = (base->ERFCR & ~CAN_ERFCR_ERFWM_MASK) |
                          ((watermark << CAN_ERFCR_ERFWM_SHIFT) & CAN_ERFCR_ERFWM_MASK); /* PRQA S 2985 */
            stat = STATUS_SUCCESS;
        }
    }
    return stat;
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

/*!
 * @brief Set the number of the last Message Buffers. This function will define the number of the last Message Buffers
 */
status_t FLEXCAN_SetMaxMsgBuffNum(/* PRQA S 4700 */
                                  CAN_Type *base,
                                  uint32_t maxMsgBuffNum)
{
    uint8_t msgBuffIdx;
    uint32_t databyte;
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
    bool hasEnhanceRxFIFO = false;
    bool isEnhanceRxFifoEnabled = false;
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
    bool isRxFifoEnabled = false;
    DEV_ASSERT(maxMsgBuffNum > 0U);
#if FEATURE_CAN_HAS_FD
    uint8_t can_real_payload = FLEXCAN_GetPayloadSize(base);
#else
    uint8_t can_real_payload = 8U;
#endif
    status_t status = STATUS_SUCCESS;

#if FEATURE_CAN_HAS_FD
    uint8_t arbitration_field_size = 8U;
    /* Check that the number of MBs is supported based on the payload size*/
    volatile uint32_t *valEndMbPointer = FLEXCAN_GetMsgBuffRegion(base, (maxMsgBuffNum - 1U));
    uint32_t valEndMb = (uint32_t)valEndMbPointer + can_real_payload + arbitration_field_size;
    if ((valEndMb > (uint32_t)&base->RAM[FEATURE_CAN_RAM_COUNT]) || (maxMsgBuffNum > FLEXCAN_GetMaxMbNum(base)))
#else
    /* Check that the number of MBs is supported based on features defined */
    if (maxMsgBuffNum > FLEXCAN_GetMaxMbNum(base))
#endif
    {
        status = STATUS_CAN_BUFF_OUT_OF_RANGE;
    }

    if (status == STATUS_SUCCESS)
    {
        /* Set the maximum number of MBs*/
        base->MCR = (base->MCR & ~CAN_MCR_MAXMB_MASK) |
                    (((maxMsgBuffNum - 1U) << CAN_MCR_MAXMB_SHIFT) & CAN_MCR_MAXMB_MASK); /*PRQA S 2985*/
        isRxFifoEnabled = FLEXCAN_IsRxFifoEnabled(base);
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
        hasEnhanceRxFIFO = FLEXCAN_HasEnhanceRxFIFO(base);
        if (hasEnhanceRxFIFO == true)
        {
            isEnhanceRxFifoEnabled = FLEXCAN_IsEnhanceRxFifoEnabled(base);
        }

        if ((hasEnhanceRxFIFO && isEnhanceRxFifoEnabled) ||
            (hasEnhanceRxFIFO && (!isEnhanceRxFifoEnabled) && (!isRxFifoEnabled)) || /*PRQA S 2995*/
            ((!hasEnhanceRxFIFO) && (!isRxFifoEnabled)))
#else
        if (!isRxFifoEnabled)
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
        {
            /* Initialize all message buffers as inactive */
            for (msgBuffIdx = 0; msgBuffIdx < maxMsgBuffNum; msgBuffIdx++)
            {
                volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
                volatile uint32_t *flexcan_mb_id = &flexcan_mb[1];
                volatile uint8_t *flexcan_mb_data = (volatile uint8_t *)(&flexcan_mb[2]);

                *flexcan_mb = 0x0;
                *flexcan_mb_id = 0x0;
                for (databyte = 0; databyte < can_real_payload; databyte++)
                {
                    flexcan_mb_data[databyte] = 0x0;
                }
            }
        }
    }

    return status;
}

/*!
 * @brief Configure RX FIFO ID filter table elements.
 */
void FLEXCAN_SetRxFifoFilter(CAN_Type *base,
                             flexcan_rx_fifo_id_element_format_t idFormat,
                             const flexcan_id_table_t *idFilterTable)
{
    DEV_ASSERT(idFilterTable != NULL);

    /* Set RX FIFO ID filter table elements*/
    uint32_t i, j, numOfFilters;
    uint32_t val1 = 0, val2 = 0, val = 0;

    volatile uint32_t *filterTable = &base->RAM[RxFifoFilterTableOffset];

    numOfFilters = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);

    switch (idFormat)
    {
        case (FLEXCAN_RX_FIFO_ID_FORMAT_A):
            /* One full ID (standard and extended) per ID Filter Table element.*/
            (base->MCR) =
                (((base->MCR) & ~(CAN_MCR_IDAM_MASK)) |
                 ((((uint32_t)(((uint32_t)(FLEXCAN_RX_FIFO_ID_FORMAT_A)) << CAN_MCR_IDAM_SHIFT)) & CAN_MCR_IDAM_MASK)));

            for (i = 0; i < RxFifoFilterElementNum(numOfFilters); i++)
            {
                val = 0;

                if (idFilterTable[i].isRemoteFrame)
                {
                    val = FlexCanRxFifoAcceptRemoteFrame << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_RTR_SHIFT;
                }
                if (idFilterTable[i].isExtendedFrame)
                {
                    val |= FlexCanRxFifoAcceptExtFrame << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_IDE_SHIFT;
                    filterTable[i] = val + ((idFilterTable[i].id << FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_EXT_SHIFT) &
                                            FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_EXT_MASK);
                }
                else
                {
                    filterTable[i] = val + ((idFilterTable[i].id << FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_STD_SHIFT) &
                                            FLEXCAN_RX_FIFO_ID_FILTER_FORMATA_STD_MASK);
                }
            }
            break;
        case (FLEXCAN_RX_FIFO_ID_FORMAT_B):
            /* Two full standard IDs or two partial 14-bit (standard and extended) IDs*/
            /* per ID Filter Table element.*/
            (base->MCR) =
                (((base->MCR) & ~(CAN_MCR_IDAM_MASK)) |
                 ((((uint32_t)(((uint32_t)(FLEXCAN_RX_FIFO_ID_FORMAT_B)) << CAN_MCR_IDAM_SHIFT)) & CAN_MCR_IDAM_MASK)));

            j = 0;
            for (i = 0; i < RxFifoFilterElementNum(numOfFilters); i++)
            {
                val1 = 0;
                val2 = 0;

                if (idFilterTable[j].isRemoteFrame)
                {
                    val1 = FlexCanRxFifoAcceptRemoteFrame << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_RTR_SHIFT;
                }
                if (idFilterTable[j + 1U].isRemoteFrame)
                {
                    val2 = FlexCanRxFifoAcceptRemoteFrame << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_RTR_SHIFT;
                }
                if (idFilterTable[j].isExtendedFrame)
                {
                    val1 |= FlexCanRxFifoAcceptExtFrame << FLEXCAN_RX_FIFO_ID_FILTER_FORMATAB_IDE_SHIFT;

                    filterTable[i] = val1 + (((idFilterTable[j].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_MASK) >>
                                              FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_CMP_SHIFT)
                                             << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1);
                }
                else
                {
                    filterTable[i] = val1 + ((idFilterTable[j].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_STD_MASK)
                                             << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_STD_SHIFT1);
                }
                if (idFilterTable[j + 1U].isExtendedFrame)
                {
                    val2 |= FlexCanRxFifoAcceptExtFrame << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_IDE_SHIFT;

                    filterTable[i] |=
                        val2 + (((idFilterTable[j + 1U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_MASK) >>
                                 FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_CMP_SHIFT)
                                << /* PRQA S 2985 */
                                FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT2);
                }
                else
                {
                    filterTable[i] |= val2 + ((idFilterTable[j + 1U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_STD_MASK)
                                              << FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_STD_SHIFT2);
                }
                j = j + 2U;
            }
            break;
        case (FLEXCAN_RX_FIFO_ID_FORMAT_C):
            /* Four partial 8-bit Standard IDs per ID Filter Table element.*/
            (base->MCR) =
                (((base->MCR) & ~(CAN_MCR_IDAM_MASK)) |
                 ((((uint32_t)(((uint32_t)(FLEXCAN_RX_FIFO_ID_FORMAT_C)) << CAN_MCR_IDAM_SHIFT)) & CAN_MCR_IDAM_MASK)));
            j = 0;
            for (i = 0; i < RxFifoFilterElementNum(numOfFilters); i++)
            {
                if (idFilterTable[j].isExtendedFrame)
                {
                    filterTable[i] |= (((idFilterTable[j].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_CMP_SHIFT)
                                       << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1);
                }
                else
                {
                    filterTable[i] |= (((idFilterTable[j].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_CMP_SHIFT)
                                       << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1);
                }
                if (idFilterTable[j + 1U].isExtendedFrame)
                {
                    filterTable[i] |= (((idFilterTable[j + 1U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_CMP_SHIFT)
                                       << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2);
                }
                else
                {
                    filterTable[i] |= (((idFilterTable[j + 1U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_CMP_SHIFT)
                                       << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2);
                }
                if (idFilterTable[j + 2U].isExtendedFrame)
                {
                    filterTable[i] |= (((idFilterTable[j + 2U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_CMP_SHIFT)
                                       << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3);
                }
                else
                {
                    filterTable[i] |= (((idFilterTable[j + 2U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_CMP_SHIFT)
                                       << FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3);
                }
                if (idFilterTable[j + 3U].isExtendedFrame)
                {
                    filterTable[i] |= (((idFilterTable[j + 3U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_EXT_CMP_SHIFT)
                                       << /* PRQA S 2985 */
                                       FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT4);
                }
                else
                {
                    filterTable[i] |= (((idFilterTable[j + 3U].id & FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_MASK) >>
                                        FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_STD_CMP_SHIFT)
                                       << /* PRQA S 2985 */
                                       FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT4);
                }
                j = j + 4U;
            }
            break;
        case (FLEXCAN_RX_FIFO_ID_FORMAT_D):
            /* All frames rejected.*/
            (base->MCR) =
                (((base->MCR) & ~(CAN_MCR_IDAM_MASK)) |
                 ((((uint32_t)(((uint32_t)(FLEXCAN_RX_FIFO_ID_FORMAT_D)) << CAN_MCR_IDAM_SHIFT)) & CAN_MCR_IDAM_MASK)));
            break;
        default:
            /* Should not get here */
            break;
    }
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
/*!
 * @brief Configure enhanced RX FIFO ID filter table elements.
 */
void FLEXCAN_SetEnchanceRxFifoFilter(CAN_Type *base,
                                     const flexcan_enhance_rx_fifo_filter_table_t *idfilterTable,
                                     uint8_t idfilterTableLength)
{
    DEV_ASSERT(idfilterTable != NULL);

    uint32_t i, j, numOfFilters, numOfExtendedIdFilters, numOfStandardIdFilters, rel_numOfStandardIdFilters;
    const flexcan_enhance_rx_fifo_filter_table_t *idfilterPtr;
    j = 0;
    numOfFilters = (((base->ERFCR) & CAN_ERFCR_NFE_MASK) >> CAN_ERFCR_NFE_SHIFT) + 1U;
    numOfExtendedIdFilters = (((base->ERFCR) & CAN_ERFCR_NEXIF_MASK) >> CAN_ERFCR_NEXIF_SHIFT);
    numOfStandardIdFilters = (numOfFilters - numOfExtendedIdFilters) * 2U;
    rel_numOfStandardIdFilters = (uint32_t)idfilterTableLength - numOfExtendedIdFilters;

    uint32_t *extIdTablePtr, *stdIdTablePtr;
    extIdTablePtr = (uint32_t *)base + (FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_OFFSET / 4U); /* PRQA S 0310, 0488 */
    stdIdTablePtr = (uint32_t *)base + ((FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_OFFSET / 4U) +
                                        (numOfExtendedIdFilters * 2UL)); /* PRQA S 0310, 0488 */

    idfilterPtr = idfilterTable;

    /* Set extended id fliter table */
    for (i = 0U; i < idfilterTableLength; i++)
    {
        if (idfilterPtr->isExtendedFrame)
        {
            *extIdTablePtr = ((*extIdTablePtr) & ~(FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_FSCH_MASK)) |
                             (((uint32_t)(idfilterPtr->filterScheme)
                               << FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_FSCH_SHIFT) & /* PRQA S 2985 */
                              FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_FSCH_MASK);
            *extIdTablePtr = ((*extIdTablePtr) & ~(FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_FILTER_MASK)) |
                             ((idfilterPtr->filter_table.scheme_filter_mask.filter
                               << FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_FILTER_SHIFT) & /* PRQA S 2985 */
                              FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_FILTER_MASK);
            *(extIdTablePtr + 1U) =
                ((*(extIdTablePtr + 1)) & ~(FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_MASK_MASK)) | /* PRQA S 0489 */
                ((idfilterPtr->filter_table.scheme_filter_mask.mask
                  << FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_MASK_SHIFT) & /* PRQA S 2985 */
                 FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_MASK_MASK);
            if (idfilterPtr->isRemoteFrame)
            {
                /* Set RTR mask, set RTR fliter */
                *extIdTablePtr |= FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_RTRFILTER_MASK;
                *(extIdTablePtr + 1U) |= FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_RTRMASK_MASK; /* PRQA S 0489 */
            }
            else
            {
                /* If mask filter mdoe or range filter mode , set RTR mask, if double filter mode, clear RTR filter */
                *(extIdTablePtr) &= ~FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_RTRFILTER_MASK;
                if (FLEXCAN_ENAHNCE_RXFIFO_FSCH_DOUBLE_FILTER != idfilterPtr->filterScheme)
                {
                    *(extIdTablePtr + 1U) |= FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_RTRMASK_MASK; /* PRQA S 0489 */
                }
                else
                {
                    *(extIdTablePtr + 1U) &= ~FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_EXTID_RTRMASK_MASK; /* PRQA S 0489 */
                }
            }
            extIdTablePtr += 2U; /* PRQA S 0488 */
        }
        idfilterPtr++;
    }

    idfilterPtr = idfilterTable;
    /* Set standard id fliter table */
    for (i = 0; i < (numOfExtendedIdFilters + numOfStandardIdFilters); i++)
    {
        if (!idfilterPtr->isExtendedFrame)
        {
            *stdIdTablePtr = ((*stdIdTablePtr) & ~(FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_FSCH_MASK)) |
                             (((uint32_t)(idfilterPtr->filterScheme)
                               << FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_FSCH_SHIFT) & /* PRQA S 2985 */
                              FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_FSCH_MASK);
            *stdIdTablePtr = ((*stdIdTablePtr) & ~(FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_FILTER_MASK)) |
                             ((idfilterPtr->filter_table.scheme_filter_mask.filter
                               << FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_FILTER_SHIFT) &
                              FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_FILTER_MASK);
            *stdIdTablePtr = ((*stdIdTablePtr) & ~(FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_MASK_MASK)) |
                             ((idfilterPtr->filter_table.scheme_filter_mask.mask
                               << FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_MASK_SHIFT) & /* PRQA S 2985 */
                              FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_MASK_MASK);
            if (idfilterPtr->isRemoteFrame)
            {
                /* Set RTR mask, set RTR fliter */
                *stdIdTablePtr |= FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_RTRFILTER_MASK;
                *stdIdTablePtr |= FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_RTRMASK_MASK;
            }
            else
            {
                /* If mask filter mdoe or range filter mode , set RTR mask, if double filter mode, clear RTR filter */
                *stdIdTablePtr &= ~FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_RTRFILTER_MASK;
                if (FLEXCAN_ENAHNCE_RXFIFO_FSCH_DOUBLE_FILTER != idfilterPtr->filterScheme)
                {
                    *stdIdTablePtr |= FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_RTRMASK_MASK;
                }
                else
                {
                    *stdIdTablePtr &= ~FLEXCAN_ENHANCE_RX_FIFO_ERFFEL_STDID_RTRMASK_MASK;
                }
            }
            j++;
            if (j < numOfStandardIdFilters)
            {
                stdIdTablePtr++;
            }
        }
        if (j < rel_numOfStandardIdFilters)
        {
            idfilterPtr++;
        }
    }
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

/*!
 * @brief Enable/Disable the corresponding Message Buffer interrupt.
 */
status_t FLEXCAN_SetMsgBuffIntCmd(CAN_Type *base, uint32_t msgBuffIdx, bool enable)
{
    uint32_t temp;
    status_t stat = STATUS_SUCCESS;

    /* Enable the corresponding message buffer Interrupt */
    INT_SYS_DisableIRQGlobal();
    temp = 1UL << (msgBuffIdx % 32U);
    if (msgBuffIdx < 32U)
    {
        if (enable)
        {
            (base->IMASK1) = ((base->IMASK1) | (temp));
        }
        else
        {
            (base->IMASK1) = ((base->IMASK1) & ~(temp));
        }
    }
#if FEATURE_CAN_MAX_MB_NUM > 32U
    if ((msgBuffIdx >= 32U) && (msgBuffIdx < 64U))
    {
        if (enable)
        {
            (base->IMASK2) = ((base->IMASK2) | (temp));
        }
        else
        {
            (base->IMASK2) = ((base->IMASK2) & ~(temp));
        }
    }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 64U
    if ((msgBuffIdx >= 64U) && (msgBuffIdx < 96U))
    {
        if (enable)
        {
            (base->IMASK3) = ((base->IMASK3) | (temp));
        }
        else
        {
            (base->IMASK3) = ((base->IMASK3) & ~(temp));
        }
    }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 96U
    if (msgBuffIdx >= 96U)
    {
        if (enable)
        {
            (base->IMASK4) = ((base->IMASK4) | (temp));
        }
        else
        {
            (base->IMASK4) = ((base->IMASK4) & ~(temp));
        }
    }
#endif
    INT_SYS_EnableIRQGlobal();
    return stat;
}

/*!
 * @brief Enable the error interrupts. This function will enable Error interrupt.
 */
void FLEXCAN_SetErrIntCmd(CAN_Type *base, flexcan_int_type_t errType, bool enable)
{
    uint32_t temp = (uint32_t)errType;
    if (enable)
    {
        if ((errType == FLEXCAN_INT_RX_WARNING) || (errType == FLEXCAN_INT_TX_WARNING))
        {
            base->MCR = (base->MCR & ~CAN_MCR_WRNEN_MASK) | CAN_MCR_WRNEN(1U);
        }
#if FEATURE_CAN_HAS_FD
        if (errType == FLEXCAN_INT_ERR)
        {
            base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_ERRMSK_FAST_MASK) | CAN_CTRL2_ERRMSK_FAST(1U);
        }
#endif
        (base->CTRL1) = ((base->CTRL1) | (temp));
    }
    else
    {
        (base->CTRL1) = ((base->CTRL1) & ~(temp));
#if FEATURE_CAN_HAS_FD
        if (errType == FLEXCAN_INT_ERR)
        {
            base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_ERRMSK_FAST_MASK) | CAN_CTRL2_ERRMSK_FAST(0U);
        }
#endif
        temp = base->CTRL1;
        if (((temp & (uint32_t)FLEXCAN_INT_RX_WARNING) == 0U) && ((temp & (uint32_t)FLEXCAN_INT_TX_WARNING) == 0U))
        {
            /* If WRNEN disabled then both FLEXCAN_INT_RX_WARNING and FLEXCAN_INT_TX_WARNING will be disabled */
            base->MCR = (base->MCR & ~CAN_MCR_WRNEN_MASK) | CAN_MCR_WRNEN(0U);
        }
    }
}

/*!
 * @brief Exit of freeze mode.
 */
void FLEXCAN_ExitFreezeMode(CAN_Type *base)
{
    base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(0U);
    base->MCR = (base->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(0U);

    /* Wait till exit freeze mode */
    while (((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) != 0U)
    {
    }
}

/*!
 * @brief Enter the freeze mode.
 */
void FLEXCAN_EnterFreezeMode(CAN_Type *base)
{
    bool enabled = false;

    base->MCR = (base->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(1U);
    base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U);
    if (((base->MCR & CAN_MCR_MDIS_MASK) >> CAN_MCR_MDIS_SHIFT) == 0U)
    {
        enabled = true;
    }
    else
    {
        base->MCR &= ~CAN_MCR_MDIS_MASK;
    }
#if defined(ERRATA_E9595)
    /* Check Low-Power Mode Acknowledge Cleared */
    while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 1U)
    {
    }
    /* Check if is a Bus-Off Error corresponding to 1x */
    if ((((base->ESR1 & CAN_ESR1_FLTCONF_MASK) >> CAN_ESR1_FLTCONF_SHIFT) & 2U) != 0U)
    {
        /* Save registers before Soft Reset */
        uint32_t tempIMSK[2], tempMCR;
        tempIMSK[0] = base->IMASK1;
        tempIMSK[1] = base->IMASK2;
        tempMCR = base->MCR;
        /* Soft Reset FlexCan */
        base->MCR |= CAN_MCR_SOFTRST(1U);
        while (((base->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT) != 0U)
        {
        }
        /* Restore registers after Soft Reset */
        base->IMASK1 = tempIMSK[0];
        base->IMASK2 = tempIMSK[1];
        base->MCR = tempMCR;
    }
    else
    {
        base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U);
    }
#endif

    base->TIMER = 0U;
    uint32_t aux = 0U;

#if FEATURE_CAN_HAS_FD
    /* MCR[FDEN] was reset to 0, wait for timeout */
    if (!FLEXCAN_IsFDEnabled(base))
    {
        while (!FLEXCAN_GetFreezeMode(base) && (aux < 180U))
        {
            /* Wait until finish counting 180 bit times and exit*/
            aux = (uint32_t)base->TIMER;
        }
    }
    else
    {
        while (!FLEXCAN_GetFreezeMode(base) && (aux < 730U))
        {
            /* Wait until finish counting 730 bit times and exit*/
            aux = (uint32_t)base->TIMER;
        }
    }
#else
    while (!FLEXCAN_GetFreezeMode(base) && (aux < 180U))
    {
        /* Wait until finish counting 180 bit times and exit*/
        aux = (uint32_t)base->TIMER;
    }
#endif /* FEATURE_CAN_HAS_FD */

    if (((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) == 0U)
    {
        /* Save registers before Soft Reset */
        uint32_t tempIMSK1, tempMCR;

        /* Save IMASK1 value */
        tempIMSK1 = base->IMASK1;

#if FEATURE_CAN_MAX_MB_NUM > 32U
        uint32_t tempIMSK2 = 0U;

        if (FLEXCAN_GetMaxMbNum(base) > 32U)
        {
            /* Save IMASK2 value */
            tempIMSK2 = base->IMASK2;
        }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 64U
        uint32_t tempIMSK3 = 0U;

        if (FLEXCAN_GetMaxMbNum(base) > 64U)
        {
            /* Save IMASK3 value */
            tempIMSK3 = base->IMASK3;
        }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 96U
        uint32_t tempIMSK4 = 0U;

        if (FLEXCAN_GetMaxMbNum(base) > 96U)
        {
            /* Save IMASK4 value */
            tempIMSK4 = base->IMASK4;
        }
#endif
        /* Save MCR value */
        tempMCR = base->MCR;

        /* Soft Reset FlexCan */
        base->MCR |= CAN_MCR_SOFTRST(1U);
        while (((base->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT) != 0U)
        {
        }

        /* Restore IMASK1 value */
        base->IMASK1 = tempIMSK1;

#if FEATURE_CAN_MAX_MB_NUM > 32U
        if (FLEXCAN_GetMaxMbNum(base) > 32U)
        {
            /* Restore IMASK2 value */
            base->IMASK2 = tempIMSK2;
        }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 64U
        if (FLEXCAN_GetMaxMbNum(base) > 64U)
        {
            /* Restore IMASK3 value */
            base->IMASK3 = tempIMSK3;
        }
#endif
#if FEATURE_CAN_MAX_MB_NUM > 96U
        if (FLEXCAN_GetMaxMbNum(base) > 96U)
        {
            /* Restore IMASK3 value */
            base->IMASK4 = tempIMSK4;
        }
#endif

        /* Restore MCR value */
        base->MCR = tempMCR;
    }

    if (false == enabled)
    {
        base->MCR |= CAN_MCR_MDIS_MASK;
        /* Wait until disable mode acknowledged */
        while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 0U)
        {
        }
    }
}

/*!
 * @brief Clear all error interrupt status.
 */
void FLEXCAN_ClearErrIntStatusFlag(CAN_Type *base)
{
    if ((base->ESR1 & FLEXCAN_ALL_INT) != 0U)
    {
#if (defined(YTM32B1L_SERIES))
        (base->ESR1) = FLEXCAN_ALL_INT;
#else
        (base->ESR1) = ERROR_INT;
#endif
#ifdef ERRATA_ARM_838869
        /* Dummy read as a workaround for errata e9005 to ensure the flags are
        cleared before continuing. */
        (void)(base->ESR1);
#endif
    }
}

/*!
 * @brief Clear all busOff and Tx/Rx Warning interrupt status.
 */
void FLEXCAN_ClearBusOffIntStatusFlag(CAN_Type *base)
{
    if ((base->ESR1 & BUS_OFF_INT) != 0U)
    {
        base->ESR1 = BUS_OFF_INT;
#ifdef ERRATA_ARM_838869
        (void)(base->ESR1);
#endif
    }
}

/*!
 * @brief Read Rx FIFO data. This function will copy MB[0] data field into user's buffer.
 */
void FLEXCAN_ReadRxFifo(/* PRQA S 4700 */
                        const CAN_Type *base,
                        flexcan_msgbuff_t *rxFifo)
{
    DEV_ASSERT(rxFifo != NULL);

    uint32_t databyte;
    uint32_t mbWord;

    volatile const uint32_t *flexcan_mb = base->RAM;
    volatile const uint32_t *flexcan_mb_id = &base->RAM[1];
    volatile const uint32_t *flexcan_mb_data_32 = &flexcan_mb[2];
    uint32_t *msgData_32 = (uint32_t *)(rxFifo->data); /* PRQA S 0310, 3305 */

    uint8_t flexcan_mb_dlc_value = (uint8_t)(((*flexcan_mb) & CAN_CS_DLC_MASK) >> 16);
    uint8_t can_real_payload = FLEXCAN_ComputePayloadSize(flexcan_mb_dlc_value);

    /* For legacy Rx FIFO, the payload size cannot exceed 8 bytes */
    if (can_real_payload > 8U)
    {
        can_real_payload = 8U;
    }

    rxFifo->dataLen = can_real_payload;
    rxFifo->cs = *flexcan_mb;

    if ((rxFifo->cs & CAN_CS_IDE_MASK) != 0U)
    {
        rxFifo->msgId = *flexcan_mb_id;
    }
    else
    {
        rxFifo->msgId = (*flexcan_mb_id) >> CAN_ID_STD_SHIFT;
    }
#if (defined(YTM32B1L_SERIES))
    /* Check if the buffer address is aligned */
    if (((uint32_t)msgData_32 & 0x3U) != 0U)
    {
        /* Copy MB[0] data field into user's buffer */
        for (databyte = 0U; databyte < can_real_payload; databyte += 4U)
        {
            mbWord = flexcan_mb_data_32[databyte >> 2U];
            uint32_t x;
            uint8_t index;
            const uint8_t *p;
            FlexcanSwapBytesInWord(mbWord, x);
            p = (uint8_t *)&x;
            for (index = 0U; index < 4U; index++)
            {
                rxFifo->data[databyte + index] = p[index];
            }
        }
    }
    else
    {
        /* Copy MB[0] data field into user's buffer */
        for (databyte = 0U; databyte < can_real_payload; databyte += 4U)
        {
            mbWord = flexcan_mb_data_32[databyte >> 2U]; /* PRQA S 2983 */
            FlexcanSwapBytesInWord(mbWord, msgData_32[databyte >> 2U]);
        }
    }
#else
    /* Copy MB[0] data field into user's buffer */
    for (databyte = 0U; databyte < can_real_payload; databyte += 4U)
    {
        mbWord = flexcan_mb_data_32[databyte >> 2U]; /* PRQA S 2983 */
        FlexcanSwapBytesInWord(mbWord, msgData_32[databyte >> 2U]);
    }
#endif
}

#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
/*!
 * @brief Read enhanced Rx FIFO data. This function will copy enhanded Rx FIFO data field into user's buffer.
 */
void FLEXCAN_ReadEnhanceRxFifo(/* PRQA S 4700 */
                               const CAN_Type *base,
                               flexcan_msgbuff_t *rxFifo)
{
    DEV_ASSERT(rxFifo != NULL);

    uint32_t databyte;
    uint32_t mbWord;

    volatile const uint32_t *enhanceFifoData =
        (uint32_t *)base + (FLEXCAN_ENHANCE_RX_FIFO_DATA_REGION_OFFSET / 4U); /* PRQA S 0310, 0311, 3305, 0488 */
    volatile const uint32_t *msgId = (enhanceFifoData + 1U);                  /* PRQA S 0488, 0489 */
    volatile const uint32_t *msgData = (enhanceFifoData + 2U);                /* PRQA S 0488, 0489 */
    uint8_t enhanceFifoMsgDLC =
        (uint8_t)(((*enhanceFifoData) & FLEXCAN_ENHANCE_RX_FIFO_DLC_MASK) >> FLEXCAN_ENHANCE_RX_FIFO_DLC_SHIFT);
    uint8_t realDataLength = FLEXCAN_ComputePayloadSize(enhanceFifoMsgDLC);
    uint32_t *msgData_32 = (uint32_t *)(rxFifo->data); /* PRQA S 0310, 3305 */

    rxFifo->dataLen = realDataLength;
    rxFifo->cs = *enhanceFifoData;
    /* Get message ID */
    if ((rxFifo->cs & FLEXCAN_ENHANCE_RX_FIFO_IDE_MASK) != 0U)
    {
        rxFifo->msgId = *msgId;
    }
    else
    {
        rxFifo->msgId = (*msgId) >> CAN_ID_STD_SHIFT;
    }

    /* Copy MB[0] data field into user's buffer */
    for (databyte = 0U; databyte < realDataLength; databyte += 4U)
    {
        mbWord = msgData[databyte >> 2U]; /* PRQA S 2983 */
        FlexcanSwapBytesInWord(mbWord, msgData_32[databyte >> 2U]);
    }
}
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */

/*!
 * @brief Enable a FlexCAN operation mode. This function will enable one of the modes listed in flexcan_operation_modes_t.
 */
void FLEXCAN_SetOperationMode(CAN_Type *base, flexcan_operation_modes_t mode)
{
    switch (mode)
    {
        case FLEXCAN_FREEZE_MODE:
            /* Debug mode, Halt and Freeze*/
            FLEXCAN_EnterFreezeMode(base);
            break;
        case FLEXCAN_DISABLE_MODE:
            /* Debug mode, Halt and Freeze */
            base->MCR = (base->MCR & ~CAN_MCR_MDIS_MASK) | CAN_MCR_MDIS(1U);
            break;
        case FLEXCAN_NORMAL_MODE:
            base->MCR = (base->MCR & ~CAN_MCR_SUPV_MASK) | CAN_MCR_SUPV(0U);
            base->CTRL1 = (base->CTRL1 & ~CAN_CTRL1_LOM_MASK) | CAN_CTRL1_LOM(0U);
            base->CTRL1 = (base->CTRL1 & ~CAN_CTRL1_LPB_MASK) | CAN_CTRL1_LPB(0U);
            break;
        case FLEXCAN_LISTEN_ONLY_MODE:
            base->CTRL1 = (base->CTRL1 & ~CAN_CTRL1_LOM_MASK) | CAN_CTRL1_LOM(1U);
            break;
        case FLEXCAN_LOOPBACK_MODE:
            base->CTRL1 = (base->CTRL1 & ~CAN_CTRL1_LPB_MASK) | CAN_CTRL1_LPB(1U);
            base->CTRL1 = (base->CTRL1 & ~CAN_CTRL1_LOM_MASK) | CAN_CTRL1_LOM(0U);
            /* Enable Self Reception */
            FLEXCAN_SetSelfReception(base, true);
            break;
        default:
            /* Should not get here */
            break;
    }
}

/*!
 * @brief Returns True if selected Message Buffer index is out of range.
 */
bool FLEXCAN_IsOutOfRangeMbIdx(const CAN_Type *base, uint32_t msgBuffIdx) /* PRQA S 4700 */
{
    bool resultval = false;
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
    bool hasEnhanceRxFIFO = false;
    bool isEnhanceRxFifoEnabled = false;
#endif
    /* Check if the MB index is in range */
    if (msgBuffIdx > (((base->MCR) & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT))
    {
        resultval = true;
    }
    else
    {
        /* Check if RX FIFO is enabled*/
        if (FLEXCAN_IsRxFifoEnabled(base) == true)
        {
#if FEATURE_CAN_HAS_ENHANCE_RX_FIFO
            hasEnhanceRxFIFO = FLEXCAN_HasEnhanceRxFIFO(base);
            if (hasEnhanceRxFIFO == true)
            {
                isEnhanceRxFifoEnabled = FLEXCAN_IsEnhanceRxFifoEnabled(base);
            }
            if (hasEnhanceRxFIFO && (!isEnhanceRxFifoEnabled))
#endif /* FEATURE_CAN_HAS_ENHANCE_RX_FIFO */
            {
                uint32_t val1 = 0U, val2 = 0U;
                /* Get the number of RX FIFO Filters*/
                val1 = (((uint32_t)(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 (msgBuffIdx <= val2)
                {
                    resultval = true;
                }
            }
        }
    }
    return resultval;
}

#if FEATURE_CAN_HAS_FD
/*!
 * @brief Sets the payload size of the MBs.
 */
void FLEXCAN_SetPayloadSize(CAN_Type *base, flexcan_fd_payload_size_t payloadSize)
{
    uint32_t tmp;

    DEV_ASSERT(FLEXCAN_IsFDEnabled(base) || (payloadSize == FLEXCAN_PAYLOAD_SIZE_8));

    /* If FD is not enabled, only 8 bytes payload is supported */
    if (FLEXCAN_IsFDEnabled(base))
    {
        tmp = base->FDCTRL;
        tmp &= ~(CAN_FDCTRL_MBDSR0_MASK);
        tmp |= ((uint32_t)payloadSize) << CAN_FDCTRL_MBDSR0_SHIFT;
#if FEATURE_CAN_HAS_MBDSR1
        tmp &= ~(CAN_FDCTRL_MBDSR1_MASK);
        tmp |= ((uint32_t)payloadSize) << CAN_FDCTRL_MBDSR1_SHIFT;
#endif
#if FEATURE_CAN_HAS_MBDSR2
        tmp &= ~(CAN_FDCTRL_MBDSR2_MASK);
        tmp |= ((uint32_t)payloadSize) << CAN_FDCTRL_MBDSR2_SHIFT;
#endif
#if defined(FEATURE_CAN_HAS_MBDSR3) && (FEATURE_CAN_HAS_MBDSR3 == 1)
        tmp &= ~(CAN_FDCTRL_MBDSR3_MASK);
        tmp |= ((uint32_t)payloadSize) << CAN_FDCTRL_MBDSR3_SHIFT;
#endif
        base->FDCTRL = tmp;
    }
}

/*!
 * @brief Returns the payload size of the MBs (in bytes).
 */
uint8_t FLEXCAN_GetPayloadSize(const CAN_Type *base)
{
    uint32_t payloadSize;

    /* The standard payload size is 8 bytes */
    if (!FLEXCAN_IsFDEnabled(base))
    {
        payloadSize = 8U;
    }
    else
    {
        payloadSize = 1UL << (((base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT) + 3U);
    }

    return (uint8_t)payloadSize;
}
#endif /* End FEATURE_CAN_HAS_FD */

#if FEATURE_CAN_HAS_PRETENDED_NETWORKING

/*!
 * @brief Configures the Pretended Networking mode.
 */
void FLEXCAN_ConfigPN(CAN_Type *base, const flexcan_pn_config_t *pnConfig)
{
    DEV_ASSERT(pnConfig != NULL);

    /* Configure specific pretended networking settings */
    FLEXCAN_SetPNFilteringSelection(base,
                                    pnConfig->wakeUpTimeout,
                                    pnConfig->wakeUpMatch,
                                    pnConfig->numMatches,
                                    pnConfig->filterComb,
                                    pnConfig->idFilterType,
                                    pnConfig->payloadFilterType);

    FLEXCAN_SetPNTimeoutValue(base, pnConfig->matchTimeout);

    /* Configure ID filtering */
    FLEXCAN_SetPNIdFilter1(base, pnConfig->idFilter1);

    /* Configure the second ID, if needed (as mask for exact matching or higher limit for range matching) */
    if ((pnConfig->idFilterType == FLEXCAN_FILTER_MATCH_EXACT) ||
        (pnConfig->idFilterType == FLEXCAN_FILTER_MATCH_RANGE))
    {
        FLEXCAN_SetPNIdFilter2(base, pnConfig);
    }
    else
    {
        /* In other case need only to check the IDE and RTR match the ID_MASK is not considered */
        FLEXCAN_SetPNIdFilter2Check(base);
    }

    /* Configure payload filtering, if requested */
    if ((pnConfig->filterComb == FLEXCAN_FILTER_ID_PAYLOAD) ||
        (pnConfig->filterComb == FLEXCAN_FILTER_ID_PAYLOAD_NTIMES))
    {
        FLEXCAN_SetPNDlcFilter(base, pnConfig->payloadFilter.dlcLow, pnConfig->payloadFilter.dlcHigh);

        FLEXCAN_SetPNPayloadHighFilter1(base, pnConfig->payloadFilter.payload1);
        FLEXCAN_SetPNPayloadLowFilter1(base, pnConfig->payloadFilter.payload1);

        /* Configure the second payload, if needed (as mask for exact matching or higher limit for range matching) */
        if ((pnConfig->payloadFilterType == FLEXCAN_FILTER_MATCH_EXACT) ||
            (pnConfig->payloadFilterType == FLEXCAN_FILTER_MATCH_RANGE))
        {
            FLEXCAN_SetPNPayloadHighFilter2(base, pnConfig->payloadFilter.payload2);
            FLEXCAN_SetPNPayloadLowFilter2(base, pnConfig->payloadFilter.payload2);
        }
    }
}

#endif /* FEATURE_CAN_HAS_PRETENDED_NETWORKING */

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