/******************************************************************************
* @file  :  hal_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  :  2020
******************************************************************************/
#include "hal_can.h"

#ifdef HAL_CAN_MODULE_ENABLED


/******************************************************************************
*@brief : Select the CAN Operation mode.
*         
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : CAN_OperatingMode: CAN Operating Mode. This parameter can be one  of @ref CAN_Operating_Mode.
*
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_OperatingModeRequest(CAN_HandleTypeDef *hcan, uint8_t CAN_OperatingMode)
{
    HAL_StatusTypeDef status = HAL_ERROR;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    assert_param(IS_CAN_OPERATING_MODE(CAN_OperatingMode));
    
    if (CAN_OperatingMode == CAN_OperatingMode_Initialization)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_Initialization;  // enter Initialization 
        if ((hcan->Instance->MOD & CAN_MOD_RM) != CAN_OperatingMode_Initialization)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_Normal)
    {
        hcan->Instance->MOD &=~ CAN_OperatingMode_Initialization;   //1-->0 enter Normal 
        if ((hcan->Instance->MOD & CAN_MOD_RM) != CAN_OperatingMode_Normal)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else if (CAN_OperatingMode == CAN_OperatingMode_Sleep)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_Sleep;  // enter Normal 
        if ((hcan->Instance->MOD & CAN_MOD_SM) != CAN_OperatingMode_Sleep)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_Listen)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_Listen;  // enter Normal 
        hcan->Instance->MOD &=~ CAN_OperatingMode_Initialization;   //1-->0 enter Normal 
        if((hcan->Instance->MOD & CAN_MOD_LOM) != CAN_OperatingMode_Listen)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_LOOPBACK)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_LOOPBACK;  // enter Normal 
        hcan->Instance->MOD |= CAN_MOD_STM;  // enter Normal 
        hcan->Instance->MOD &=~ CAN_OperatingMode_Initialization;   //1-->0 enter Normal 
        if((hcan->Instance->MOD & CAN_MOD_LBKM) != CAN_OperatingMode_LOOPBACK)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_SILENT)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_SILENT;  // enter Normal 
        hcan->Instance->MOD |= CAN_MOD_STM;  // enter Normal 
        hcan->Instance->MOD &=~ CAN_OperatingMode_Initialization;   //1-->0 enter Normal 
        if((hcan->Instance->MOD & CAN_MOD_SILM) != CAN_OperatingMode_SILENT)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_SILENT_LOOPBACK)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_SILENT_LOOPBACK;  // enter Normal 
        hcan->Instance->MOD |= CAN_MOD_STM;  // enter Normal 
        hcan->Instance->MOD &=~ CAN_OperatingMode_Initialization;   //1-->0 enter Normal 
        if(((hcan->Instance->MOD & CAN_MOD_SILM) == CAN_OperatingMode_SILENT)&&((hcan->Instance->MOD & CAN_MOD_LBKM) == CAN_OperatingMode_LOOPBACK))
        {
            status = HAL_OK;
        }
        else
        {
            status = HAL_ERROR;
        }
    }
    else if(CAN_OperatingMode == CAN_OperatingMode_SelfTest)
    {
        hcan->Instance->MOD |= CAN_OperatingMode_SelfTest;  // enter selftest mode 
        if((hcan->Instance->MOD & CAN_MOD_STM) != CAN_OperatingMode_SelfTest)
        {
            status = HAL_ERROR;
        }
        else
        {
            status = HAL_OK;
        }
    }
    else
    {
        status = HAL_ERROR;
    }
    return   status;
}

/******************************************************************************
*@brief : Initialize the CAN low level, such as Clock, GPIO.
*         
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*
*@return: None
******************************************************************************/
__weak void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan)
{
    /* NOTE : This function should not be modified, when the callback is needed,
                the HAL_UART_MspInit can be implemented in the user file
    */
    /* For Example */
    GPIO_InitTypeDef GPIO_InitStructure={0};
    
    if(hcan->Instance == CAN1)
    {
        /* Enable CAN clock */
        __HAL_RCC_CAN1_CLK_ENABLE();
        __HAL_RCC_GPIOD_CLK_ENABLE();

        __HAL_RCC_CAN1_RESET();

        /* Initialization GPIO */
        /* PD0:Rx */  /* PD1:Tx */
        GPIO_InitStructure.Pin       = GPIO_PIN_0 | GPIO_PIN_1;	
        GPIO_InitStructure.Alternate = GPIO_FUNCTION_4;
        GPIO_InitStructure.Pull      = GPIO_PULLUP;
        GPIO_InitStructure.Mode      = GPIO_MODE_AF_PP;
        GPIO_InitStructure.Drive     = GPIO_DRIVE_LEVEL3;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);

        NVIC_ClearPendingIRQ(CAN1_IRQn);
        NVIC_SetPriority(CAN1_IRQn, 5);
        NVIC_EnableIRQ(CAN1_IRQn); 
    }
    else if(hcan->Instance == CAN2)
    {
        /* Enable CAN clock */
        __HAL_RCC_CAN2_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();

        __HAL_RCC_CAN2_RESET();

        /* Initialization GPIO */
        /* PB5:Rx */  /* PB6:Tx */
        GPIO_InitStructure.Pin       = GPIO_PIN_5 | GPIO_PIN_6;	
        GPIO_InitStructure.Alternate = GPIO_FUNCTION_4;
        GPIO_InitStructure.Pull      = GPIO_PULLUP;
        GPIO_InitStructure.Mode      = GPIO_MODE_AF_PP;
        GPIO_InitStructure.Drive     = GPIO_DRIVE_LEVEL3;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
        NVIC_ClearPendingIRQ(CAN2_IRQn);
        NVIC_SetPriority(CAN2_IRQn, 5);
        NVIC_EnableIRQ(CAN2_IRQn); 
    }
}

/******************************************************************************
*@brief : CAN MSP De-Initialization 
*         This function frees the hardware resources used in this example:
*              - Disable the Peripheral's clock
*              - Revert GPIO configuration to their default state
*         
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*
*@return: None
******************************************************************************/
__weak void HAL_CAN_MspDeInit(CAN_HandleTypeDef *hcan)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    if(hcan->Instance == CAN1)
    {
        /* Reset CAN clock */
        __HAL_RCC_CAN1_CLK_DISABLE();

        /* De-Initialization GPIO */
        /* PD0:Rx */  /* PD1:Tx */
        HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0);
        HAL_GPIO_DeInit(GPIOD, GPIO_PIN_1);
    }
    else if(hcan->Instance == CAN2)
    {
        /* Reset CAN clock */
        __HAL_RCC_CAN2_CLK_DISABLE();
        
        GPIO_InitTypeDef GPIO_InitStructure;   	
        /* De-Initialization GPIO */
        /* PB5:Rx */  /* PB6:Tx */
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_5);
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
    }
}

/******************************************************************************
*@brief : Initializes the CAN peripheral according to the specified  parameters 
*         in the CAN_HandleTypeDef.      
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*
*@return: HAL Status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan)
{
    HAL_StatusTypeDef ret = HAL_OK;
    
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    assert_param(IS_CAN_OPERATING_MODE(hcan->Init.CAN_Mode));
    assert_param(IS_CAN_SJW(hcan->Init.CAN_SJW));
    assert_param(IS_CAN_TSEG1(hcan->Init.CAN_TSEG1));
    assert_param(IS_CAN_TSEG2(hcan->Init.CAN_TSEG2));
    assert_param(IS_CAN_BRP(hcan->Init.CAN_BRP));
    assert_param(IS_CAN_SAM(hcan->Init.CAN_SAM));
    
    HAL_CAN_MspInit(hcan);
    
    ret = HAL_CAN_OperatingModeRequest(hcan,CAN_OperatingMode_Initialization);//enter CAN_OperatingMode_Initialization
    
    if(ret == HAL_OK)
    {
    
        if(hcan->Init.CAN_BOR == CAN_BOR_ENABLE)
        {
            /* Enable the CAN BUS OFF ERROR interrupt */
            hcan->Instance->IER |= CAN_IER_BEIE;
        }
        
        hcan->Instance->BTR = (hcan->Init.CAN_SJW << CAN_BTR_SJW_Pos )
                            | (hcan->Init.CAN_BRP << CAN_BTR_BRP_Pos)
                            | (hcan->Init.CAN_SAM << CAN_BTR_SAM_Pos)
                            | (hcan->Init.CAN_TSEG2 << CAN_BTR_TSEG2_Pos)
                            | (hcan->Init.CAN_TSEG1 << CAN_BTR_TSEG1_Pos);
        
        ret = HAL_CAN_OperatingModeRequest(hcan,hcan->Init.CAN_Mode);
    }
    
    return ret;
}

/******************************************************************************
*@brief : Deinitializes the CAN peripheral registers to their default
*         reset values.      
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*
*@return: HAL Status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_DeInit(CAN_HandleTypeDef *hcan)
{
    /* Check CAN handle */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));

    HAL_CAN_MspDeInit(hcan);
    
    /* Reset the CAN peripheral */
    SET_BIT(hcan->Instance->MOD, CAN_MOD_RM);
    
    /* Return function status */
    return HAL_OK;
}

/******************************************************************************
*@brief : add a message to the TxBuffer,and activate the corresponding
*         transmission request      
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : TxMessage: pointer to a structure which contains CAN Id, CAN
*                    DLC and CAN data.
*@param : Timeout: timeout for aborting message sending when failed. unit:MS. 0xFFFFFFFF is wait forever
*@return: HAL Status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, CanTxRxMsg* TxMessage, uint32_t Timeout)
{
    uint8_t i = 0;
    uint8_t can_id[4];  
    uint32_t tickstart;
    uint32_t frame_header;

    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
    assert_param(IS_CAN_RTR(TxMessage->RTR));
    assert_param(IS_CAN_DLC(TxMessage->DLC));
    
    /* 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++)
        {
            hcan->Instance->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++)
        {
            hcan->Instance->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++)  
        {
            hcan->Instance->DF.DATABUF[3 + (TxMessage->IDE * 2) + i] = TxMessage->Data[i];      
        }
    }
    else//CAN_RTR_Remote
    {
        frame_header |= (CAN_RTR_Remote << 6);
    }
    hcan->Instance->DF.DATABUF[0] = frame_header;
    if(hcan->Init.CAN_Mode == CAN_OperatingMode_LOOPBACK||hcan->Init.CAN_Mode == CAN_OperatingMode_SILENT
                                                      ||hcan->Init.CAN_Mode == CAN_OperatingMode_SILENT_LOOPBACK
                                                      ||hcan->Init.CAN_Mode == CAN_OperatingMode_SelfTest)
    {
        /* self receive request */
        hcan->Instance->CMR = CAN_CMR_SRR;  
    }
    else
    {
        /* transfer request */
        hcan->Instance->CMR = CAN_CMR_TR;
    }
   
    tickstart = HAL_GetTick();
    
    while((hcan->Instance->SR & CAN_SR_TCS) == 0x00)//wait for send ok
    {  
        if ((HAL_GetTick() - tickstart) > Timeout)
        {
            hcan->Instance->CMR |= CAN_CMR_AT;
            return HAL_TIMEOUT;
        }
        
        if(hcan->Instance->SR & CAN_SR_BS)
        {
            return HAL_ERROR;
        }
    }
	
    return HAL_OK;
}

/******************************************************************************
*@brief : abort a transmit request.     
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: None
******************************************************************************/
void HAL_CAN_CancelTransmit(CAN_HandleTypeDef *hcan)
{
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    /* abort transmission */
    hcan->Instance->CMR |= CAN_CMR_AT; //Abort Transmission 
}

/******************************************************************************
*@brief : Receives a message by interrupt mode.     
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : RxMessage: pointer to a structure of CanTxRxMsg which will return the value 
*                     of incoming messages. sucha as CAN Id, CAN DLC, CAN datas
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_Receive_IT(CAN_HandleTypeDef *hcan, CanTxRxMsg* RxMessage)
{
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    
    hcan->RxMessage = RxMessage;

    /* Enable the CAN Receive interrupt */
    hcan->Instance->IER |= CAN_IER_RIE;
    hcan->Instance->IER |= CAN_IER_DOIE;
    
    NVIC_ClearPendingIRQ(CAN1_IRQn);
    NVIC_SetPriority(CAN1_IRQn, 5);
    NVIC_EnableIRQ(CAN1_IRQn);

    return HAL_OK;
}

/******************************************************************************
*@brief : Receives a message by loop mode within timeout.     
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : RxMessage: pointer to a structure of CanTxRxMsg which will return the value 
*                     of incoming messages. sucha as CAN Id, CAN DLC, CAN datas
*@param : Timeout: timeout period for receving message. unit:MS. 0xFFFFFFFF is wait forever
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, CanTxRxMsg* RxMessage, uint32_t Timeout)
{
    uint32_t tickstart;
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    
    tickstart = HAL_GetTick();
    while(!(hcan->Instance->SR & CAN_SR_RBS))
    {
        if ((HAL_GetTick() - tickstart) > Timeout)
        {
            return HAL_TIMEOUT;
        }
    }
    
    HAL_CAN_GetRxMessage(hcan, RxMessage);
    
    return HAL_OK;
}

/******************************************************************************
*@brief : get the message from RXBUFF    
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : RxMessage: pointer to a structure of CanTxRxMsg which will return the value 
*                     of incoming messages. sucha as CAN Id, CAN DLC, CAN datas
*@return: None
******************************************************************************/
void HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, CanTxRxMsg* RxMessage)
{
    uint8_t i=0;

    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    
    if(0 == (hcan->Instance->SR & CAN_SR_RBS) ) return;
    /* Get the IDE */
    RxMessage->IDE = (uint8_t)(0x80 & hcan->Instance->DF.DATABUF[0]) >> 7;
    /* Get the RTR */
    RxMessage->RTR = (uint8_t)(0x40 & hcan->Instance->DF.DATABUF[0]) >> 6;
    /* Get the DLC */
    RxMessage->DLC = (uint8_t)(0x0F & hcan->Instance->DF.DATABUF[0]);
    
    if (RxMessage->IDE == CAN_Id_Standard)
    {
        RxMessage->StdId = (uint32_t)(( hcan->Instance->DF.DATABUF[1] << 8) |  hcan->Instance->DF.DATABUF[2]) >> 5;
        for(i = 0; i < RxMessage->DLC; i++)  
        {
            RxMessage->Data[i] = hcan->Instance->DF.DATABUF[3 + i];       
        }
    }
    else
    {
        RxMessage->ExtId = (uint32_t)(( hcan->Instance->DF.DATABUF[1] << 24) 
                                    | ( hcan->Instance->DF.DATABUF[2] << 16) 
                                    | ( hcan->Instance->DF.DATABUF[3] << 8) 
                                    | (hcan->Instance->DF.DATABUF[4])) >> 3;
        
        for(i = 0; i < RxMessage->DLC; i++)  
        {
            RxMessage->Data[i] = hcan->Instance->DF.DATABUF[5 + i];       
        }
    }
    /* Release the FIFO */
	hcan->Instance->CMR |= CAN_CMR_RRB; //Release Receive Buffer
}

/******************************************************************************
*@brief : config the CAN message receiving filter rules    
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : CAN_FilterInitStruct: pointer to a CAN_FilterInitTypeDef structure 
*                               that contains the filter rules information.
*@return: None
******************************************************************************/
void HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan,CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
    uint8_t filter_num=0;
    HAL_CAN_OperatingModeRequest(hcan,CAN_OperatingMode_Initialization);//enter CAN_OperatingMode_Initialization
    
    filter_num = CAN_FilterInitStruct->FilterBank;
    
    /* Filter Mode */
    if (CAN_FilterInitStruct->FilterMode == CAN_FilterMode_Dual) /*Dual mode*/
    {
        hcan->Instance->MOD &= ~(1 << (8 + filter_num));
        /*Dual mode ACR set*/    
         hcan->Instance->FILTER[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*/
         hcan->Instance->FILTER[filter_num+7] =
                                (( CAN_FilterInitStruct->FilterMaskId1 & 0x1FFFE000) >> 13)|                 
                                (((CAN_FilterInitStruct->FilterMaskId2 & 0x1FFFE000) >> 13) << 16) ;   	       
    }
    else /*Single mode*/
    {
        hcan->Instance->MOD |= (1 << (8 + filter_num));
        /*Single mode ACR set*/    
        
        hcan->Instance->FILTER[filter_num] = ((CAN_FilterInitStruct->FilterId1 & 0x1FFFFFFF) << 3) ;	/*Single mode ACR=ID28...ID0 of ID1*/    
        /*Single mode AMR set*/   
         hcan->Instance->FILTER[filter_num + 7] = ((CAN_FilterInitStruct->FilterMaskId1 & 0x1FFFFFFF) << 3) ;         
    }
    
    /* Filter activation */
    if (CAN_FilterInitStruct->FilterActivation == CAN_FILTER_ENABLE)
    {
        hcan->Instance->MOD |= (1 << (16 + filter_num));
    }
    else
    {
       hcan->Instance->MOD &=~ (1 << (16 + filter_num));
    }
    HAL_CAN_OperatingModeRequest(hcan,CAN_OperatingMode_Normal);//enter CAN_OperatingMode_Initialization
}

/******************************************************************************
*@brief : put CAN module into sleep mode   
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_Sleep(CAN_HandleTypeDef *hcan)
{
    HAL_StatusTypeDef status;

    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    /* Request Sleep mode */
    hcan->Instance->MOD |= CAN_MOD_SM; //Enter Sleep Mode
   
    /* Sleep mode status */
    if ((hcan->Instance->MOD & CAN_MOD_SM) == CAN_MOD_SM)
    {
    /* Sleep mode entered */
        status= HAL_OK;
    }else
    {
        status=HAL_ERROR;
    }
    /* return sleep mode status */
    return status;
}

/******************************************************************************
*@brief : wake the CAN module up
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_WakeUp(CAN_HandleTypeDef *hcan)
{
    HAL_StatusTypeDef status;

    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    /* sleep wake mode */
    hcan->Instance->MOD &=~ CAN_MOD_SM; //Enter Sleep Mode
   
    /* sleep wake status */
    if ((hcan->Instance->MOD & CAN_MOD_SM)== CAN_MOD_SM)
    {
        /* sleep wake not entered */
        status= HAL_ERROR;
    }else
    {
        status=HAL_OK;
    }
    /* return sleep mode status */
    return status;
}

/******************************************************************************
*@brief : return the CAN error code information.
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : pErrCode: a pointer of @ref CAN_ErrCodeInfo_t
*@return: HAL status; the error code information is stored in pErrCode.
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_GetErrorCode(CAN_HandleTypeDef *hcan, CAN_ErrCodeInfo_t *pErrCode)
{
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    
    if(!pErrCode)
        return HAL_ERROR;
    
    pErrCode->ALC = (uint8_t)((hcan->Instance->ECCR & CAN_ECCR_ALC) >> CAN_ECCR_ALC_Pos);
    
    pErrCode->ErrCode = (CAN_ErrCode_Enum)((hcan->Instance->ECCR & CAN_ECCR_ERRCODE) >> CAN_ECCR_ERRCODE_Pos);
    
    pErrCode->ErrDirection = (uint8_t)((hcan->Instance->ECCR & CAN_ECCR_DIRECTION) >> CAN_ECCR_DIRECTION_Pos);
    
    pErrCode->SegCode = (CAN_ERR_SegCode_Enum)((hcan->Instance->ECCR & CAN_ECCR_SEGCODE) >> CAN_ECCR_SEGCODE_Pos);

    return HAL_OK;
}


/******************************************************************************
*@brief : return the CAN error count information.
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@param : pErrCnt: a pointer of @ref CAN_ErrCnt_t
*@return: HAL status; the error count value is stored in pErrCnt.
******************************************************************************/
HAL_StatusTypeDef HAL_CAN_GetErrorCNT(CAN_HandleTypeDef *hcan, CAN_ErrCnt_t *pErrCnt)
{
    uint32_t ErrCnt;
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    
    if(!pErrCnt)
        return HAL_ERROR;
    
    ErrCnt = hcan->Instance->ERRCNTR;
    
    pErrCnt->EWL = (uint8_t)((ErrCnt & CAN_ERRCNTR_EWL) >> CAN_ERRCNTR_EWL_Pos);
    
    pErrCnt->TXERR_CNT = (uint8_t)((ErrCnt & CAN_ERRCNTR_TXERR) >> CAN_ERRCNTR_TXERR_Pos);
    
    pErrCnt->RXERR_CNT = (uint8_t)((ErrCnt & CAN_ERRCNTR_RXERR) >> CAN_ERRCNTR_RXERR_Pos);

    return HAL_OK;
}

/******************************************************************************
*@brief : return the CAN Receive FiFo Counter(RMC)
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: the number of packets.
******************************************************************************/
int8_t HAL_CAN_GetReceiveFiFoCounter(CAN_HandleTypeDef *hcan)
{
    uint8_t counter = 0;

    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));

    counter = (uint8_t)((hcan->Instance->RSR & CAN_RSR_RMC) >> CAN_RSR_RMC_Pos);

    return counter;
}


/******************************************************************************
*@brief : Returns the  CANx Receive FiFo start address(RBSA).
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: the address of receive FIFO.
******************************************************************************/
int8_t HAL_CAN_GetReceiveFiFoAddr(CAN_HandleTypeDef *hcan)
{
    uint8_t addr = 0;

    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));

    addr = (uint8_t)((hcan->Instance->RSR & CAN_RSR_RBSA) >> CAN_RSR_RBSA_Pos);

    return addr;
}

/******************************************************************************
*@brief : Releases the Receive FIFO.
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: None
******************************************************************************/
void HAL_CAN_ReleaseReceiveFIFO(CAN_HandleTypeDef *hcan)
{
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    /* Releases the Receive FIFO. */
    hcan->Instance->CMR |= CAN_CMR_RRB;	
}

/******************************************************************************
*@brief : Clear Overload
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: None
******************************************************************************/
void HAL_CAN_ClearOverload(CAN_HandleTypeDef *hcan)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    /* Clear Overload. */
    hcan->Instance->CMR |= CAN_CMR_CDO;	
}

/******************************************************************************
*@brief : Slef Receive request
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: None
******************************************************************************/
void HAL_CAN_SelfReceive(CAN_HandleTypeDef *hcan)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(hcan->Instance));
    /* Slef Receive. */
    hcan->Instance->CMR |= CAN_CMR_SRR;	
    while((hcan->Instance->SR & CAN_SR_TCS) == 0x00); //wait for send ok	
}

/******************************************************************************
*@brief : This function handles CAN interrupt request.
*@param : hcan: pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
*@return: None
******************************************************************************/
void HAL_CAN_IRQHandler(CAN_HandleTypeDef *hcan)
{
    volatile uint32_t IR_val;
    IR_val = hcan->Instance->IR;//read clear 
   
    if(IR_val & CAN_IR_RI) //RI
    {
        /* CAN ReceiveIT complete callback */ 
        HAL_CAN_GetRxMessage(hcan, hcan->RxMessage);  
        if(hcan->CAN_ReceiveIT_Callback)
		    hcan->CAN_ReceiveIT_Callback(hcan);  
    }
    
    if(IR_val & CAN_IR_TI) //TI
    {
        /* CAN TransmitIT complete callback */ 
        if(hcan->CAN_TransmitIT_Callback)
            hcan->CAN_TransmitIT_Callback(hcan);  
    }
    
    if(IR_val & CAN_IR_BEI) //BEI
    {
        /* CAN bus off error recover */ 
        if((hcan->Init.CAN_BOR == CAN_BOR_ENABLE) && (hcan->Instance->MOD & CAN_MOD_RM))
        {
            HAL_CAN_OperatingModeRequest(hcan,CAN_OperatingMode_Normal);//enter CAN_OperatingMode_Normal
        }
    }
}

#endif //HAL_CAN_MODULE_ENABLED
