/**
*     Copyright (c) 2023, Nations Technologies Inc.
* 
*     All rights reserved.
*
*     This software is the exclusive property of Nations Technologies Inc. (Hereinafter 
* referred to as NATIONS). This software, and the product of NATIONS described herein 
* (Hereinafter referred to as the Product) are owned by NATIONS under the laws and treaties
* of the People's Republic of China and other applicable jurisdictions worldwide.
*
*     NATIONS does not grant any license under its patents, copyrights, trademarks, or other 
* intellectual property rights. Names and brands of third party may be mentioned or referred 
* thereto (if any) for identification purposes only.
*
*     NATIONS reserves the right to make changes, corrections, enhancements, modifications, and 
* improvements to this software at any time without notice. Please contact NATIONS and obtain 
* the latest version of this software before placing orders.

*     Although NATIONS has attempted to provide accurate and reliable information, NATIONS assumes 
* no responsibility for the accuracy and reliability of this software.
* 
*     It is the responsibility of the user of this software to properly design, program, and test 
* the functionality and safety of any application made of this information and any resulting product. 
* In no event shall NATIONS be liable for any direct, indirect, incidental, special,exemplary, or 
* consequential damages arising in any way out of the use of this software or the Product.
*
*     NATIONS Products are neither intended nor warranted for usage in systems or equipment, any
* malfunction or failure of which may cause loss of human life, bodily injury or severe property 
* damage. Such applications are deemed, "Insecure Usage".
*
*     All Insecure Usage shall be made at user's risk. User shall indemnify NATIONS and hold NATIONS 
* harmless from and against all claims, costs, damages, and other liabilities, arising from or related 
* to any customer's Insecure Usage.

*     Any express or implied warranty with regard to this software or the Product, including,but not 
* limited to, the warranties of merchantability, fitness for a particular purpose and non-infringement
* are disclaimed to the fullest extent permitted by law.

*     Unless otherwise explicitly permitted by NATIONS, anyone may not duplicate, modify, transcribe
* or otherwise distribute this software for any purposes, in whole or in part.
*
*     NATIONS products and technologies shall not be used for or incorporated into any products or systems
* whose manufacture, use, or sale is prohibited under any applicable domestic or foreign laws or regulations. 
* User shall comply with any applicable export control laws and regulations promulgated and administered by 
* the governments of any countries asserting jurisdiction over the parties or transactions.
**/

/**
*\*\file n32a052_can.c
*\*\author Nations
*\*\version v1.0.0
*\*\copyright Copyright (c) 2023, Nations Technologies Inc. All rights reserved.
**/

#include "n32a052_can.h"
#include "n32a052_rcc.h"

/** CAN Private Defines **/

static INTStatus CheckINTStatus(uint32_t CAN_Reg, uint32_t Int_Bit);

/** CAN Driving Functions Declaration **/

/**
*\*\name    CAN_DeInit
*\*\fun     Deinitializes the CAN peripheral registers to their default reset values.
*\*\param   CANx:
*\*\             - CAN
*\*\return  none
**/
void CAN_DeInit(CAN_Module* CANx)
{
    RCC_EnableAPB1PeriphReset(RCC_APB1_PERIPH_CAN);
}


/**
*\*\name   CAN_Init
*\*\fun    Initializes the CAN peripheral according to the specified
*\*\       parameters in the CAN_initializes_parameter.
*\*\param  CANx:
*\*\            - CAN
*\*\param  CAN_InitParam (The input parameters must be the following values) :
*\*\            - BaudRatePrescaler
*\*\                - It ranges from 1 to 1024.
*\*\            - OperatingMode
*\*\                - CAN_Normal_Mode
*\*\                - CAN_LoopBack_Mode
*\*\                - CAN_Silent_Mode
*\*\                - CAN_Silent_LoopBack_Mode
*\*\            - RSJW
*\*\                - CAN_RSJW_1tq
*\*\                - CAN_RSJW_2tq
*\*\                - CAN_RSJW_3tq
*\*\                - CAN_RSJW_4tq
*\*\            - TBS1
*\*\                - CAN_TBS1_1tq
*\*\                - CAN_TBS1_2tq
*\*\                - CAN_TBS1_3tq
*\*\                - CAN_TBS1_4tq
*\*\                - CAN_TBS1_5tq
*\*\                - CAN_TBS1_6tq
*\*\                - CAN_TBS1_7tq
*\*\                - CAN_TBS1_8tq
*\*\                - CAN_TBS1_9tq
*\*\                - CAN_TBS1_10tq
*\*\                - CAN_TBS1_11tq
*\*\                - CAN_TBS1_12tq
*\*\                - CAN_TBS1_13tq
*\*\                - CAN_TBS1_14tq
*\*\                - CAN_TBS1_15tq
*\*\                - CAN_TBS1_16tq
*\*\            - TBS2
*\*\                - CAN_TBS2_1tq
*\*\                - CAN_TBS2_2tq
*\*\                - CAN_TBS2_3tq
*\*\                - CAN_TBS2_4tq
*\*\                - CAN_TBS2_5tq
*\*\                - CAN_TBS2_6tq
*\*\                - CAN_TBS2_7tq
*\*\                - CAN_TBS2_8tq
*\*\            - TTCM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - ABOM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - AWKUM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - NART
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - RFLM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - TXFP
*\*\                - DISABLE
*\*\                - ENABLE           
*\*\return InitStatus :
*\*\            - CAN_InitSTS_Failed
*\*\            - CAN_InitSTS_Success
**/
uint8_t CAN_Init(CAN_Module* CANx, CAN_InitType* CAN_InitParam)
{
    uint8_t InitStatus;
    uint32_t wait_ack  = 0x00000000;

    /* Exit from sleep mode */
    CANx->MCTRL &= (~(uint32_t)CAN_MCTRL_SLPRQ);

    /* Request initialisation */
    CANx->MCTRL |= CAN_MCTRL_INIRQ;

    /* Wait the acknowledge */
    while (((CANx->MSTS & CAN_MSTS_INIAK) != CAN_MSTS_INIAK) && (wait_ack != INIAK_TIMEOUT))
    {
        wait_ack++;
    }

    /* Check acknowledge */
    if ((CANx->MSTS & CAN_MSTS_INIAK) != CAN_MSTS_INIAK)
    {
        InitStatus = CAN_InitSTS_Failed;
    }
    else
    {
        /* Set the time triggered communication mode */
        if (CAN_InitParam->TTCM == ENABLE)
        {
            CANx->MCTRL |= CAN_MCTRL_TTCM;
        }
        else
        {
            CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_TTCM;
        }

        /* Set the automatic bus-off management */
        if (CAN_InitParam->ABOM == ENABLE)
        {
            CANx->MCTRL |= CAN_MCTRL_ABOM;
        }
        else
        {
            CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_ABOM;
        }

        /* Set the automatic wake-up mode */
        if (CAN_InitParam->AWKUM == ENABLE)
        {
            CANx->MCTRL |= CAN_MCTRL_AWKUM;
        }
        else
        {
            CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_AWKUM;
        }

        /* Set the no automatic retransmission */
        if (CAN_InitParam->NART == ENABLE)
        {
            CANx->MCTRL |= CAN_MCTRL_NART;
        }
        else
        {
            CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_NART;
        }

        /* Set the receive DATFIFO locked mode */
        if (CAN_InitParam->RFLM == ENABLE)
        {
            CANx->MCTRL |= CAN_MCTRL_RFLM;
        }
        else
        {
            CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_RFLM;
        }

        /* Set the transmit DATFIFO priority */
        if (CAN_InitParam->TXFP == ENABLE)
        {
            CANx->MCTRL |= CAN_MCTRL_TXFP;
        }
        else
        {
            CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_TXFP;
        }

        /* Set the bit timing register */
        CANx->BTIM = (uint32_t)((uint32_t)CAN_InitParam->OperatingMode << 30) | ((uint32_t)CAN_InitParam->RSJW << 24)
                    | ((uint32_t)CAN_InitParam->TBS1 << 16) | ((uint32_t)CAN_InitParam->TBS2 << 20)
                    | ((uint32_t)CAN_InitParam->BaudRatePrescaler - (uint32_t)0x1);

        /* Request leave initialisation */
        CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_INIRQ;

        /* Wait the acknowledge */
        wait_ack = 0;

        while (((CANx->MSTS & CAN_MSTS_INIAK) == CAN_MSTS_INIAK) && (wait_ack != INIAK_TIMEOUT))
        {
            wait_ack++;
        }

        /* ...and check acknowledged */
        if ((CANx->MSTS & CAN_MSTS_INIAK) == CAN_MSTS_INIAK)
        {
            InitStatus = CAN_InitSTS_Failed;
        }
        else
        {
            InitStatus = CAN_InitSTS_Success;
        }
    }

    /* At this step, return the status of initialization */
    return InitStatus;
}


/**
*\*\name   CAN_InitFilter
*\*\fun    Initializes the CAN peripheral according to the specified
*\*\       parameters in the CAN_filter_initializes_structure.
*\*\param  CAN_InitFilterStruct (The input parameters must be the following values) :
*\*\            - Filter_HighId
*\*\                - It ranges from 0x0000 to 0xFFFF
*\*\            - Filter_LowId
*\*\                - It ranges from 0x0000 to 0xFFFF
*\*\            - FilterMask_HighId
*\*\                - It ranges from 0x0000 to 0xFFFF
*\*\            - FilterMask_LowId
*\*\                - It ranges from 0x0000 to 0xFFFF
*\*\            - Filter_FIFOAssignment
*\*\                - CAN_Filter_FIFO0
*\*\                - CAN_Filter_FIFO1
*\*\            - Filter_Num
*\*\                - It ranges from 0 to 13
*\*\            - Filter_Mode
*\*\                - CAN_Filter_IdMaskMode
*\*\                - CAN_Filter_IdListMode
*\*\            - Filter_Scale
*\*\                - CAN_Filter_16bitScale
*\*\                - CAN_Filter_32bitScale
*\*\            - Filter_Act
*\*\                - ENABLE
*\*\                - DISABLE
*\*\return none
**/
void CAN_InitFilter(CAN_FilterInitType* CAN_InitFilterStruct)
{
    uint32_t filter_number_bit_pos;

    filter_number_bit_pos = ((uint32_t)1) << CAN_InitFilterStruct->Filter_Num;

    /* Initialisation mode for the filter */
    CAN->FMC |= FMC_FINITM;

    /* Filter Deactivation */
    CAN->FA1 &= ~(uint32_t)filter_number_bit_pos;

    /* Filter Scale */
    if (CAN_InitFilterStruct->Filter_Scale == CAN_Filter_16bitScale)
    {
        /* 16-bit scale for the filter */
        CAN->FS1 &= ~(uint32_t)filter_number_bit_pos;

        /* First 16-bit identifier and First 16-bit mask */
        /* Or First 16-bit identifier and Second 16-bit identifier */
        CAN->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR1 =
            (((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_LowId) << 16)
            | ((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_LowId);

        /* Second 16-bit identifier and Second 16-bit mask */
        /* Or Third 16-bit identifier and Fourth 16-bit identifier */
        CAN->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR2 =
            (((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_HighId) << 16)
            | ((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_HighId);
    }

    if (CAN_InitFilterStruct->Filter_Scale == CAN_Filter_32bitScale)
    {
        /* 32-bit scale for the filter */
        CAN->FS1 |= filter_number_bit_pos;
        /* 32-bit identifier or First 32-bit identifier */
        CAN->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR1 =
            (((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_HighId) << 16)
            | ((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_LowId);
        /* 32-bit mask or Second 32-bit identifier */
        CAN->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR2 =
            (((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_HighId) << 16)
            | ((uint32_t)0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_LowId);
    }

    /* Filter Mode */
    if (CAN_InitFilterStruct->Filter_Mode == CAN_Filter_IdMaskMode)
    {
        /*Id/Mask mode for the filter*/
        CAN->FM1 &= ~(uint32_t)filter_number_bit_pos;
    }
    else /* CAN_InitFilterStruct->Filter_Mode == CAN_Filter_IdListMode */
    {
        /*Identifier list mode for the filter*/
        CAN->FM1 |= (uint32_t)filter_number_bit_pos;
    }

    /* Filter DATFIFO assignment */
    if (CAN_InitFilterStruct->Filter_FIFOAssignment == CAN_Filter_FIFO0)
    {
        /* DATFIFO 0 assignation for the filter */
        CAN->FFA1 &= ~(uint32_t)filter_number_bit_pos;
    }

    if (CAN_InitFilterStruct->Filter_FIFOAssignment == CAN_Filter_FIFO1)
    {
        /* DATFIFO 1 assignation for the filter */
        CAN->FFA1 |= (uint32_t)filter_number_bit_pos;
    }

    /* Filter activation */
    if (CAN_InitFilterStruct->Filter_Act == ENABLE)
    {
        CAN->FA1 |= filter_number_bit_pos;
    }

    /* Leave the initialisation mode for the filter */
    CAN->FMC &= ~FMC_FINITM;
}

/**
*\*\name   CAN_InitStruct
*\*\fun    Fills each CAN_initializes_parameter member with its default value.
*\*\param  CAN_InitParam (The input parameters must be the following values) :
*\*\            - BaudRatePrescaler
*\*\                - It ranges from 1 to 1024.
*\*\            - OperatingMode
*\*\                - CAN_Normal_Mode
*\*\                - CAN_LoopBack_Mode
*\*\                - CAN_Silent_Mode
*\*\                - CAN_Silent_LoopBack_Mode
*\*\            - RSJW
*\*\                - CAN_RSJW_1tq
*\*\                - CAN_RSJW_2tq
*\*\                - CAN_RSJW_3tq
*\*\                - CAN_RSJW_4tq
*\*\            - TBS1
*\*\                - CAN_TBS1_1tq
*\*\                - CAN_TBS1_2tq
*\*\                - CAN_TBS1_3tq
*\*\                - CAN_TBS1_4tq
*\*\                - CAN_TBS1_5tq
*\*\                - CAN_TBS1_6tq
*\*\                - CAN_TBS1_7tq
*\*\                - CAN_TBS1_8tq
*\*\                - CAN_TBS1_9tq
*\*\                - CAN_TBS1_10tq
*\*\                - CAN_TBS1_11tq
*\*\                - CAN_TBS1_12tq
*\*\                - CAN_TBS1_13tq
*\*\                - CAN_TBS1_14tq
*\*\                - CAN_TBS1_15tq
*\*\                - CAN_TBS1_16tq
*\*\            - TBS2
*\*\                - CAN_TBS2_1tq
*\*\                - CAN_TBS2_2tq
*\*\                - CAN_TBS2_3tq
*\*\                - CAN_TBS2_4tq
*\*\                - CAN_TBS2_5tq
*\*\                - CAN_TBS2_6tq
*\*\                - CAN_TBS2_7tq
*\*\                - CAN_TBS2_8tq
*\*\            - TTCM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - ABOM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - AWKUM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - NART
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - RFLM
*\*\                - DISABLE
*\*\                - ENABLE
*\*\            - TXFP
*\*\                - DISABLE
*\*\                - ENABLE 
*\*\return none
**/
void CAN_InitStruct(CAN_InitType* CAN_InitParam)
{
    /* Reset CAN init structure parameters values */

    /* Initialize the time triggered communication mode */
    CAN_InitParam->TTCM = DISABLE;

    /* Initialize the automatic bus-off management */
    CAN_InitParam->ABOM = DISABLE;

    /* Initialize the automatic wake-up mode */
    CAN_InitParam->AWKUM = DISABLE;

    /* Initialize the no automatic retransmission */
    CAN_InitParam->NART = DISABLE;

    /* Initialize the receive DATFIFO locked mode */
    CAN_InitParam->RFLM = DISABLE;

    /* Initialize the transmit DATFIFO priority */
    CAN_InitParam->TXFP = DISABLE;

    /* Initialize the OperatingMode member */
    CAN_InitParam->OperatingMode = CAN_Normal_Mode;

    /* Initialize the RSJW member */
    CAN_InitParam->RSJW = CAN_RSJW_1tq;

    /* Initialize the TBS1 member */
    CAN_InitParam->TBS1 = CAN_TBS1_4tq;

    /* Initialize the TBS2 member */
    CAN_InitParam->TBS2 = CAN_TBS2_3tq;

    /* Initialize the BaudRatePrescaler member */
    CAN_InitParam->BaudRatePrescaler = 1;
}

/**
*\*\name   CAN_DebugFreeze
*\*\fun    Enables the DBG Freeze for CAN.
*\*\param  CANx:
*\*\            - CAN
*\*\param  Cmd (The input parameters must be the following values):
*\*\            - DISABLE
*\*\            - ENABLE
*\*\return none
**/
void CAN_DebugFreeze(CAN_Module* CANx, FunctionalState Cmd)
{
    if (Cmd != DISABLE)
    {
        /* Enable Debug Freeze  */
        CANx->MCTRL |= MCTRL_DBGF;
    }
    else
    {
        /* Disable Debug Freeze */
        CANx->MCTRL &= ~MCTRL_DBGF;
    }
}

/**
*\*\name   CAN_EnTTComMode
*\*\fun    Enables the CAN Time stamp sent.
*\*\param  CANx:
*\*\            - CAN
*\*\param  Cmd (The input parameters must be the following values):
*\*\            - DISABLE
*\*\            - ENABLE
*\*\note   when enabled, Time stamp (TIME[15:0]) value is sent in the last
*\*\       two data bytes of the 8-byte message: TIME[7:0] in data byte 6
*\*\       and TIME[15:8] in data byte 7
*\*\note   DLC must be programmed as 8 in order Time Stamp (2 bytes) to be
*\*\       sent over the CAN bus.
*\*\return none
**/
void CAN_EnTTComMode(CAN_Module* CANx, FunctionalState Cmd)
{
    if (Cmd != DISABLE)
    {
        /* Enable the TTCM mode */
        CANx->MCTRL |= CAN_MCTRL_TTCM;

        /* Set TGT bits */
        CANx->sTxMailBox[0].TMDT |= ((uint32_t)CAN_TMDT0_TGT);
        CANx->sTxMailBox[1].TMDT |= ((uint32_t)CAN_TMDT1_TGT);
        CANx->sTxMailBox[2].TMDT |= ((uint32_t)CAN_TMDT2_TGT);
    }
    else
    {
        /* Disable the TTCM mode */
        CANx->MCTRL &= (uint32_t)(~(uint32_t)CAN_MCTRL_TTCM);

        /* Reset TGT bits */
        CANx->sTxMailBox[0].TMDT &= ((uint32_t)~CAN_TMDT0_TGT);
        CANx->sTxMailBox[1].TMDT &= ((uint32_t)~CAN_TMDT1_TGT);
        CANx->sTxMailBox[2].TMDT &= ((uint32_t)~CAN_TMDT2_TGT);
    }
}


/**
*\*\name   CAN_TransmitMessage
*\*\fun    initialize the transmission of a message.
*\*\param  CANx:
*\*\            - CAN
*\*\param  TxMessage  (The input parameters must be the following values):
*\*\            - StdId
*\*\                - It ranges from 0 to 0x7FF
*\*\            - ExtId
*\*\                - It ranges from 0 to 0x1FFFFFFF
*\*\            - IDE
*\*\                - CAN_Standard_Id
*\*\                - CAN_Extended_Id
*\*\            - RTR
*\*\                - CAN_RTRQ_Data
*\*\                - CAN_RTRQ_Remote
*\*\            - DLC
*\*\                - It ranges from 0 to 8
*\*\            - Data[0-7]
*\*\                - It ranges from 0 to 0xFF
*\*\return  transmit_mailbox (The input parameters must be the following values) :
*\*\            - CAN_TXMAILBOX_0
*\*\            - CAN_TXMAILBOX_1
*\*\            - CAN_TXMAILBOX_2
*\*\            - CAN_TxSTS_NoMailBox
**/
uint8_t CAN_TransmitMessage(CAN_Module* CANx, CanTxMessage* TxMessage)
{
    uint8_t transmit_mailbox;

    /* Select one empty transmit mailbox */
    if ((CANx->TSTS & CAN_TSTS_TMEM0) == CAN_TSTS_TMEM0)
    {
        transmit_mailbox = 0;
    }
    else if ((CANx->TSTS & CAN_TSTS_TMEM1) == CAN_TSTS_TMEM1)
    {
        transmit_mailbox = 1;
    }
    else if ((CANx->TSTS & CAN_TSTS_TMEM2) == CAN_TSTS_TMEM2)
    {
        transmit_mailbox = 2;
    }
    else
    {
        transmit_mailbox = CAN_TxSTS_NoMailBox;
    }

    if (transmit_mailbox != CAN_TxSTS_NoMailBox)
    {
        /* Set up the Id */
        CANx->sTxMailBox[transmit_mailbox].TMI &= TMIDxR_TXRQ;
        if (TxMessage->IDE == CAN_Standard_Id)
        {
            CANx->sTxMailBox[transmit_mailbox].TMI |= ((TxMessage->StdId << 21) | TxMessage->RTR);
        }
        else
        {
            CANx->sTxMailBox[transmit_mailbox].TMI |= ((TxMessage->ExtId << 3) | TxMessage->IDE | TxMessage->RTR);
        }

        /* Set up the DLC */
        TxMessage->DLC &= (uint8_t)0x0000000F;
        CANx->sTxMailBox[transmit_mailbox].TMDT &= (uint32_t)0xFFFFFFF0U;
        CANx->sTxMailBox[transmit_mailbox].TMDT |= TxMessage->DLC;

        /* Set up the data field */
        CANx->sTxMailBox[transmit_mailbox].TMDL =
            (((uint32_t)TxMessage->Data[3] << 24) | ((uint32_t)TxMessage->Data[2] << 16)
             | ((uint32_t)TxMessage->Data[1] << 8) | ((uint32_t)TxMessage->Data[0]));
        CANx->sTxMailBox[transmit_mailbox].TMDH =
            (((uint32_t)TxMessage->Data[7] << 24) | ((uint32_t)TxMessage->Data[6] << 16)
             | ((uint32_t)TxMessage->Data[5] << 8) | ((uint32_t)TxMessage->Data[4]));
        /* Request transmission */
        CANx->sTxMailBox[transmit_mailbox].TMI |= TMIDxR_TXRQ;
    }
    return transmit_mailbox;
}

/**
*\*\name   CAN_TransmitSTS
*\*\fun    Checks the transmission of a message.
*\*\param  CANx:
*\*\            - CAN
*\*\param  mailbox_queue (The input parameters must be the following values) :
*\*\            - CAN_TXMAILBOX_0
*\*\            - CAN_TXMAILBOX_1
*\*\            - CAN_TXMAILBOX_2
*\*\return state :
*\*\            - CAN_TxSTS_Failed
*\*\            - CAN_TxSTS_Ok
*\*\            - CAN_TxSTS_Pending
**/
uint8_t CAN_TransmitSTS(const CAN_Module* CANx, uint8_t TransmitMailbox)
{
    uint32_t state;

    switch (TransmitMailbox)
    {
    case (CAN_TXMAILBOX_0):
        state = CANx->TSTS & (CAN_TSTS_RQCPM0 | CAN_TSTS_TXOKM0 | CAN_TSTS_TMEM0);
        break;
    case (CAN_TXMAILBOX_1):
        state = CANx->TSTS & (CAN_TSTS_RQCPM1 | CAN_TSTS_TXOKM1 | CAN_TSTS_TMEM1);
        break;
    case (CAN_TXMAILBOX_2):
        state = CANx->TSTS & (CAN_TSTS_RQCPM2 | CAN_TSTS_TXOKM2 | CAN_TSTS_TMEM2);
        break;
    default:
        state = (uint32_t)CAN_TxSTS_Failed;
        break;
    }
    switch (state)
    {
        /* transmit pending  */
    case (0x0):
        state = (uint32_t)CAN_TxSTS_Pending;
        break;
        /* transmit failed  */
    case (CAN_TSTS_RQCPM0 | CAN_TSTS_TMEM0):
        state = (uint32_t)CAN_TxSTS_Failed;
        break;
    case (CAN_TSTS_RQCPM1 | CAN_TSTS_TMEM1):
        state = (uint32_t)CAN_TxSTS_Failed;
        break;
    case (CAN_TSTS_RQCPM2 | CAN_TSTS_TMEM2):
        state = (uint32_t)CAN_TxSTS_Failed;
        break;
        /* transmit succeeded  */
    case (CAN_TSTS_RQCPM0 | CAN_TSTS_TXOKM0 | CAN_TSTS_TMEM0):
        state = (uint32_t)CAN_TxSTS_Ok;
        break;
    case (CAN_TSTS_RQCPM1 | CAN_TSTS_TXOKM1 | CAN_TSTS_TMEM1):
        state = (uint32_t)CAN_TxSTS_Ok;
        break;
    case (CAN_TSTS_RQCPM2 | CAN_TSTS_TXOKM2 | CAN_TSTS_TMEM2):
        state = (uint32_t)CAN_TxSTS_Ok;
        break;
    default:
        state = (uint32_t)CAN_TxSTS_Failed;
        break;
    }
    return (uint8_t)state;
}


/**
*\*\name   CAN_CancelTransmitMessage
*\*\brief  Cancels a transmit request.
*\*\param  CANx:
*\*\            - CAN
*\*\param  Mailbox (The input parameters must be the following values) :
*\*\            - CAN_TXMAILBOX_0
*\*\            - CAN_TXMAILBOX_1
*\*\            - CAN_TXMAILBOX_2
*\*\return none
**/
void CAN_CancelTransmitMessage(CAN_Module* CANx, uint8_t Mailbox)
{
    /* abort transmission */
    switch (Mailbox)
    {
    case (CAN_TXMAILBOX_0):
        CANx->TSTS |= CAN_TSTS_ABRQM0;
        break;
    case (CAN_TXMAILBOX_1):
        CANx->TSTS |= CAN_TSTS_ABRQM1;
        break;
    case (CAN_TXMAILBOX_2):
        CANx->TSTS |= CAN_TSTS_ABRQM2;
        break;
    default:
        break;
    }
}

/**
*\*\name   CAN_ReceiveMessage
*\*\fun    Receives a message.
*\*\param  CANx:
*\*\            - CAN
*\*\param  FIFONum (The input parameters must be the following values) :
*\*\            - CAN_FIFO0
*\*\            - CAN_FIFO1
*\*\param  RxMessage (The input parameters must be the following values) :
*\*\            - StdId
*\*\                - It ranges from 0 to 0x7FF
*\*\            - ExtId
*\*\                - It ranges from 0 to 0x1FFFFFFF
*\*\            - IDE
*\*\                - CAN_Standard_Id
*\*\                - CAN_Extended_Id
*\*\            - RTR
*\*\                - CAN_RTRQ_Data
*\*\                - CAN_RTRQ_Remote
*\*\            - DLC
*\*\                - It ranges from 0 to 8
*\*\            - Data[0-7]
*\*\                - It ranges from 0 to 0xFF
*\*\            - FMI
*\*\                - It ranges from 0 to 0xFF
*\*\return none
**/
void CAN_ReceiveMessage(CAN_Module* CANx, uint8_t FIFONum, CanRxMessage* RxMessage)
{
    /* Get the Id */
    RxMessage->IDE = (uint8_t)(CAN_RMIx_IDE & CANx->sFIFOMailBox[FIFONum].RMI);
    if (RxMessage->IDE == CAN_Standard_Id)
    {
        RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONum].RMI >> 21);
    }
    else
    {
        RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONum].RMI >> 3);
    }

    RxMessage->RTR = (uint8_t)(CAN_RMIx_RTRQ & CANx->sFIFOMailBox[FIFONum].RMI);
    /* Get the DLC */
    RxMessage->DLC = (uint8_t)(CAN_TMDTx_DLC & CANx->sFIFOMailBox[FIFONum].RMDT);
    /* Get the FMI */
    RxMessage->FMI = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDT >> 8));
    /* Get the data field */
    RxMessage->Data[0] = (uint8_t)(CAN_DATA_FIFO_MASK & CANx->sFIFOMailBox[FIFONum].RMDL);
    RxMessage->Data[1] = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDL >> 8));
    RxMessage->Data[2] = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDL >> 16));
    RxMessage->Data[3] = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDL >> 24));
    RxMessage->Data[4] = (uint8_t)(CAN_DATA_FIFO_MASK & CANx->sFIFOMailBox[FIFONum].RMDH);
    RxMessage->Data[5] = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDH >> 8));
    RxMessage->Data[6] = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDH >> 16));
    RxMessage->Data[7] = (uint8_t)(CAN_DATA_FIFO_MASK & (CANx->sFIFOMailBox[FIFONum].RMDH >> 24));
    /* Release the DATFIFO */
    /* Release FIFO0 */
    if (FIFONum == CAN_FIFO0)
    {
        CANx->RFF0 |= CAN_RFF0_RFFOM0;
    }
    /* Release FIFO1 */
    else /* FIFONum == CAN_FIFO1 */
    {
        CANx->RFF1 |= CAN_RFF1_RFFOM1;
    }
}

/**
*\*\name   CAN_ReleaseFIFO
*\*\fun    Releases the specified DATAFIFO.
*\*\param  CANx:
*\*\            - CAN
*\*\param  FIFONum (The input parameters must be the following values) :
*\*\            - CAN_FIFO0
*\*\            - CAN_FIFO1
*\*\return none
**/
void CAN_ReleaseFIFO(CAN_Module* CANx, uint8_t FIFONum)
{
    /* Release FIFO0 */
    if (FIFONum == CAN_FIFO0)
    {
        CANx->RFF0 |= CAN_RFF0_RFFOM0;
    }
    /* Release FIFO1 */
    else /* FIFONum == CAN_FIFO1 */
    {
        CANx->RFF1 |= CAN_RFF1_RFFOM1;
    }
}

/**
*\*\name   CAN_PendingMessage
*\*\fun    Returns the number of pending messages.
*\*\param  CANx :
*\*\            - CAN
*\*\param  FIFONum (The input parameters must be the following values) :
*\*\            - CAN_FIFO0
*\*\            - CAN_FIFO1
*\*\return message_pending : 
*\*\            - CAN_FIFOX_PENDING_0
*\*\            - CAN_FIFOX_PENDING_1
*\*\            - CAN_FIFOX_PENDING_2
*\*\            - CAN_FIFOX_PENDING_3
**/
uint8_t CAN_PendingMessage(const CAN_Module* CANx, uint8_t FIFONum)
{
    uint8_t message_pending;

    if (FIFONum == CAN_FIFO0)
    {
        message_pending = (uint8_t)(CANx->RFF0 & (uint32_t)0x03);
    }
    else if (FIFONum == CAN_FIFO1)
    {
        message_pending = (uint8_t)(CANx->RFF1 & (uint32_t)0x03);
    }
    else
    {
        message_pending = 0;
    }
    return message_pending;
}

/**
*\*\name   CAN_OperatingModeReq
*\*\fun    Select the CAN Operation mode.
*\*\param  CANx:
*\*\            - CAN
*\*\param  CAN_OperatingMode (The input parameters must be the following values) :
*\*\               - CAN_Operating_InitMode
*\*\               - CAN_Operating_NormalMode
*\*\               - CAN_Operating_SleepMode
*\*\return status :
*\*\               - CAN_ModeSTS_Failed    CAN failed entering the specific mode
*\*\               - CAN_ModeSTS_Success   CAN Succeed entering the specific mode
**/
uint8_t CAN_OperatingModeReq(CAN_Module* CANx, uint8_t CAN_OperatingMode)
{
    uint8_t status;

    /* Timeout for INAK or also for SLAK bits*/
    uint32_t timeout = INIAK_TIMEOUT;

    if (CAN_OperatingMode == CAN_Operating_InitMode)
    {
        /* Request initialisation */
        CANx->MCTRL = (uint32_t)((CANx->MCTRL & (uint32_t)(~(uint32_t)CAN_MCTRL_SLPRQ)) | CAN_MCTRL_INIRQ);

        /* Wait the acknowledge */
        while (((CANx->MSTS & CAN_MODE_MASK) != CAN_MSTS_INIAK) && (timeout != (uint32_t)0))
        {
            timeout--;
        }
        if ((CANx->MSTS & CAN_MODE_MASK) != CAN_MSTS_INIAK)
        {
            status = CAN_ModeSTS_Failed;
        }
        else
        {
            status = CAN_ModeSTS_Success;
        }
    }
    else if (CAN_OperatingMode == CAN_Operating_NormalMode)
    {
        /* Request leave initialisation and sleep mode  and enter Normal mode */
        CANx->MCTRL &= (uint32_t)(~(CAN_MCTRL_SLPRQ | CAN_MCTRL_INIRQ));

        /* Wait the acknowledge */
        while (((CANx->MSTS & CAN_MODE_MASK) != (uint32_t)0) && (timeout != (uint32_t)0))
        {
            timeout--;
        }
        if ((CANx->MSTS & CAN_MODE_MASK) != (uint32_t)0)
        {
            status = CAN_ModeSTS_Failed;
        }
        else
        {
            status = CAN_ModeSTS_Success;
        }
    }
    else if (CAN_OperatingMode == CAN_Operating_SleepMode)
    {
        /* Request Sleep mode */
        CANx->MCTRL = (uint32_t)((CANx->MCTRL & (uint32_t)(~(uint32_t)CAN_MCTRL_INIRQ)) | CAN_MCTRL_SLPRQ);

        /* Wait the acknowledge */
        while (((CANx->MSTS & CAN_MODE_MASK) != CAN_MSTS_SLPAK) && (timeout != (uint32_t)0))
        {
            timeout--;
        }
        if ((CANx->MSTS & CAN_MODE_MASK) != CAN_MSTS_SLPAK)
        {
            status = CAN_ModeSTS_Failed;
        }
        else
        {
            status = CAN_ModeSTS_Success;
        }
    }
    else
    {
        status = CAN_ModeSTS_Failed;
    }

    return (uint8_t)status;
}

/**
*\*\name   CAN_EnterSleep
*\*\fun    Enters sleep mode.
*\*\param  CANx:
*\*\            - CAN
*\*\return sleepstatus: 
*\*\            - CAN_SLEEP_Ok
*\*\            - CAN_SLEEP_Failed
**/
uint8_t CAN_EnterSleep(CAN_Module* CANx)
{
    uint8_t sleepstatus = CAN_SLEEP_Failed;

    /* Request Sleep mode */
    CANx->MCTRL = (((CANx->MCTRL) & (uint32_t)(~(uint32_t)CAN_MCTRL_INIRQ)) | CAN_MCTRL_SLPRQ);

    /* Sleep mode status */
    if ((CANx->MSTS & (CAN_MSTS_SLPAK | CAN_MSTS_INIAK)) == CAN_MSTS_SLPAK)
    {
        /* Sleep mode entered */
        sleepstatus = CAN_SLEEP_Ok;
    }
    /* return sleep mode status */
    return (uint8_t)sleepstatus;
}

/**
*\*\name   CAN_WakeUp
*\*\fun    Wakes the CAN up.
*\*\param  CANx:
*\*\            - CAN
*\*\return CAN_Status: 
*\*\            - CAN_WKU_Ok
*\*\            - CAN_WKU_Failed
**/
uint8_t CAN_WakeUp(CAN_Module* CANx)
{
    uint32_t wait_slak   = SLPAK_TIMEOUT;
    uint8_t wakeupstatus = CAN_WKU_Failed;

    /* Wake up request */
    CANx->MCTRL &= ~(uint32_t)CAN_MCTRL_SLPRQ;

    /* Sleep mode status */
    while (((CANx->MSTS & CAN_MSTS_SLPAK) == CAN_MSTS_SLPAK) && (wait_slak != (uint32_t)0x00))
    {
        wait_slak--;
    }
    if ((CANx->MSTS & CAN_MSTS_SLPAK) != CAN_MSTS_SLPAK)
    {
        /* wake up done : Sleep mode exited */
        wakeupstatus = CAN_WKU_Ok;
    }
    /* return wakeup status */
    return (uint8_t)wakeupstatus;
}

/**
*\*\name   CAN_GetLastErrCode
*\*\fun    Returns the CANx's last error code (LEC).
*\*\param  CANx:
*\*\            - CAN
*\*\return errorcode :
*\*\            - CAN_ERRORCODE_NoErr            No Error
*\*\            - CAN_ERRORCODE_StuffErr         Stuff Error
*\*\            - CAN_ERRORCODE_FormErr          Form Error
*\*\            - CAN_ERRORCODE_ACKErr           Acknowledgment Error
*\*\            - CAN_ERRORCODE_BitRecessiveErr  Bit Recessive Error
*\*\            - CAN_ERRORCODE_BitDominantErr   Bit Dominant Error
*\*\            - CAN_ERRORCODE_CRCErr           CRC Error
*\*\            - CAN_ERRORCODE_SoftwareSetErr   Software Set Error
**/
uint8_t CAN_GetLastErrCode(const CAN_Module* CANx)
{
    uint8_t errorcode;

    /* Get the error code*/
    errorcode = (((uint8_t)CANx->ESTS) & (uint8_t)CAN_ESTS_LEC);

    /* Return the error code*/
    return errorcode;
}

/**
*\*\name   CAN_GetReceiveErrCounter
*\*\fun    Returns the CANx Receive Error Counter (REC).
*\*\param  CANx:
*\*\            - CAN
*\*\return counter_value:
*\*\            - It ranges from 0 to 127
*\*\note   In case of an error during reception, this counter is incremented
*\*\       by 1 or by 8 depending on the error condition as defined by the CAN
*\*\       standard. After every successful reception, the counter is
*\*\       decremented by 1 or reset to 120 if its value was higher than 128.
*\*\       When the counter value exceeds 127, the CAN controller enters the
*\*\       error passive state.
**/
uint8_t CAN_GetReceiveErrCounter(const CAN_Module* CANx)
{
    uint8_t counter;

    /* Get the Receive Error Counter*/
    counter = (uint8_t)((CANx->ESTS & CAN_ESTS_RXEC) >> 24);

    /* Return the Receive Error Counter*/
    return counter;
}

/**
*\*\name   CAN_GetLSBTransmitErrCounter
*\*\fun    Returns the LSB of the 9-bit CANx Transmit Error Counter(TEC).
*\*\param  CAN to to select the CAN peripheral.
*\*\return counter_value:
*\*\            - It ranges from 0 to 127
**/
uint8_t CAN_GetLSBTransmitErrCounter(const CAN_Module* CANx)
{
    uint8_t counter;

    /* Get the LSB of the 9-bit CANx Transmit Error Counter(TEC) */
    counter = (uint8_t)((CANx->ESTS & CAN_ESTS_TXEC) >> 16);

    /* Return the LSB of the 9-bit CANx Transmit Error Counter(TEC) */
    return counter;
}

/**
*\*\name   CAN_INTConfig
*\*\fun    Enables the specified CANx interrupts.
*\*\param  CANx:
*\*\               - CAN
*\*\param  CAN_INT (The input parameters must be the following values) :
*\*\               - CAN_INT_TME,
*\*\               - CAN_INT_FMP0,
*\*\               - CAN_INT_FF0,
*\*\               - CAN_INT_FOV0,
*\*\               - CAN_INT_FMP1,
*\*\               - CAN_INT_FF1,
*\*\               - CAN_INT_FOV1,
*\*\               - CAN_INT_EWG,
*\*\               - CAN_INT_EPV,
*\*\               - CAN_INT_BOF,
*\*\               - CAN_INT_LEC,
*\*\               - CAN_INT_ERR,
*\*\               - CAN_INT_WKU,
*\*\               - CAN_INT_SLK.
*\*\param  Cmd :
*\*\               - DISABLE
*\*\               - ENABLE
*\*\return none
**/
void CAN_INTConfig(CAN_Module* CANx, uint32_t CAN_INT, FunctionalState Cmd)
{
    if (Cmd != DISABLE)
    {
        /* Enable the selected CANx interrupt */
        CANx->INTE |= CAN_INT;
    }
    else
    {
        /* Disable the selected CANx interrupt */
        CANx->INTE &= ~CAN_INT;
    }
}


/**
*\*\name   CAN_GetFlagSTS
*\*\fun    Checks whether the specified CAN flag is set or not.
*\*\param  CANx:
*\*\                - CAN
*\*\param  CAN_flag (The input parameters must be the following values) :
*\*\                - CAN_FLAG_EWGFL
*\*\                - CAN_FLAG_EPVFL
*\*\                - CAN_FLAG_BOFFL
*\*\                - CAN_FLAG_LEC
*\*\                - CAN_FLAG_RQCPM0
*\*\                - CAN_FLAG_RQCPM1
*\*\                - CAN_FLAG_RQCPM2
*\*\                - CAN_FLAG_FFMP1
*\*\                - CAN_FLAG_FFULL1
*\*\                - CAN_FLAG_FFOVR1
*\*\                - CAN_FLAG_FFMP0
*\*\                - CAN_FLAG_FFULL0
*\*\                - CAN_FLAG_FFOVR0
*\*\                - CAN_FLAG_WKU
*\*\                - CAN_FLAG_SLAK
*\*\return  FlagStatus:
*\*\                - SET
*\*\                - RESET
**/
FlagStatus CAN_GetFlagSTS(const CAN_Module* CANx, uint32_t CAN_FLAG)
{
    FlagStatus bitstatus;

    if ((CAN_FLAG & CAN_FLAGS_ESTS) != (uint32_t)RESET)
    {
        /* Check the status of the specified CAN flag */
        if ((CANx->ESTS & (CAN_FLAG & CAN_FLAG_MASK)) != (uint32_t)RESET)
        {
            /* CAN_FLAG is set */
            bitstatus = SET;
        }
        else
        {
            /* CAN_FLAG is reset */
            bitstatus = RESET;
        }
    }
    else if ((CAN_FLAG & CAN_FLAGS_MSTS) != (uint32_t)RESET)
    {
        /* Check the status of the specified CAN flag */
        if ((CANx->MSTS & (CAN_FLAG & CAN_FLAG_MASK)) != (uint32_t)RESET)
        {
            /* CAN_FLAG is set */
            bitstatus = SET;
        }
        else
        {
            /* CAN_FLAG is reset */
            bitstatus = RESET;
        }
    }
    else if ((CAN_FLAG & CAN_FLAGS_TSTS) != (uint32_t)RESET)
    {
        /* Check the status of the specified CAN flag */
        if ((CANx->TSTS & (CAN_FLAG & CAN_FLAG_MASK)) != (uint32_t)RESET)
        {
            /* CAN_FLAG is set */
            bitstatus = SET;
        }
        else
        {
            /* CAN_FLAG is reset */
            bitstatus = RESET;
        }
    }
    else if ((CAN_FLAG & CAN_FLAGS_RFF0) != (uint32_t)RESET)
    {
        /* Check the status of the specified CAN flag */
        if ((CANx->RFF0 & (CAN_FLAG & CAN_FLAG_MASK)) != (uint32_t)RESET)
        {
            /* CAN_FLAG is set */
            bitstatus = SET;
        }
        else
        {
            /* CAN_FLAG is reset */
            bitstatus = RESET;
        }
    }
    else /* If(CAN_FLAG & CAN_FLAGS_RFF1 != (uint32_t)RESET) */
    {
        /* Check the status of the specified CAN flag */
        if ((uint32_t)(CANx->RFF1 & (CAN_FLAG & CAN_FLAG_MASK)) != (uint32_t)RESET)
        {
            /* CAN_FLAG is set */
            bitstatus = SET;
        }
        else
        {
            /* CAN_FLAG is reset */
            bitstatus = RESET;
        }
    }
    /* Return the CAN_FLAG status */
    return bitstatus;
}

/**
*\*\name   CAN_ClearFlag
*\*\fun    Clears the CAN's flag status.
*\*\param  CANx:
*\*\                  - CAN
*\*\param  CAN_flag :
*\*\                  - CAN_FLAG_RQCPM0
*\*\                  - CAN_FLAG_RQCPM1
*\*\                  - CAN_FLAG_RQCPM2
*\*\                  - CAN_FLAG_FFULL1
*\*\                  - CAN_FLAG_FFOVR1
*\*\                  - CAN_FLAG_FFULL0
*\*\                  - CAN_FLAG_FFOVR0
*\*\                  - CAN_FLAG_WKU
*\*\                  - CAN_FLAG_SLAK
*\*\                  - CAN_FLAG_LEC
*\*\return none
**/
void CAN_ClearFlag(CAN_Module* CANx, uint32_t CAN_FLAG)
{
    uint32_t flagtmp;

    if (CAN_FLAG == CAN_FLAG_LEC) /* ESTS register */
    {
        /* Clear the selected CAN flags */
        CANx->ESTS = (uint32_t)RESET;
    }
    else /* MSTS or TSTS or RFF0 or RFF1 */
    {
        flagtmp = CAN_FLAG & CAN_FLAG_MASK;

        if ((CAN_FLAG & CAN_FLAGS_RFF0) != (uint32_t)RESET)
        {
            /* Receive Flags */
            CANx->RFF0 = (uint32_t)(flagtmp);
        }
        else if ((CAN_FLAG & CAN_FLAGS_RFF1) != (uint32_t)RESET)
        {
            /* Receive Flags */
            CANx->RFF1 = (uint32_t)(flagtmp);
        }
        else if ((CAN_FLAG & CAN_FLAGS_TSTS) != (uint32_t)RESET)
        {
            /* Transmit Flags */
            CANx->TSTS = (uint32_t)(flagtmp);
        }
        else /* If((CAN_FLAG & CAN_FLAGS_MSTS)!=(uint32_t)RESET) */
        {
            /* Operating mode Flags */
            CANx->MSTS = (uint32_t)(flagtmp);
        }
    }
}

/**
*\*\name   CAN_GetIntStatus
*\*\fun    Checks whether the specified CANx interrupt has occurred or not.
*\*\param  CANx:
*\*\                    -  CAN
*\*\param  CAN_interrupt (The input parameters must be the following values) :
*\*\                    -  CAN_INT_TME
*\*\                    -  CAN_INT_FMP0
*\*\                    -  CAN_INT_FF0
*\*\                    -  CAN_INT_FOV0
*\*\                    -  CAN_INT_FMP1
*\*\                    -  CAN_INT_FF1
*\*\                    -  CAN_INT_FOV1
*\*\                    -  CAN_INT_WKU
*\*\                    -  CAN_INT_SLK
*\*\                    -  CAN_INT_EWG
*\*\                    -  CAN_INT_EPV
*\*\                    -  CAN_INT_BOF
*\*\                    -  CAN_INT_LEC
*\*\                    -  CAN_INT_ERR
*\*\return INTStatus : 
*\*\                    - SET
*\*\                    - RESET
**/
INTStatus CAN_GetIntStatus(const CAN_Module* CANx, uint32_t CAN_INT)
{
    INTStatus itstatus;

    /* check the enable interrupt bit */
    if ((CANx->INTE & CAN_INT) != (uint32_t)RESET)
    {
        /* in case the Interrupt is enabled, .... */
        switch (CAN_INT)
        {
        case CAN_INT_TME:
            /* Check CAN_TSTS_RQCPx bits */
            itstatus = CheckINTStatus(CANx->TSTS, CAN_TSTS_RQCPM0 | CAN_TSTS_RQCPM1 | CAN_TSTS_RQCPM2);
            break;
        case CAN_INT_FMP0:
            /* Check CAN_RFF0_FFMP0 bit */
            itstatus = CheckINTStatus(CANx->RFF0, CAN_RFF0_FFMP0);
            break;
        case CAN_INT_FF0:
            /* Check CAN_RFF0_FFULL0 bit */
            itstatus = CheckINTStatus(CANx->RFF0, CAN_RFF0_FFULL0);
            break;
        case CAN_INT_FOV0:
            /* Check CAN_RFF0_FFOVR0 bit */
            itstatus = CheckINTStatus(CANx->RFF0, CAN_RFF0_FFOVR0);
            break;
        case CAN_INT_FMP1:
            /* Check CAN_RFF1_FFMP1 bit */
            itstatus = CheckINTStatus(CANx->RFF1, CAN_RFF1_FFMP1);
            break;
        case CAN_INT_FF1:
            /* Check CAN_RFF1_FFULL1 bit */
            itstatus = CheckINTStatus(CANx->RFF1, CAN_RFF1_FFULL1);
            break;
        case CAN_INT_FOV1:
            /* Check CAN_RFF1_FFOVR1 bit */
            itstatus = CheckINTStatus(CANx->RFF1, CAN_RFF1_FFOVR1);
            break;
        case CAN_INT_WKU:
            /* Check CAN_MSTS_WKUINT bit */
            itstatus = CheckINTStatus(CANx->MSTS, CAN_MSTS_WKUINT);
            break;
        case CAN_INT_SLK:
            /* Check CAN_MSTS_SLAKINT bit */
            itstatus = CheckINTStatus(CANx->MSTS, CAN_MSTS_SLAKINT);
            break;
        case CAN_INT_EWG:
            /* Check CAN_ESTS_EWGFL bit */
            itstatus = CheckINTStatus(CANx->ESTS, CAN_ESTS_EWGFL);
            break;
        case CAN_INT_EPV:
            /* Check CAN_ESTS_EPVFL bit */
            itstatus = CheckINTStatus(CANx->ESTS, CAN_ESTS_EPVFL);
            break;
        case CAN_INT_BOF:
            /* Check CAN_ESTS_BOFFL bit */
            itstatus = CheckINTStatus(CANx->ESTS, CAN_ESTS_BOFFL);
            break;
        case CAN_INT_LEC:
            /* Check CAN_ESTS_LEC bit */
            itstatus = CheckINTStatus(CANx->ESTS, CAN_ESTS_LEC);
            break;
        case CAN_INT_ERR:
            /* Check CAN_MSTS_ERRINT bit */
            itstatus = CheckINTStatus(CANx->MSTS, CAN_MSTS_ERRINT);
            break;
        default:
            /* in case of error, return RESET */
            itstatus = RESET;
            break;
        }
    }
    else
    {
        /* in case the Interrupt is not enabled, return RESET */
        itstatus = RESET;
    }

    /* Return the CAN_INT status */
    return itstatus;
}

/**
*\*\name   CAN_ClearINTPendingBit
*\*\fun    Clears the CANx's interrupt status.
*\*\param  CANx:
*\*\                -  CAN
*\*\param  CAN_interrupt (The input parameters must be the following values) :
*\*\                -  CAN_INT_TME
*\*\                -  CAN_INT_FF0
*\*\                -  CAN_INT_FOV0
*\*\                -  CAN_INT_FF1
*\*\                -  CAN_INT_FOV1
*\*\                -  CAN_INT_WKU
*\*\                -  CAN_INT_SLK
*\*\                -  CAN_INT_EWG
*\*\                -  CAN_INT_EPV
*\*\                -  CAN_INT_BOF
*\*\                -  CAN_INT_LEC
*\*\                -  CAN_INT_ERR
*\*\return none
**/
void CAN_ClearINTPendingBit(CAN_Module* CANx, uint32_t CAN_INT)
{
    switch (CAN_INT)
    {
    case CAN_INT_TME:
        /* Clear CAN_TSTS_RQCPx (rc_w1)*/
        CANx->TSTS = CAN_TSTS_RQCPM0 | CAN_TSTS_RQCPM1 | CAN_TSTS_RQCPM2;
        break;
    case CAN_INT_FF0:
        /* Clear CAN_RFF0_FFULL0 (rc_w1)*/
        CANx->RFF0 = CAN_RFF0_FFULL0;
        break;
    case CAN_INT_FOV0:
        /* Clear CAN_RFF0_FFOVR0 (rc_w1)*/
        CANx->RFF0 = CAN_RFF0_FFOVR0;
        break;
    case CAN_INT_FF1:
        /* Clear CAN_RFF1_FFULL1 (rc_w1)*/
        CANx->RFF1 = CAN_RFF1_FFULL1;
        break;
    case CAN_INT_FOV1:
        /* Clear CAN_RFF1_FFOVR1 (rc_w1)*/
        CANx->RFF1 = CAN_RFF1_FFOVR1;
        break;
    case CAN_INT_WKU:
        /* Clear CAN_MSTS_WKUINT (rc_w1)*/
        CANx->MSTS = CAN_MSTS_WKUINT;
        break;
    case CAN_INT_SLK:
        /* Clear CAN_MSTS_SLAKINT (rc_w1)*/
        CANx->MSTS = CAN_MSTS_SLAKINT;
        break;
    case CAN_INT_EWG:
        /* Clear CAN_MSTS_ERRINT (rc_w1) */
        CANx->MSTS = CAN_MSTS_ERRINT;
        /* Note : the corresponding Flag is cleared by hardware depending
                  of the CAN Bus status*/
        break;
    case CAN_INT_EPV:
        /* Clear CAN_MSTS_ERRINT (rc_w1) */
        CANx->MSTS = CAN_MSTS_ERRINT;
        /* Note : the corresponding Flag is cleared by hardware depending
                  of the CAN Bus status*/
        break;
    case CAN_INT_BOF:
        /* Clear CAN_MSTS_ERRINT (rc_w1) */
        CANx->MSTS = CAN_MSTS_ERRINT;
        /* Note : the corresponding Flag is cleared by hardware depending
                  of the CAN Bus status*/
        break;
    case CAN_INT_LEC:
        /*  Clear LEC bits */
        CANx->ESTS = (uint32_t)0x00;
        /* Clear CAN_MSTS_ERRINT (rc_w1) */
        CANx->MSTS = CAN_MSTS_ERRINT;
        break;
    case CAN_INT_ERR:
        /*Clear LEC bits */
        CANx->ESTS = (uint32_t)0x00;
        /* Clear CAN_MSTS_ERRINT (rc_w1) */
        CANx->MSTS = CAN_MSTS_ERRINT;
        /* Note : BOFF, EPVF and EWGF Flags are cleared by hardware depending
            of the CAN Bus status*/
        break;
    default:
        break;
    }
}

/**
*\*\name   CheckINTStatus
*\*\fun    Checks whether the CAN interrupt has occurred or not.
*\*\param  CAN_register specifies the CAN interrupt register to check.
*\*\param  interrupt_bit specifies the interrupt source bit to check.
*\*\return INTStatus:
*\*\                    - SET
*\*\                    - RESET
**/
static INTStatus CheckINTStatus(uint32_t CAN_Reg, uint32_t Int_Bit)
{
    INTStatus pendingbitstatus;

    if ((CAN_Reg & Int_Bit) != (uint32_t)RESET)
    {
        /* CAN_INT is set */
        pendingbitstatus = SET;
    }
    else
    {
        /* CAN_INT is reset */
        pendingbitstatus = RESET;
    }
    return pendingbitstatus;
}



