/* USER CODE BEGIN Header */
/* you can remove the copyright */

/*
 *  Copyright 2020-2023 Yuntu Microelectronics co.,ltd
 *  All rights reserved.
 * 
 *  YUNTU Confidential. This software is owned or controlled by YUNTU and may only be
 *  used strictly in accordance with the applicable license terms. By expressly
 *  accepting such terms or by downloading, installing, activating and/or otherwise
 *  using the software, you are agreeing that you have read, and that you agree to
 *  comply with and are bound by, such license terms. If you do not agree to be
 *  bound by the applicable license terms, then you may not retain, install,
 *  activate or otherwise use the software. The production use license in
 *  Section 2.3 is expressly granted for this software.
 * 
 * @file main.c
 * @brief 
 * 
 */

/* USER CODE END Header */
#include "Mcal.h"
/* Includes ------------------------------------------------------------------*/

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define CAN_ID_TYPE_FD_FRAME_MASK 		(0x40000000U)
#define CAN_ID_TYPE_EXTENDED_FRAME_MASK (0x80000000U)

#define CAN_LEGACY_FORMAT_A_STD_OFFSET  (19U)
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* ============================================================================================== */
/*                                         Sdu data define                                        */
/* ============================================================================================== */
uint8 FeedBackData[8] = {0x00};

uint8 sduData16[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F
};

/* ============================================================================================== */
/*                                       LOCAL STATE DEFINE                                       */
/* ============================================================================================== */
typedef enum
{
    UNINIT,        /* Can_Demo is UNINIT */
    CAN1_TX_CAN0,  /* Can_Demo is working in CAN1 send msg to CAN0 */
    CAN0_TX_CAN1,  /* Can_Demo is working in CAN0 send msg to CAN1 */
    CAN3_TX_CAN2,  /* Can_Demo is working in CAN3 send msg to CAN2 */
    CAN2_TX_CAN3   /* Can_Demo is working in CAN2 send msg to CAN3 */
} Demo_StateType;

/* ============================================================================================== */
/*                                      LOCAL FUNCTION DEFINE                                     */
/* ============================================================================================== */
/**
 * @brief This function is used for software delay 1ms.
 * 
 * @param[in] Ms delay x ms.
 */
void Delay_1ms(uint32 Ms);

/**
 * @brief This callback will be called when the CAN controller enters the bus-off state.
 * 
 * @note 1. Bus-off will not happen when no message needs to be transmitted. If you want to generate
 *          a bus-off manually, please ensure the controller is transmitting some messages.
 *       2. CAN2 is set to use polling for the bus-off event, but bus-off recovery is set to auto by
 *          default, so before this function is called, the controller may recover automatically. If
 *          you need to recover from bus-off manually, please assert the flag in the CAN2 > CTRL1[BOFFREC] register.
 *       3. Callback name is setting in yct file. After this callback, the Can channel will be stop by
 *          software, you need to call `Can_SetControllerMode(CanConf_CanController_CAN2, CAN_CS_STARTED)`
 *          to START the CanController again.
 */
void CanBusOffCAN2(void);

 /**
 * @brief This call back will be called when can controller enter bus-off.
 * 
 * @note 1. bus-off will not be happen when no msg need to transmit. if you want to generate a bus-off
 *          call handlely, please confirm the controller is transmitting some msg.
 *       2. Callback name is setting in yct file. After this callback, the Can channel will be stop by
 *          software, you need to call `Can_SetControllerMode(CanConf_CanController_CAN3, CAN_CS_STARTED)`
 *          to START the CanController again.
 */
void CanBusOffCAN3(void);

/**
 * @brief The fellowing function is used for each stage.
 */
void DemoStageFunc0_CAN1_TX_CAN0(void);
void DemoStageFunc1_CAN0_TX_CAN1(void);
void DemoStageFunc2_CAN3_TX_CAN2(void);
void DemoStageFunc3_CAN2_TX_CAN3(void);

/**
 * @brief Receive callback.
 * 
 * @details Once received a msg, this callback will simply send the CanId of received msg to 0x11111111,
 *          you could check the data of 0x11111111 to check which CanId had been received.
 *
 * @param Hrh Hardware receive object handler id.
 * @param CanId msg id
 * @param CanDataLength msg len
 * @param CanSduPtr msg ptr
 * @return result of this callback
 */
boolean CanReceiveCallOut(uint8 Hrh, Can_IdType CanId, uint8 CanDataLength, const uint8* CanSduPtr);
/* ============================================================================================== */
/*                                       GLOBAL DATA DEFINE                                       */
/* ============================================================================================== */
/**
 * The following flag is used to distinguish whether CAN2 has already entered bus-off mode and needs
 * to be restarted
 */
boolean CAN2_BusOffFlag = FALSE;
boolean CAN3_BusOffFlag = FALSE;

Can_PduType TempPduInfo = {
    .swPduHandle = 60U,
	.id = 0x000U,
    .length = 16U,
    .sdu = sduData16,
};

Can_PduType FeedBackPduInfo = {
    .swPduHandle = 60U,
	.id = 0x11111111U | CAN_ID_TYPE_EXTENDED_FRAME_MASK,
    .length = 8U,
    .sdu = FeedBackData,
};

/**
 * @brief This value is used to show which stage is the Can_demo in.
 */
Demo_StateType Demo_State = UNINIT;

uint32 tempSent, handleAcc;

/* USER CODE END PV */

/* Private function declare --------------------------------------------------*/
/* USER CODE BEGIN PFDC */
void CanTransmitCallOut(PduIdType TxPduId)
{
    handleAcc = TxPduId;
    tempSent ++;
}

/* USER CODE END PFDC */
static void Board_Init(void);

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */


/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
    /* USER CODE BEGIN 1 */
    Mcu_Init(&Mcu_Config);
    Mcu_InitClock(0);
#if (MCU_NO_PLL == STD_OFF)
    while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() )
    {
    /* Busy wait until the System PLL is locked */
    }
    Mcu_DistributePllClock();
#endif
    /* USER CODE END 1 */ 
    Board_Init();
    /* USER CODE BEGIN 2 */

    /**
     * @note: According to [SWS_Can_00245], the Can controller should be started separately by
     *        calling the function `Can_SetControllerMode(<ControllerId>, CAN_CS_STARTED)`
     */
    Can_SetControllerMode(CanConf_CanController_CAN0, CAN_CS_STARTED);
    Can_SetControllerMode(CanConf_CanController_CAN1, CAN_CS_STARTED);
    Can_SetControllerMode(CanConf_CanController_CAN2, CAN_CS_STARTED);
    Can_SetControllerMode(CanConf_CanController_CAN3, CAN_CS_STARTED);

    /* ========================================================================================== */
    /*                          Change Demo_State to start relative stage                         */
    /* ========================================================================================== */
    Demo_State = CAN1_TX_CAN0;

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    uint32 Cnt = 0U;
    while (1)
    {
        /* Polling stage */
        if (Cnt % 2 == 0)
        {
            /* This function is used to polling read status */
            Can_MainFunction_Read_CanReadWrite2ms();
            /* This function is used to polling write status */
            Can_MainFunction_Write_CanReadWrite2ms();
            /* This function is used to polling can bus off notification */
            Can_MainFunction_BusOff();
        }
        if (Cnt % 500 == 0)
        {
            Can_MainFunction_Read_CanReadWrite500ms();
            Can_MainFunction_Write_CanReadWrite500ms();
        }

        /* Send function will be called in period of 1s */
        if (Cnt % 1000 == 0)
        {
            switch (Demo_State) {
                case CAN1_TX_CAN0:
                    DemoStageFunc0_CAN1_TX_CAN0();
                    break;
                case CAN0_TX_CAN1:
                    DemoStageFunc1_CAN0_TX_CAN1();
                    break;
                case CAN3_TX_CAN2:
                    DemoStageFunc2_CAN3_TX_CAN2();
                    break;
                case CAN2_TX_CAN3:
                    DemoStageFunc3_CAN2_TX_CAN3();
                    break;
                default:
                    break;
            }
        }
        if (CAN2_BusOffFlag)
        {
            CAN2_BusOffFlag = FALSE;
            Can_SetControllerMode(CanConf_CanController_CAN2, CAN_CS_STARTED);
        }
        if (CAN3_BusOffFlag)
        {
            CAN3_BusOffFlag = FALSE;
            Can_SetControllerMode(CanConf_CanController_CAN3, CAN_CS_STARTED);
        }
        Delay_1ms(1);
        Cnt++;
    }
    /* USER CODE END WHILE */
        /* USER CODE BEGIN 3 */  
    /* USER CODE END 3 */
}

static void Board_Init(void)
{
    Port_Init(&Port_Config);
    Can_Init(&Can_Config);
    Platform_Init(NULL_PTR);
}

/* USER CODE BEGIN 4 */

boolean CanReceiveCallOut(uint8 Hrh, Can_IdType CanId, uint8 CanDataLength, const uint8* CanSduPtr)
{
    FeedBackPduInfo.sdu[0] = ((uint8*)(&CanId))[3];
    FeedBackPduInfo.sdu[1] = ((uint8*)(&CanId))[2];
    FeedBackPduInfo.sdu[2] = ((uint8*)(&CanId))[1];
    FeedBackPduInfo.sdu[3] = ((uint8*)(&CanId))[0];
    Can_Write(CanConf_CanHardwareObject_CAN1_TX2, &FeedBackPduInfo);
    Can_Write(CanConf_CanHardwareObject_CAN3_TX0, &FeedBackPduInfo);
    return TRUE;
}

void Delay_1ms(uint32 Ms)
{
    while (Ms > 0)
    {
        --Ms;
        for (uint16 Cnt = 0; Cnt < 25000; ++Cnt)
        {
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
        }
    }
}


void CanBusOffCAN2(void)
{
    CAN2_BusOffFlag = TRUE;
}

void CanBusOffCAN3(void)
{
    CAN3_BusOffFlag = TRUE;
}

void DemoStageFunc0_CAN1_TX_CAN0(void)
{
    /**
    * In this stage, Can_Demo will send the messages with IDs from 0x101 to 0x10A in the following order:
    *   - Tx: 0x101, 0x00000102, 0x00000104, 0x103, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A
    *   - Rx: 0x101, 0x00000102, 0x00000104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x103
    * Messages with IDs from 0x101 to 0x104 are received by MailBox.
    * Messages with standard IDs between 0x105 and 0x10A are received by Enhanced FIFO.
    *
    * @note 1. The message with ID 0x00000104 will be sent before 0x103 in the current demo because
    *          0x00000104 has a higher priority in this demo.
    *       2. The message 0x103 will be received by polling for 500ms, so this message appears to 
    *          be the last received message in the software.
    */

    /* CAN0_RX0 FD STD INT*/
    TempPduInfo.id = 0x101 | CAN_ID_TYPE_FD_FRAME_MASK;
    TempPduInfo.length = 16;
    Can_Write(CanConf_CanHardwareObject_CAN1_TX0, &TempPduInfo);
    
    /* CAN0_RX1 FD EXT INT*/
    TempPduInfo.id = 0x00000102 | CAN_ID_TYPE_FD_FRAME_MASK | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 16;
    Can_Write(CanConf_CanHardwareObject_CAN1_TX0, &TempPduInfo);

    /* CAN0_RX2 2.0 STD Polling500ms */
    TempPduInfo.id = 0x103;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN1_TX0, &TempPduInfo);

    /* CAN0_RX3 2.0 EXT Polling2ms*/
    TempPduInfo.id = 0x00000104 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN1_TX0, &TempPduInfo);

    /* CAN0_RX_FIFO 0x105 ~ 0x10A */
    for (uint8 TempCnt = 0U; TempCnt < 6U; ++TempCnt)
    {
        TempPduInfo.id = (0x105 + (uint32)TempCnt) | CAN_ID_TYPE_FD_FRAME_MASK;
        Can_Write(CanConf_CanHardwareObject_CAN1_TX1, &TempPduInfo);
    }
}

void DemoStageFunc1_CAN0_TX_CAN1()
{
    /**
    * In this stage, Can_Demo will send the messages with IDs from 0x201 to 0x20A in the following order:
    *   - Tx: 0x00000201, 0x00000202, 0x00000203, 0x00000204, 0x00000205, \
    *         0x00000206, 0x00000207, 0x00000208, 0x00000209, 0x0000020A, 0x20A
    *   - Rx: 0x00000201, 0x00000202, 0x00000203, 0x00000204, 0x00000205, \
    *         0x00000206, 0x00000207, 0x00000208, 0x00000209, 0x20A
    * All messages are received by Enhanced FIFO.
    *
    * @note 1. The msg with id 0x0000020A will be ignored because no filter match this id.
    */

    /* CAN1_RX_FIFO 0x00000201 ~ 0x00000209 */
    TempPduInfo.length = 16;
    for (uint8 TempCnt = 0U; TempCnt < 10U; ++TempCnt)
    {
        TempPduInfo.id = (0x00000201 + (uint32)TempCnt) | CAN_ID_TYPE_FD_FRAME_MASK | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
        Can_Write(CanConf_CanHardwareObject_CAN0_TX0, &TempPduInfo);
    }

    /* CAN1_RX_FIFO 0x20A */
    TempPduInfo.id = 0x20A | CAN_ID_TYPE_FD_FRAME_MASK;
    TempPduInfo.length = 16;
    Can_Write(CanConf_CanHardwareObject_CAN0_TX0, &TempPduInfo);
}

void DemoStageFunc2_CAN3_TX_CAN2()
{
    /**
    * In this stage, Can_Demo will send the messages with IDs from 0x301 to 0x305 in the following order:
    *   - Tx: 0x301, 0x00000302, 0x00000304, 0x303, 0x305
    *   - Rx: 0x305,      0x301,      0x302, 0x304, 0x303
    * All messages are received by Legacy FIFO.
    *
    * @note 1. The Legacy FIFO filter format is: `CAN_LEGACY_RX_FIFO_FILTER_FORMAT_A`.
    *       2. The message with ID 0x303 is matched by Global_Filter0. See Figure 20.4 "ID Filter Table Structure"
    *          in the reference manual for why 0xC0C00000 matches 0x303.
    *       3. The message with ID 0x305 will be received in software because other messages are received
    *          using 2ms polling.
    */
    /* CAN2_RX_FIFO Individual_Filter0 */
    TempPduInfo.id = 0x301;
    Can_Write(CanConf_CanHardwareObject_CAN3_TX0, &TempPduInfo);
    
    /* CAN2_RX_FIFO Individual_Filter1 */
    TempPduInfo.id = 0x00000302 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    Can_Write(CanConf_CanHardwareObject_CAN3_TX0, &TempPduInfo);

    /* CAN2_RX_FIFO Global_Filter0 */
    TempPduInfo.id = 0x303;
    Can_Write(CanConf_CanHardwareObject_CAN3_TX0, &TempPduInfo);

    /* CAN2_RX_FIFO Global_Filter1 */
    TempPduInfo.id = 0x00000304 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN3_TX0, &TempPduInfo);

    /* CAN2_RX0 */
    TempPduInfo.id = 0x305;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN3_TX0, &TempPduInfo);
}

void DemoStageFunc3_CAN2_TX_CAN3()
{
    /**
    * In this stage, Can_Demo will send the messages with IDs from 0x301 to 0x305 in the following order:
    *   - Tx: 0x401,      0x100, 0x04020000, 0x04030000,      0x101, 0x04050000,      0x404, 0x10100000
    *   - Rx: 0x401,      0x100, 0x04020000, 0x04030000, 0x04050000,      0x404, 0x10100000
    * All messages are received by Legacy FIFO.
    *
    * @note 1. The Legacy FIFO filter format is: `CAN_LEGACY_RX_FIFO_FILTER_FORMAT_B`.
    *       2. The message with ID 0x100 is matched by Individual_Filter2. See Figure 20.4 "ID Filter Table Structure"
    *          in the reference manual for why 0x04020000 matches 0x100.
    *       3. The message with ID 0x404 is matched by Individual_Filter3. See Figure 20.4 "ID Filter Table Structure"
    *          in the reference manual for why 0x10100000 matches 0x404.
    *       4. The message with ID 0x101 will be ignored because no filter match this id.
    */
    /* CAN3_RX_FIFO Individual_Filter0 */
    TempPduInfo.id = 0x401;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);

    /* CAN3_RX_FIFO Individual_Filter1 */
    TempPduInfo.id = 0x04020000 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);

    /* CAN3_RX_FIFO Individual_Filter2 */
    TempPduInfo.id = 0x04030000 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);

    /* CAN3_RX_FIFO Individual_Filter2 */
    TempPduInfo.id = 0x100;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);

    TempPduInfo.id = 0x101;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);

    /* CAN3_RX_FIFO Individual_Filter3 */
    TempPduInfo.id = 0x10100000 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);
    
    /* CAN3_RX_FIFO Individual_Filter3 */
    TempPduInfo.id = 0x404;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);

    /* CAN3_RX_FIFO Global_Filter0 */
    TempPduInfo.id = 0x04050000 | CAN_ID_TYPE_EXTENDED_FRAME_MASK;
    TempPduInfo.length = 8;
    Can_Write(CanConf_CanHardwareObject_CAN2_TX0, &TempPduInfo);
}

/* USER CODE END 4 */
