/* 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 "Can.h"
#include "Can_GeneralTypes.h"
#include "Mcal.h"
#include "Platform_Types.h"
#include "Can_ExtraConfig.h"
extern Can_FilterOfMbType Can_ExtraConfig_0[1];
/* 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;

uint32 rxCnt = 0U;

/* 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);

    /* ========================================================================================== */
    /*                          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)
    {
        Delay_1ms(1);
        Cnt++;
        if (rxCnt == 5) {
            Can_SetControllerMode(CanConf_CanController_CAN0, CAN_CS_STOPPED);
            Can_DeInit();
            Can_ChangeFilterPtr(0, Can_ExtraConfig_0);
            Can_Init(&Can_Config);
            Can_SetControllerMode(CanConf_CanController_CAN0, CAN_CS_STARTED);
            rxCnt++;
        }
    }
    /* 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_CAN0_TX0, &FeedBackPduInfo);
    rxCnt++;
    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();
        }
    }
}

/* USER CODE END 4 */
