/******************************************************************************
* @file  :  spl_can.c
* @brief :  This file provides firmware functions to manage the following
*           functionalities of the Controller Area Network (CAN) peripheral.
* @ver   :  V1.0.0
* @date  :  2023
******************************************************************************/
#include "spl_can.h"

/******************************************************************************
*@brief : CAN operation mode request.
*         This function is used for configuring CAN module registers which must be
*         written in RESET mode.
*         
*@param : CANx: Specifies which CAN instance used
*@param : CAN_OperatingMode : This parameter can be one of @ref CAN_OperatingMode.
*
*@return: Status : CAN_Status_Failed or CAN_Status_Success
******************************************************************************/
uint8_t CAN_OperatingModeRequest(CAN_TypeDef* CANx, uint8_t CAN_OperatingMode)
{
    uint8_t status = CAN_Status_Failed ;
	
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    assert_param(IS_CAN_OPERATING_MODE(CAN_OperatingMode));
    
    if (CAN_OperatingMode == CAN_OperatingMode_Initialization)
    {
        CANx->MOD |= CAN_OperatingMode_Initialization;  // enter Initialization 
        if ((CANx->MOD & CAN_MOD_RM) != CAN_OperatingMode_Initialization)
        {
            status = CAN_Status_Failed;
        }
        else
        {
            status = CAN_Status_Success;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_Normal)
    {
        CANx->MOD &= ~CAN_OperatingMode_Initialization;   //1-->0 enter Normal 
        if ((CANx->MOD & CAN_MOD_RM) != CAN_OperatingMode_Normal)
        {
            status = CAN_Status_Failed;
        }
        else
        {
            status = CAN_Status_Success;
        }
    }
    else if (CAN_OperatingMode == CAN_OperatingMode_Sleep)
    {
        CANx->MOD |= CAN_OperatingMode_Sleep;  // enter Normal 
        if ((CANx->MOD & CAN_MOD_SM) != CAN_OperatingMode_Sleep)
        {
            status = CAN_Status_Failed;
        }
        else
        {
            status = CAN_Status_Success;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_Listen)
    {
        CANx->MOD |= CAN_OperatingMode_Listen;  // enter Normal 
        if((CANx->MOD & CAN_MOD_LOM) != CAN_OperatingMode_Listen)
        {
            status = CAN_Status_Failed;
        }
        else
        {
            status = CAN_Status_Success;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_SelfTest)
    {
        CANx->MOD |= CAN_OperatingMode_SelfTest;  // enter Normal 
        if((CANx->MOD & CAN_MOD_STM) != CAN_OperatingMode_SelfTest)
        {
            status = CAN_Status_Failed;
        }
        else
        {
            status = CAN_Status_Success;
        }
    }
    else
    {
        status = CAN_Status_Failed;
    }
    return  (uint8_t) status;
}

/******************************************************************************
*@brief : Initilise CAN module.
*         
*@param : CANx: Specifies which CAN instance used
*@param : CAN_InitStruct : Pointer to a CAN_InitTypeDef structure.
*
*@return: Status : CAN_InitStatus_Failed or CAN_InitStatus_Success
******************************************************************************/
uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)
{
    uint8_t InitStatus = CAN_InitStatus_Failed;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx)) ;
    assert_param(IS_CAN_MODE(CAN_InitStruct->CAN_Mode)) ;
    assert_param(IS_CAN_SJW(CAN_InitStruct->CAN_SJW)) ;
    assert_param(IS_CAN_TSEG1(CAN_InitStruct->CAN_TSEG1));
    assert_param(IS_CAN_TSEG2(CAN_InitStruct->CAN_TSEG2));
    assert_param(IS_CAN_BRP(CAN_InitStruct->CAN_BRP));
    assert_param(IS_CAN_SAM(CAN_InitStruct->CAN_SAM));
    /* Reset the CANx */
    if(CANx==CAN1)
    {
        __RCC_CAN1_RESET();
        __RCC_CAN1_CLK_ENABLE();
    }
    else
    {
        __RCC_CAN2_RESET();
        __RCC_CAN2_CLK_ENABLE();
    }

    CAN_OperatingModeRequest(CANx, CAN_OperatingMode_Initialization);//enter CAN_OperatingMode_Initialization
    if(CAN_InitStruct->CAN_BOR == CAN_BOR_ENABLE)
    {
        /* Enable the CAN BUS OFF ERROR interrupt */
        CANx->IER |= CAN_IER_BEIE;
    }
    
    CANx->BTR = (CAN_InitStruct->CAN_SJW << CAN_BTR_SJW_Pos )    | \
                (CAN_InitStruct->CAN_BRP << CAN_BTR_BRP_Pos)     | \
                (CAN_InitStruct->CAN_SAM << CAN_BTR_SAM_Pos)     | \
                (CAN_InitStruct->CAN_TSEG2 << CAN_BTR_TSEG2_Pos) | \
                (CAN_InitStruct->CAN_TSEG1 << CAN_BTR_TSEG1_Pos);
    
    CAN_OperatingModeRequest(CANx, CAN_OperatingMode_Normal);//enter CAN_OperatingMode_Normal
    return CAN_InitStatus_Success;
}

/******************************************************************************
*@brief : De-initializes the CAN peripheral registers to their default
*               reset values.
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: None
******************************************************************************/
void CAN_DeInit(CAN_TypeDef* CANx)
{
		if(CANx==CAN1)
		{
            /* Reset CAN clock */
            __RCC_CAN1_RESET();
        }
		else if(CANx==CAN2)
        {
            /* Reset CAN clock */
            __RCC_CAN2_RESET();
		}
}


static uint8_t CAN_AddTXMessageToBuffer(CAN_TypeDef* CANx, CanTxRxMsg* TxMessage)
{
    uint8_t i = 0;
    uint8_t can_id[4];  
    uint32_t frame_header;  
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
    assert_param(IS_CAN_RTR(TxMessage->RTR));
    assert_param(IS_CAN_DLC(TxMessage->DLC));
    
    /* Transmit buffer locked */
    if(!READ_BIT(CANx->SR, CAN_SR_TBS))
        return CAN_Status_Failed;
    
    /* Set up the DLC */
    frame_header =TxMessage->DLC & 0x0F;  // standard data frame 
    /* Set up the Id */
    if(TxMessage->IDE == CAN_Id_Standard)//Standard ID
    {
        can_id[0] = TxMessage->StdId >> 3; 
        can_id[1] = (TxMessage->StdId & 0x07) << 5;   
        for(i = 0; i < 2; i++)
        {
            CANx->DF.DATABUF[1+i] = can_id[i];  
        }
    }
    else//Id_Extended
    {
        can_id[0] = TxMessage->ExtId >> 21; 
        can_id[1] = (TxMessage->ExtId & 0x1FE000) >> 13;   
        can_id[2] = (TxMessage->ExtId & 0x1FE0) >> 5; 
        can_id[3] = (TxMessage->ExtId & 0x1F) << 3;
        frame_header |= (CAN_Id_Extended << 7);  // extended data frame 
        for(i = 0; i < 4; i++)
        {
            CANx->DF.DATABUF[1 + i] = can_id[i];  
        }
    }
    if(TxMessage->RTR == CAN_RTR_Data)//CAN_RTR_Data
    {
        frame_header &= ~(CAN_RTR_Remote << 6);
        for(i = 0; i < TxMessage->DLC; i++)  
        {
            CANx->DF.DATABUF[3 + (TxMessage->IDE * 2) + i] = TxMessage->Data[i];      
        }
    }
    else//CAN_RTR_Remote
    {
        frame_header |= (CAN_RTR_Remote << 6);
    }
    
    CANx->DF.DATABUF[0] = frame_header;
    
    return CAN_Status_Success;
}

/******************************************************************************
*@brief : Transmit CAN message and wait for its completed. Auto re-transmission mode
*         
*@param : CANx: Specifies which CAN instance used
*@param : TxMessage : pointer to a structure which contains CAN Id, CAN
*                         DLC and CAN data.
*
*@return: Status
*@Note  : Callling this function for transmitting message result in auto-retransmission 
          in the event of an error or loss of arbitration
******************************************************************************/
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxRxMsg* TxMessage)
{
    uint8_t status;
    
    status = CAN_AddTXMessageToBuffer(CANx, TxMessage);
    if(status != CAN_Status_Success)
        return status;
    
    CANx->CMR = CAN_CMR_TR;  // transfer request
    while((CANx->SR & CAN_SR_TCS) == 0x00); //wait for send ok	
    return CAN_Status_Success;
}


/******************************************************************************
*@brief : Transmit CAN message and wait for its completed with in Timeout. Auto re-transmission mode
*         
*@param : CANx:     Specifies which CAN instance used
*@param : TxMessage:pointer to a structure which contains CAN Id, CAN DLC and CAN data.
*@param : Timeout : The timeout value for transmitting message. 
                    Tranmission will be cancelled when the transmission time execeede timeout value
*
*@return: Status
*@Note  : Callling this function for transmitting message result in auto-retransmission 
          in the event of an error or loss of arbitration
******************************************************************************/
uint8_t CAN_Transmit_WithTimeout(CAN_TypeDef* CANx, CanTxRxMsg* TxMessage, uint32_t Timeout)
{
    uint8_t status;
    uint32_t tickstart;
    
    status = CAN_AddTXMessageToBuffer(CANx, TxMessage);
    if(status != CAN_Status_Success)
        return status;
    
    CANx->CMR = CAN_CMR_TR;  // transfer request
    
    tickstart = SysTick_Get();
    
    while((CANx->SR & CAN_SR_TCS) == 0x00)
    {
        if((SysTick_Get() - tickstart) > Timeout)
        {
            CAN_CancelTransmit(CANx);
            return CAN_Status_Timeout;
        }
        
        if(CANx->SR & CAN_SR_BS)
        {
            return CAN_Status_Busoff;
        }
    }
    return CAN_Status_Success;
}

/******************************************************************************
*@brief : Transmit CAN message in single shot mode
*         
*@param : CANx: Specifies which CAN instance used
*@param : TxMessage : pointer to a structure which contains CAN Id, CAN
*                         DLC and CAN data.
*
*@return: Status
*@Note  : Calling this function results in a Single-Shot transmission 
          of the Transmit message without re-transmission in the event of an error 
          or loss of arbitration.
******************************************************************************/
uint8_t CAN_Transmit_SingleShot(CAN_TypeDef* CANx, CanTxRxMsg* TxMessage)
{
    uint8_t status;
    
    status = CAN_AddTXMessageToBuffer(CANx, TxMessage);
    if(status != CAN_Status_Success)
        return status;
    
    CANx->CMR = CAN_CMR_TR | CAN_CMR_AT;    // 
    while((CANx->SR & CAN_SR_TCS) == 0x00); //wait for send ok	
    return CAN_Status_Success;
}

/******************************************************************************
*@brief : CAN Transmit message with self receive request. Auto re-transmission mode
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: Status
*@Note  : Callling this function for transmitting message result in auto-retransmission 
          in the event of an error or loss of arbitration
******************************************************************************/
uint8_t CAN_Transmit_SelfReceive(CAN_TypeDef* CANx, CanTxRxMsg* TxMessage)
{
    uint8_t status;
    
    status = CAN_AddTXMessageToBuffer(CANx, TxMessage);
    if(status != CAN_Status_Success)
        return status;

    CANx->CMR = CAN_CMR_SRR; 
    while((CANx->SR & CAN_SR_TCS) == 0x00); //wait for send ok	
    return CAN_Status_Success;
}

/******************************************************************************
*@brief : CAN Transmit message with self receive request, SingleShot mode
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: Status
*@Note  : Calling this function results in a Single-Shot transmission 
          of the Transmit message without re-transmission in the event of an error 
          or loss of arbitration.
******************************************************************************/
uint8_t CAN_Transmit_SingleShot_SelfReceive(CAN_TypeDef* CANx, CanTxRxMsg* TxMessage)
{
    uint8_t status;
    
    status = CAN_AddTXMessageToBuffer(CANx, TxMessage);
    if(status != CAN_Status_Success)
        return status;

    CANx->CMR = CAN_CMR_SRR | CAN_CMR_AT; 
    while((CANx->SR & CAN_SR_TCS) == 0x00); //wait for send ok	
    return CAN_Status_Success;
}

/******************************************************************************
*@brief : Cancel transmion of CAN message 
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: Status
******************************************************************************/
void CAN_CancelTransmit(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx)) ;
    /* abort transmission */
    CANx->CMR |= CAN_CMR_AT; //Abort Transmission 
}

/******************************************************************************
*@brief : wait for receiving CAN message
*         
*@param : CANx: Pointer to a CAN_TypeDef structure
*@param : RxMessage : pointer to a structure receive message which contains 
*                           CAN Id, CAN DLC, CAN datas.
*@return: None
******************************************************************************/
void CAN_Receive(CAN_TypeDef* CANx, CanTxRxMsg* RxMessage)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    while(!(CANx->SR & CAN_SR_RBS));
    CAN_GetRxMessage(CANx, RxMessage);
}

/******************************************************************************
*@brief : Get one of CAN messages in CAN module RX FIFO, then release the 
*         buffer been read.
*@param : CANx: Specifies which CAN instance used
*@param : RxMessage : pointer to a structure receive message which contains 
*                           CAN Id, CAN DLC, CAN datas.
*@return: None
******************************************************************************/
void CAN_GetRxMessage(CAN_TypeDef* CANx, CanTxRxMsg* RxMessage)
{
    uint8_t i=0;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx)) ;
    
    if(0 == (CANx->SR & CAN_SR_RBS)) return;  // receive fifo empty  
    
    /* Get the IDE */
    RxMessage->IDE = (uint8_t)(0x80 & CANx->DF.DATABUF[0]) >> 7;
    /* Get the RTR */
    RxMessage->RTR = (uint8_t)(0x40 & CANx->DF.DATABUF[0]) >> 6;
    /* Get the DLC */
    RxMessage->DLC = (uint8_t)0x0F & CANx->DF.DATABUF[0];
    if (RxMessage->IDE == CAN_Id_Standard)
    {
        RxMessage->StdId = (uint32_t)(( CANx->DF.DATABUF[1] << 8) |  CANx->DF.DATABUF[2]) >> 5;;
        for(i=0; i< RxMessage->DLC; i++)  
        {
            RxMessage->Data[i] = CANx->DF.DATABUF[3 + i];
        }
    }
    else
    {
        RxMessage->ExtId = (uint32_t)(( CANx->DF.DATABUF[1]<<24) | ( CANx->DF.DATABUF[2]<<16) | ( CANx->DF.DATABUF[3]<<8) | (CANx->DF.DATABUF[4] ))>>3;;
        for(i=0; i<RxMessage->DLC; i++)  
        {
            RxMessage->Data[i] = CANx->DF.DATABUF[5+i];       
        }
    }
    
    while(CANx->SR & CAN_SR_RS){}
    /* Release the FIFO */
    CANx->CMR |= CAN_CMR_RRB; //Release Receive Buffer
}

/******************************************************************************
*@brief : Configure CAN filter with parameters in the CAN_FilterInitStruct.
*
*@param : CANx: Specifies which CAN instance used
*
*@param : CAN_FilterInitStruct : pointer to a CAN_FilterInitTypeDef structure 
*                                that contains the configuration information.
*@return: None
******************************************************************************/
void CAN_FilterInit(CAN_TypeDef* CANx, CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
    uint8_t filter_num = 0;
    
    CAN_OperatingModeRequest(CANx,CAN_OperatingMode_Initialization);//enter CAN_OperatingMode_Initialization
    /* Filter Mode */
    filter_num = CAN_FilterInitStruct->FilterBank;
    
    /* Filter Mode */
    if (CAN_FilterInitStruct->FilterMode == CAN_FilterMode_Dual) /*Dual mode*/
    {
        CANx->MOD &= ~(1 << (8 + filter_num));
        /*Dual mode ACR set*/    
         CANx->ACR[filter_num] =
                                (( CAN_FilterInitStruct->FilterId1 & 0x1FFFE000) >> 13)|         /*Dual mode ACR=ID28...ID13 of ID1*/
                                (((CAN_FilterInitStruct->FilterId2 & 0x1FFFE000) >> 13) << 16) ;	/*Dual mode ACR=ID28...ID13 of ID2*/
        
        /*Dual mode AMR set*/
         CANx->AMR[filter_num] =
                                (( CAN_FilterInitStruct->FilterMaskId1 & 0x1FFFE000) >> 13)|               
                                (((CAN_FilterInitStruct->FilterMaskId2 & 0x1FFFE000) >> 13) << 16) ; 	       
    }
    else /*Single mode*/
    {
        CANx->MOD |= (1 << (8 + filter_num));
        /*Single mode ACR set*/            
        CANx->ACR[filter_num] = ((CAN_FilterInitStruct->FilterId1 & 0x1FFFFFFF) << 3) ;	/*Single mode ACR=ID28...ID0 of ID1*/
        
        /*Single mode AMR set*/   
        CANx->AMR[filter_num] = ((CAN_FilterInitStruct->FilterMaskId1 & 0x1FFFFFFF) << 3) ;           
    }
    
    CANx->MOD |= (1 << (16 + filter_num));

    CAN_OperatingModeRequest(CANx,CAN_OperatingMode_Normal);//enter CAN_OperatingMode_Initialization
}

/******************************************************************************
*@brief : Enter sleep mode
*
*@param : CANx: Specifies which CAN instance used
*
*@return: status
******************************************************************************/
uint8_t CAN_Sleep(CAN_TypeDef* CANx)
{
    uint8_t status;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    /* Request Sleep mode */
    CANx->MOD |= CAN_MOD_SM; //Enter Sleep Mode
   
    /* Sleep mode status */
    if ((CANx->MOD & CAN_MOD_SM) == CAN_MOD_SM)
    {
    /* Sleep mode entered */
        status= CAN_Status_Success;
    }else
    {
        status=CAN_Status_Failed;
    }
    /* return sleep mode status */
    return status;
}

/******************************************************************************
*@brief : Wake up from sleep mode
*
*@param : CANx: Specifies which CAN instance used
*
*@return: status
******************************************************************************/
uint8_t CAN_WakeUp(CAN_TypeDef* CANx)
{
    uint8_t status;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    /* sleep wake mode */
    CANx->MOD &= ~CAN_MOD_SM; //Enter Sleep Mode
   
    /* sleep wake status */
    if ((CANx->MOD & CAN_MOD_SM) == CAN_MOD_SM)
    {
        /* sleep wake not entered */
        status= CAN_Status_Failed;
    }else
    {
        status=CAN_Status_Success;
    }
    /* return sleep mode status */
    return status;
}

/******************************************************************************
*@brief : Get CAN transmit error counter
*
*@param : CANx: Specifies which CAN instance used
*
*@return: The TX error counter
******************************************************************************/
uint8_t CAN_GetTransmitErrorCounter(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    return CANx->ERRCNTR.TxErr;
}

/******************************************************************************
*@brief : Get CAN receive error counter
*
*@param : CANx: Specifies which CAN instance used
*
*@return: The RX error counter
******************************************************************************/
uint8_t CAN_GetReceiveErrorCounter(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    return CANx->ERRCNTR.RxErr;
}

/******************************************************************************
*@brief : Get CAN error code
*
*@param : CANx: Specifies which CAN instance used
*
*@return: a value of CAN_ErrCode_t struct which contains informations of
*          ALC, ErrCode, Direction, SegCode. @REF CAN_ErrCode_t
******************************************************************************/
CAN_ErrCode_t CAN_GetErrorCode(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    return CANx->ECCR;
}

/******************************************************************************
*@brief : Get CAN error warning level value 
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: Error Warning Level value(EWL)
******************************************************************************/
uint8_t CAN_GetErrorAlarmCounter(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    return CANx->ERRCNTR.EWL;
}


/******************************************************************************
*@brief : Set CAN error alarm counter 
*         
*@param : CANx: Specifies which CAN instance used
*@param : cnt : Alarm counter value
*
*@return: None
******************************************************************************/
void CAN_SetErrorAlarmCounter(CAN_TypeDef* CANx, uint8_t cnt)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    CAN_OperatingModeRequest(CANx,CAN_OperatingMode_Initialization);
    
    CANx->ERRCNTR.EWL = cnt;
    
    CAN_OperatingModeRequest(CANx,CAN_OperatingMode_Normal);
}

/******************************************************************************
*@brief : Get the bit position value(ALC) at where CAN arbitration is lost 
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: The CANx Arbitration Lost Position(ALC).
******************************************************************************/
uint8_t CAN_GetArbitrationErrorPosition(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    return CANx->ECCR.ALC + 1;
}

/******************************************************************************
*@brief : Get Received CAN message counter
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: Received Message Counter(RMC)
******************************************************************************/
uint8_t CAN_GetReceiveFiFoCounter(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    
    return CANx->RSR.RMC;
}

/******************************************************************************
*@brief : Get the start address of incoming CAN message in Receive buffer
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: Receive Buffer Start Address(RBSA)
******************************************************************************/
uint8_t CAN_GetReceiveFiFoAddr(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));

    return CANx->RSR.RBSA;
}

/******************************************************************************
*@brief : Release receive buffer
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: None
******************************************************************************/
void CAN_ReleaseReceiveFIFO(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    /* Releases the Receive FIFO. */
    CANx->CMR |= CAN_CMR_RRB;	
}

/******************************************************************************
*@brief : Clear Data Overflow(CDO) status
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: None
******************************************************************************/
void CAN_ClearOverload(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    /* Clear Overload. */
    CANx->CMR |= CAN_CMR_CDO;	
}

/******************************************************************************
*@brief : CAN self receive request
*         
*@param : CANx: Specifies which CAN instance used
*
*@return: None
******************************************************************************/
void CAN_SelfReceive(CAN_TypeDef* CANx)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    /* Slef Receive. */
    CANx->CMR |= CAN_CMR_SRR;	
    while((CANx->SR & CAN_SR_TCS) == 0x00); //wait for send ok	
}

/******************************************************************************
*@brief : Enable or disable CAN Interrupt.
*         
*@param : CANx: Specifies which CAN instance used
*@param : CAN_IT: can be one of the following values:
                    CAN_IER_RIE  : CAN message received interrupt
                    CAN_IER_TIE  : CAN message transmit completed interrupt
                    CAN_IER_EIE  : CAN error interrupt
                    CAN_IER_DOIE : CAN data overflow interupt
                    CAN_IER_WUIE : CAN wake-up interrupt
                    CAN_IER_EPIE : CAN error-passive interrupt
                    CAN_IER_ALIE : CAN arbitration lost interrupt
                    CAN_IER_BEIE : CAN bus error interrupt
*@param : NewState : ENABLE or DISABLE
*
*@return: None
******************************************************************************/
void CAN_ITConfig(CAN_TypeDef* CANx, uint32_t CAN_IT, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_CAN_ALL_PERIPH(CANx));
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    /* Enable the selected CANx interrupt */
    CANx->IER |= CAN_IT;
  }
  else
  {
    /* Disable the selected CANx interrupt */
    CANx->IER &= ~CAN_IT;
  }
}

static ITStatus CheckITStatus(uint32_t CAN_Reg, uint32_t It_Bit)
{
    ITStatus pendingbitstatus = RESET;

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

/******************************************************************************
*@brief : Get CAN Interrupt status
*         
*@param : CANx: Specifies which CAN instance used
*@param : CAN_IT: can be one of the following values:
                    CAN_IER_RIE  : CAN message received interrupt
                    CAN_IER_TIE  : CAN message transmit completed interrupt
                    CAN_IER_EIE  : CAN error interrupt
                    CAN_IER_DOIE : CAN data overflow interupt
                    CAN_IER_WUIE : CAN wake-up interrupt
                    CAN_IER_EPIE : CAN error-passive interrupt
                    CAN_IER_ALIE : CAN arbitration lost interrupt
                    CAN_IER_BEIE : CAN bus error interrupt
*
*@return: @REF ITStatus
******************************************************************************/
ITStatus CAN_GetITStatus(CAN_TypeDef* CANx, uint32_t CAN_IT)
{
    ITStatus itstatus = RESET;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
		
		/* check the enable interrupt bit */
	 if((CANx->IER & CAN_IT) != RESET)
	 {
		 /* in case the Interrupt is enabled, .... */
        switch (CAN_IT)
        {
            case CAN_IER_RIE:
                 /* Check CAN_TSR_RQCPx bits */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_RI);  
                break;
            case CAN_IER_TIE:
                 /* Check CAN_RF0R_FMP0 bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_TI);  
                break;
            case CAN_IER_EIE:
                 /* Check CAN_RF0R_FULL0 bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_EI);  
                break;
            case CAN_IER_DOIE:
                 /* Check CAN_RF0R_FOVR0 bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_DOI);  
                break;
            case CAN_IER_WUIE:
                 /* Check CAN_RF1R_FMP1 bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_WUI);  
                break;
            case CAN_IER_EPIE:
                 /* Check CAN_RF1R_FULL1 bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_EPI);  
                break;
            case CAN_IER_ALIE:
                 /* Check CAN_RF1R_FOVR1 bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_ALI);  
                break;
            case CAN_IER_BEIE:
                 /* Check CAN_MSR_WKUI bit */
                 itstatus = CheckITStatus(CANx->IR, CAN_IR_BEI);  
                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_IT status */
    return  itstatus;
}

/******************************************************************************
*@brief : Get CAN status flags
*         
*@param : CANx: Specifies which CAN instance used
*@param : CAN_FLAG: can be one of the following values:
                    CAN_SR_BS   : CAN bus status
                    CAN_SR_ES   : CAN error status
                    CAN_SR_TS   : CAN transmion status
                    CAN_SR_RS   : CAN receive status
                    CAN_SR_TCS  : CAN transmion completed status
                    CAN_SR_TBS  : CAN transmion buffer status
                    CAN_SR_DOS  : CAN data overflow status
                    CAN_SR_RBS  : CAN receive buffer status                  
*
*@return: @REF FlagStatus
******************************************************************************/
FlagStatus CAN_GetFlagStatus(CAN_TypeDef* CANx, uint32_t CAN_FLAG)
{
		FlagStatus bitstatus = RESET;
		
		/* Check the parameters */
		assert_param(IS_CAN_ALL_PERIPH(CANx));
		assert_param(IS_CAN_GET_FLAG(CAN_FLAG));
	 
			/* Check the status of the specified CAN flag */
		 if ((CANx->SR & CAN_FLAG ) != (uint32_t)RESET)
			{ 
				/* CAN_FLAG is set */
				bitstatus = SET;
			}
			else
			{ 
				/* CAN_FLAG is reset */
				bitstatus = RESET;
			}
	 
		/* Return the CAN_FLAG status */
		return  bitstatus;
}
