

 /**
 ******************************************************************************
 *
 * @file        MG_CAN.c
 * @brief       MG CAN module sample code C file.
 *
 * @par         Project
 *              MG32F02N128
 * @version     V1.00
 * @date        2025/04/28
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 * 
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "MG32_ChipInit.h"
#include "MG32_GPIO_DRV.h"
#include "MG32_CAN_DRV.h"
#include "Sample_CAN.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/


static CAN_RXBuf_TypeDef CAN_Rx_Frame;


/* Private function prototypes -----------------------------------------------*/
void CAN0_IRQHandler(void);


/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/



/**
 *******************************************************************************
 * @brief	   CAN IRQ Handler
 * @details
 * @return      
 * @exception   
 * @note           
 *******************************************************************************
 */
void CAN0_IRQHandler(void)
{
    uint32_t BSP_CAN_ITFlag;
    
    BSP_CAN_ITFlag = CAN_GetITAllFlagStatus(CAN_Module) & CAN_GetITStatus(CAN_Module);
    
    
    /*Bus error*/
    if( BSP_CAN_ITFlag & CAN_IT_BERR)
    {
        CAN_ClearITFlag(CAN_Module,CAN_IT_BERR);
        
        CAN_BusError_Callback();
    }
    
    /*Bus OFF*/
    if( BSP_CAN_ITFlag & CAN_IT_BUS)
    {
        CAN_ClearITFlag(CAN_Module,CAN_IT_BUS);
        // To do...
    }
    /*Error passive*/
    if( BSP_CAN_ITFlag & CAN_IT_EP)
    {
        CAN_ClearITFlag(CAN_Module,CAN_IT_EP);
        // To do...
    }
    /*FIFO 0 receive*/
    if( BSP_CAN_ITFlag & CAN_IT_RX0)
    {
        CAN_ReceiveFrame(CAN_Module,CAN_Rx_FIFO0,&CAN_Rx_Frame);
        
        CAN_RxFIFO0_CpltCallback(CAN_Rx_Frame);
    }
    /*FIFO 1 receive*/
    if( BSP_CAN_ITFlag & CAN_IT_RX1)
    {
        CAN_ReceiveFrame(CAN_Module,CAN_Rx_FIFO1,&CAN_Rx_Frame);
        
        CAN_RxFIFO1_CpltCallback(CAN_Rx_Frame);
        
    }
    /*TX mailbox 0 */
    if( BSP_CAN_ITFlag & CAN_IT_TX0)
    {
        CAN_ClearITFlag(CAN_Module,CAN_IT_TX0);
        
        CAN_TXBuf_CpltCallback(CAN_Tx_Buf0);
    }
    
    /*TX mailbox 1 */
    if( BSP_CAN_ITFlag & CAN_IT_TX1)
    {
        CAN_ClearITFlag(CAN_Module,CAN_IT_TX1);
        
        CAN_TXBuf_CpltCallback(CAN_Tx_Buf1);
    }
    
    /*TX mailbox 2 */
    if( BSP_CAN_ITFlag & CAN_IT_TX2)
    {
        CAN_ClearITFlag(CAN_Module,CAN_IT_TX2);
        
        CAN_TXBuf_CpltCallback(CAN_Tx_Buf2);
    }
}


/**
 *******************************************************************************
 * @brief	  Control CAN TCAN1462 transceiver mode 
 * @details   
 * @param[in] CAN_TransceiverMode:
 *  @arg\b    BSP_CAN_TRANSCEIVER_NORMAL
 *  @arg\b    BSP_CAN_TRANSCEIVER_STANDBY
 * @return  
 * @exception   
 * @note           
 *******************************************************************************
 */
void CAN_TransceiverMode_Select( uint8_t CAN_TransceiverMode)
{
    CAN_STB = CAN_TransceiverMode;
}

/**
 *******************************************************************************
 * @brief	  Trigger CAN transmit data frame
 * @details   
 * @param[in] DF_ID  : CAN data frame ID 
 * @param[in] DF_IDE : CAN data frame IDE bit 
 * @param[in] DF_DLC : CAN data frame data length
 * @param[in] DF_Buf : Pointer CAN transmit data field buffer source
 * @return    Return that this trigger transmit wheter success or not.
 * @exception   
 * @note           
 *******************************************************************************
 */
uint8_t CAN_TransmitDataFrame( uint32_t DF_ID, uint8_t DF_IDE, uint8_t DF_DLC, uint8_t *DF_Buf)
{
    uint8_t            CAN_TXDF_Tmp;
    uint8_t            CAN_TXDF_BufIndex;
    uint32_t           CAN_TXDF_Status = 0;
    CAN_TXBuf_TypeDef  CAN_TXDF;
    
    for(CAN_TXDF_BufIndex = 0; CAN_TXDF_BufIndex < SMP_CAN_TXMAILBOX_MAX; CAN_TXDF_BufIndex++)
    {
        CAN_TXDF_Status = CAN_GetTXBufferStatus(CAN_Module, (CAN_TXIndex_TypeDef)CAN_TXDF_BufIndex);
        
        if((CAN_TXDF_Status & CAN_TRANSMIT_STATE_BUSY)==0)
        {
            break;
        }
    }
    
    if((CAN_TXDF_Status & CAN_TRANSMIT_STATE_BUSY)!=0)
    {
        return(SMP_CAN_TX_BUSY);
    }
    
    if( DF_IDE == 1)
    {
        CAN_TXDF.Format.Field.SID = ((DF_ID >> CAN_RDAT00_RX0_SID_shift_w) & 0x000007FF);
        CAN_TXDF.Format.Field.EID = ((DF_ID >> CAN_RDAT00_RX0_EID_shift_w) & 0x0003FFFF);
    }
    else
    {
        CAN_TXDF.Format.Field.SID = DF_ID;
    }
    
    CAN_TXDF.Format.Field.IDE = DF_IDE;
    CAN_TXDF.Format.Field.RTR = 0;
    CAN_TXDF.Format.Field.DLC = DF_DLC;
    for(CAN_TXDF_Tmp = 0; CAN_TXDF_Tmp < DF_DLC; CAN_TXDF_Tmp++)
    {
        CAN_TXDF.Format.Field.Data[CAN_TXDF_Tmp] = DF_Buf[CAN_TXDF_Tmp];
    }
    CAN_SendFrame(CAN_Module,(CAN_TXIndex_TypeDef)CAN_TXDF_BufIndex,&CAN_TXDF);
    
    return(CAN_TXDF_BufIndex);
}

/**
 *******************************************************************************
 * @brief	  Trigger CAN transmit remote frame
 * @details   
 * @param[in] RF_ID  : CAN remote frame ID 
 * @param[in] RF_IDE : CAN remote frame IDE bit 
 * @param[in] RF_DLC : CAN remote frame data length
 * @return    Return that this trigger transmit wheter success or not.
 * @exception   
 * @note        
 *******************************************************************************
 */
uint8_t CAN_TransmitRemoteFrame( uint32_t RF_ID, uint8_t RF_IDE, uint8_t RF_DLC)
{
    uint8_t            CAN_TXRF_Tmp;
    uint32_t           CAN_TXRF_Status = 0;
    CAN_TXBuf_TypeDef  CAN_TXRF;
    
    for(CAN_TXRF_Tmp = 0; CAN_TXRF_Tmp < SMP_CAN_TXMAILBOX_MAX; CAN_TXRF_Tmp++)
    {
        CAN_TXRF_Status = CAN_GetTXBufferStatus(CAN_Module, (CAN_TXIndex_TypeDef)CAN_TXRF_Tmp);
        
        if((CAN_TXRF_Status & CAN_TRANSMIT_STATE_BUSY)==0)
        {
            break;
        }
    }
    
    if((CAN_TXRF_Status & CAN_TRANSMIT_STATE_BUSY)!=0)
    {
        return(SMP_CAN_TX_BUSY);
    }
    
    if( RF_IDE == 1)
    {
        CAN_TXRF.Format.Field.SID = ((RF_ID >> CAN_RDAT00_RX0_SID_shift_w) & 0x000007FF);
        CAN_TXRF.Format.Field.EID = ((RF_ID >> CAN_RDAT00_RX0_EID_shift_w) & 0x0003FFFF);
    }
    else
    {
        CAN_TXRF.Format.Field.SID = RF_ID;
    }
    CAN_TXRF.Format.Field.IDE = RF_IDE;
    CAN_TXRF.Format.Field.RTR = 1;
    CAN_TXRF.Format.Field.DLC = RF_DLC;
    CAN_SendFrame(CAN_Module,(CAN_TXIndex_TypeDef)CAN_TXRF_Tmp,&CAN_TXRF);

    
    return(CAN_TXRF_Tmp);    
}

/**
 *******************************************************************************
 * @brief	   main function  
 * @details     
 * @return      
 * @exception  No 
 * @note
 *******************************************************************************
 */
void CAN_Initial(void)
{
    /*Declare Variable*/
    CAN_Bittime_TypeDef   CAN_Bit;
    PIN_InitTypeDef       CAN_Pin;
    CAN_Filter_TypeDef    CAN_Filter;
    
    
    /*CAN Pin Initial*/
    CAN_Pin.PINX_Mode               = PINX_Mode_PushPull_O;
    CAN_Pin.PINX_PUResistant        = PINX_PUResistant_Disable;
    CAN_Pin.PINX_Speed              = PINX_Speed_High;
    CAN_Pin.PINX_Inverse            = PINX_Inverse_Disable;
    CAN_Pin.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    CAN_Pin.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    CAN_Pin.PINX_Alternate_Function = CAN_TX_AFS;
    GPIO_PinMode_Config( CAN_TX_PINX ,&CAN_Pin);                 // CAN_TX pin initial
    
    CAN_Pin.PINX_Alternate_Function = CAN_STB_AFS;                            
    GPIO_PinMode_Config( CAN_STB_PINX ,&CAN_Pin);                // CAN_STB pin initial (The pin is TCAN1462/TCAN1472 standby mode control pin)
    
    CAN_Pin.PINX_Mode               = PINX_Mode_Digital_I;
    CAN_Pin.PINX_PUResistant        = PINX_PUResistant_Disable;
    CAN_Pin.PINX_Alternate_Function = CAN_RX_AFS; 
    GPIO_PinMode_Config( CAN_RX_PINX ,&CAN_Pin);                 // CAN_RX pin initial 
    
    /*CAN module into initial mode*/
    CAN_OperationMode_Select(CAN_Module,CAN_Initial_Mode);  
    while(CAN_GetOperationMode(CAN_Module)!=CAN_INITIAL_MODE);
    
    /*Bit-time configure ( 500 KHz sample point at 87.5% in APB = 48MHz)
       TQ = prescaler / ( APB frequence)
       Bit time = ( 1 + (TimeSeg1 + 1) + ( TimeSeg2 + 1) ) * TQ
    */
    CAN_ClockSource_Select(CAN_Module,CAN_Clock_PROC);
    CAN_Bit.CTR.MBIT.prescaler     = (6 - 1);
    CAN_Bit.CTR.MBIT.TimeSeg1      = (13 - 1);
    CAN_Bit.CTR.MBIT.TimeSeg2      = (2 - 1);
    CAN_Bit.CTR.MBIT.SyncJumpWidth = (1 - 1);
    CAN_BitTime_Config( CAN_Module, &CAN_Bit);
    
    /*Receive FIFO configure*/
    CAN_RXFIFOType_Select(CAN_Module,CAN_RXFIFO_Two);
    CAN_RXOverrunMode_Select(CAN_Module,CAN_RXOverrun_Keep);
    CAN_ResetRXFIFO( CAN_Module, CAN_Rx_FIFO0);
    
    /*TX mode configure*/
    CAN_TXPriorityMode_Select(CAN_Module,CAN_TXPriority_SEQ);
    
    /*Error counter reset*/
    CAN_SetRXErrorCounter(CAN_Module,0x00);
    CAN_SetTXErrorCounter(CAN_Module,0x00);
    
    /*Filter configure*/
    /*Filter 0 configure : 32 bit Mask mode, and the configuration only receive. 
        *. Classical Base frame 
           >> Base ID  0x000 ~ 0x00F
    */
    CAN_AcceptanceFilterMode_Config( CAN_Module, CAN_Filter0, CAN_Filter_32bitMask); // Select the filter is 32 bit Mask mode
    
    CAN_Filter.AFnR.Mask32.ID.SID    = 0x000;       
    CAN_Filter.AFnR.Mask32.ID.EID    = 0x00000;     
    CAN_Filter.AFnR.Mask32.ID.IDE    = 0;           
    CAN_Filter.AFnR.Mask32.ID.RTR    = 0;           
    
    CAN_Filter.AFnR.Mask32.Mask.SID  = 0x7F0;         // The mask bit = 0  is the bit is don't care.
    CAN_Filter.AFnR.Mask32.Mask.EID  = 0x00000;       // The mask bit = 0  is the bit is don't care.
    CAN_Filter.AFnR.Mask32.Mask.IDE  = 1;             // The mask bit = 0  is the bit is don't care.
    CAN_Filter.AFnR.Mask32.Mask.RTR  = 0;             // The mask bit = 0  is the bit is don't care.
    CAN_AccptanceFilter_Config(CAN_Module,CAN_Filter0,&CAN_Filter);
    
    CAN_AcceptanceFilterFIFO_Select( CAN_Module, CAN_Filter0, CAN_Filter_FIFO0);  //The filter use FIFO 0
    CAN_AcceptanceFilter_Cmd( CAN_Module, CAN_Filter0, ENABLE);
    
    /*Filter 1 configure : 32 bit Mask mode, and the configuration only receive. 
        *. Classical base frame 
           >> Base ID 0x048
        *. Classical extended frame
           >> Base ID 0x048  and identifier extension 0x00000 ~ 0x0000F
    */
    CAN_AcceptanceFilterMode_Config( CAN_Module, CAN_Filter1, CAN_Filter_32bitMask); // Select the filter is 32 bit Mask mode
    
    CAN_Filter.AFnR.Mask32.ID.SID    = 0x048;       
    CAN_Filter.AFnR.Mask32.ID.EID    = 0x00000;     
    CAN_Filter.AFnR.Mask32.ID.IDE    = 0;           
    CAN_Filter.AFnR.Mask32.ID.RTR    = 0;           
    
    CAN_Filter.AFnR.Mask32.Mask.SID  = 0x7FF;          
    CAN_Filter.AFnR.Mask32.Mask.EID  = 0x3FFF0;        
    CAN_Filter.AFnR.Mask32.Mask.IDE  = 0;             
    CAN_Filter.AFnR.Mask32.Mask.RTR  = 0;              
    CAN_AccptanceFilter_Config(CAN_Module,CAN_Filter1,&CAN_Filter);
    
    CAN_AcceptanceFilterFIFO_Select( CAN_Module, CAN_Filter1, CAN_Filter_FIFO0);  //The filter use FIFO 0
    CAN_AcceptanceFilter_Cmd( CAN_Module, CAN_Filter1, ENABLE);
    
    /*Filter 2 configure : 32 bit List mode, and the configuration only receive. 
        *. Classical base data frame 
           >> Base ID 0x765
        *. Classical extended data frame
           >> Base ID 0x000 and identifier extension 0x4843;
    */
    CAN_AcceptanceFilterMode_Config( CAN_Module, CAN_Filter2, CAN_Filter_32bitList); // Select the filter is 32 bit List mode
    
    CAN_Filter.AFnR.List32.List0.SID = 0x055;
    CAN_Filter.AFnR.List32.List0.EID = 0;
    CAN_Filter.AFnR.List32.List0.IDE = 0;
    CAN_Filter.AFnR.List32.List0.RTR = 0;
    
    CAN_Filter.AFnR.List32.List1.SID = 0x000;
    CAN_Filter.AFnR.List32.List1.EID = 0x4843;
    CAN_Filter.AFnR.List32.List1.IDE = 1;
    CAN_Filter.AFnR.List32.List1.RTR = 0;
                
    CAN_AccptanceFilter_Config(CAN_Module,CAN_Filter2,&CAN_Filter);
    
    CAN_AcceptanceFilterFIFO_Select( CAN_Module, CAN_Filter2, CAN_Filter_FIFO1);  //The filter use FIFO 1
    CAN_AcceptanceFilter_Cmd( CAN_Module, CAN_Filter2, ENABLE);
    

    /*Interrupt configure*/
    CAN_ClearITFlag(CAN_Module,(CAN_IT_TX0 | CAN_IT_TX1 | CAN_IT_TX2 | \
                                CAN_IT_RX0 | CAN_IT_RX1 | \
                                CAN_IT_EP  | CAN_IT_BUS | CAN_IT_BERR));
    CAN_IT_Config(CAN_Module, ( CAN_IT_TX0 | CAN_IT_TX1 | CAN_IT_TX2 | \
                               (CAN_IT_RX0 | CAN_IT_RX1 | \
                                CAN_IT_EP  | CAN_IT_BUS )),ENABLE);
                                
//    CAN_IT_Config(CAN_Module, ( CAN_IT_TX0 | CAN_IT_TX1 | CAN_IT_TX2 | \
//                               (CAN_IT_RX0 | CAN_IT_RX1 | \
//                                CAN_IT_EP  | CAN_IT_BUS | CAN_IT_BERR)),ENABLE);
                                
    CAN_ITEA_Cmd(CAN_Module,ENABLE);
    NVIC_EnableIRQ(CAN0_IRQn);
    
    /*CAN Enable*/
    CAN_Cmd(CAN_Module, ENABLE);
    
    /*CAN into Normal mode*/
    CAN_OperationMode_Select(CAN_Module,CAN_Normal_Mode);  
    while(CAN_GetOperationMode(CAN_Module)!=CAN_NORMAL_MODE);
    
    /*CAN transceiver to normal mode*/
    CAN_TransceiverMode_Select(SMP_CAN_TRANSCEIVER_NORMAL);
}



/**
 *******************************************************************************
 * @brief	    RX FIFO0 receive call back function
 * @details     
 * @param[in]   CAN_Rx1_Frame : RX FIFO0 receive frame.
 * @return      No.
 * @exception   No
 * @note        No
 *******************************************************************************
 */
__WEAK void CAN_RxFIFO0_CpltCallback(CAN_RXBuf_TypeDef CAN_Rx1_Frame)
{
    //=========================================================
    //Prevent unused argument compilation warning
    ((void)(CAN_Rx1_Frame));
    
    //=========================================================
    //NOTE : This function should not be modified , when the 
    //       callback is needed, the CAN_RxFIFO0_CpltCallback can
    //       be implemented in the user file.   
}

/**
 *******************************************************************************
 * @brief	    RX FIFO0 receive call back function
 * @details     
 * @param[in]   CAN_Rx1_Frame : RX FIFO1 receive frame. 
 * @return      No.
 * @exception   No
 * @note        No
 *******************************************************************************
 */
__WEAK void CAN_RxFIFO1_CpltCallback(CAN_RXBuf_TypeDef CAN_Rx1_Frame)
{
    //=========================================================
    //Prevent unused argument compilation warning
    ((void)(CAN_Rx1_Frame));
    
    //=========================================================
    //NOTE : This function should not be modified , when the 
    //       callback is needed, the CAN_RxFIFO1_CpltCallback can
    //       be implemented in the user file.   
}


/**
 *******************************************************************************
 * @brief	    TX Buffer call back function.
 * @details     
 * @param[in]   CAN_TxBuf_Index : TX message buffer inedex number
 * @return      No.
 * @exception   No
 * @note        No
 *******************************************************************************
 */
__WEAK void CAN_TXBuf_CpltCallback(CAN_TXIndex_TypeDef CAN_TxBuf_Index)
{
    uint32_t CAN_TXBuf_CpltTmp;
    
    CAN_TXBuf_CpltTmp = CAN_GetTXBufferStatus(CAN_Module,CAN_TxBuf_Index);
    
    /*Transmit success*/
    if( CAN_TXBuf_CpltTmp == CAN_TRANSMIT_STATE_SUCCESS)
    {
        //To do...
    }
    /*Transmit failure*/
    else if( CAN_TXBuf_CpltTmp == CAN_TRANSMIT_STATE_FAILURE)
    {
        //To do...
    }
    
    //=========================================================
    //NOTE : This function should not be modified , when the 
    //       callback is needed, the CAN_RxFIFO1_CpltCallback can
    //       be implemented in the user file.   
}

/**
 *******************************************************************************
 * @brief	    Bus error call back function.
 * @details     
 * @param[in]   
 * @return      No.
 * @exception   No
 * @note        No
 *******************************************************************************
 */
__WEAK void CAN_BusError_Callback(void)
{
    uint16_t CAN_ErrorCode;
    
    CAN_ErrorCode = CAN_GetErrorCode(CAN_Module);
    
    switch((CAN_ErrorCode & 0x0700))
    {
        case CAN_ERR_CODE_BIT:
                                //To do...
                                break;
        case CAN_ERR_CODE_FORM:
                                //To do...
                                break;
        case CAN_ERR_CODE_STUFF:
                                //To do...
                                break;
        case CAN_ERR_CODE_CRC:
                                //To do...
                                break;
        /* For example no ACK*/
        case CAN_ERR_CODE_OTHER:
        default:    
                                //To do...
                                break;
    }

    //=========================================================
    //NOTE : This function should not be modified , when the 
    //       callback is needed, the CAN_RxFIFO1_CpltCallback can
    //       be implemented in the user file.   
}




