/**
*   @file    can_task.c
*   @version 1.0.0
*
*   @brief   Can task init and runtime
*   @details The base task includes the following:
*            1) toggling LED1(PTF8) every 100ms;
*            2) sample ADC0/ADC1/ADC2 channels;
*            3) use PTF11_EMIOS2_CH11 to control PWM duty for LED4(PTF11);
*            4) monitor user buttons and toggle LED2(PTF9)/LED3(PTF10) respectively;
*               Btn1=PTC20_SIUL2_EIRQ16,
*               Btn2=PTC21_SIUL2_EIRQ17,
*
*   This file contains sample code only. It is not part of the production code deliverables.
*
*   @addtogroup Application_Tasks
*   @{
*/

#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************
 * The can task includes the following:
 * 1) CAN0 send CAN FD frames to CAN1;
 * 2) CAN2 send classical frames to CAN3;
 * 3) CAN1 and CAN3 will print the received message;
 ************************************************************/

/*==================================================================================================
*                                        INCLUDE FILES
* 1) Basic RTD modules includes
* 2) MCU registers definitions includes
* 3) needed interfaces from external units
==================================================================================================*/
#include "bsp.h"
#include <TJA1145FD_ApplHint.h>

/*==================================================================================================
*                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/

/*==================================================================================================
*                                       LOCAL MACROS
==================================================================================================*/
#define FLEXCAN0_INST 0U
#define FLEXCAN0_TX_MSG_ID 0x01u
#define FLEXCAN0_RX_MSG_ID 0x02u
#define FLEXCAN0_RX_MB_IDX 1U
#define FLEXCAN0_TX_MB_IDX 0U

#define FLEXCAN1_INST 1U
#define FLEXCAN1_TX_MSG_ID 0x10u
#define FLEXCAN1_RX_MSG_ID 0x11u
#define FLEXCAN1_RX_MB_IDX 1U
#define FLEXCAN1_TX_MB_IDX 0U

#define FLEXCAN2_INST 2U
#define FLEXCAN2_TX_MSG_ID 0x20u
#define FLEXCAN2_RX_MSG_ID 0x21u
#define FLEXCAN2_RX_MB_IDX 1U
#define FLEXCAN2_TX_MB_IDX 0U

#define FLEXCAN3_INST 3U
#define FLEXCAN3_TX_MSG_ID 0x30u
#define FLEXCAN3_RX_MSG_ID 0x31u
#define FLEXCAN3_RX_MB_IDX 1U
#define FLEXCAN3_TX_MB_IDX 0U

/*==================================================================================================
*                                      LOCAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                      LOCAL VARIABLES
==================================================================================================*/

/*==================================================================================================
*                                      GLOBAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                      GLOBAL VARIABLES
==================================================================================================*/
/* The template buffer type of CAN frame */
Flexcan_Ip_DataInfoType FLEXCAN_RxTx_info = {
		.msg_id_type = FLEXCAN_MSG_ID_STD,
		.data_length = 8u,
		.is_polling = false,
		.is_remote = false
};

/* The template Tx Data for CAN0 */
uint8 FLEXCAN0_Tx_Data[8] = {1,2,3,4,5,6,7};
/* The Rx buffer for CAN0 RX MB */
Flexcan_Ip_MsgBuffType FLEXCAN0_RxDta;

uint8 FLEXCAN1_Tx_Data[8] = {1,2,3,4,5,6,7};
Flexcan_Ip_MsgBuffType FLEXCAN1_RxDta;

uint8 FLEXCAN2_Tx_Data[8] = {1,2,3,4,5,6,7};
Flexcan_Ip_MsgBuffType FLEXCAN2_RxDta;

uint8 FLEXCAN3_Tx_Data[8] = {10,12,13,14,15,16,17};
Flexcan_Ip_MsgBuffType FLEXCAN3_RxDta;

/*==================================================================================================
*                                   LOCAL FUNCTION PROTOTYPES
==================================================================================================*/

/*==================================================================================================
*                                       External FUNCTIONS
==================================================================================================*/
extern void CAN0_ORED_0_31_MB_IRQHandler(void);
extern void CAN1_ORED_0_31_MB_IRQHandler(void);
extern void CAN2_ORED_0_31_MB_IRQHandler(void);
extern void CAN3_ORED_0_31_MB_IRQHandler(void);

extern Device_t DeviceType;
extern TJA1145FD_Main_Status_Reg_t mainStatusReg;
/*==================================================================================================
*                                       LOCAL FUNCTIONS
==================================================================================================*/

/*==================================================================================================
*                                       Interrupts callback FUNCTIONS
==================================================================================================*/
/*================================================================================================*/
/**
 * @brief          CAN0 normal TX/RX callback function
 * @details        It's invoked when CAN complete TX/RX in ISR.
 * @param[in]      instance, the index of instance of the CAN that tigger this interrupt.
 * 				   eventType, the event type refer to current interrupt.
 * 				   buffIdx, the MB index that trigger this event.
 * 				   flexcanState, tha global state of this can instance.
 * @return         none
 */
void CAN0_ISRCallback(uint8 instance, Flexcan_Ip_EventType eventType, uint32 buffIdx, const Flexcan_Ip_StateType * flexcanState)
{
	(void)flexcanState;
	switch(eventType)
	{
		case FLEXCAN_EVENT_RX_COMPLETE:
			if(buffIdx == FLEXCAN0_RX_MB_IDX)
			{
				/* Reset the RX MB state to BUSY to receive next new message */
				FlexCAN_Ip_Receive(instance, FLEXCAN0_RX_MB_IDX, &FLEXCAN0_RxDta, false);
			}
			break;
		default:
			break;
	}
}

/*================================================================================================*/
/**
 * @brief          CAN1 normal TX/RX callback function
 * @details        It's invoked when CAN complete TX/RX in ISR.
 * @param[in]      instance, the index of instance of the CAN that tigger this interrupt.
 * 				   eventType, the event type refer to current interrupt.
 * 				   buffIdx, the MB index that trigger this event.
 * 				   flexcanState, tha global state of this can instance.
 * @return         none
 */
void CAN1_ISRCallback(uint8 instance, Flexcan_Ip_EventType eventType, uint32 buffIdx, const Flexcan_Ip_StateType * flexcanState)
{
	(void)flexcanState;
	switch(eventType)
	{
		case FLEXCAN_EVENT_RX_COMPLETE:
			if(buffIdx == FLEXCAN1_RX_MB_IDX)
			{
				LOGI("CAN", "CAN1 received message. Timestamp=0x%04X, ID=0x%04X\r\n", (unsigned int)(FLEXCAN1_RxDta.time_stamp), (unsigned int)(FLEXCAN1_RxDta.msgId));
				/* Reset the RX MB state to BUSY to receive next new message */
				FlexCAN_Ip_Receive(instance, FLEXCAN1_RX_MB_IDX, &FLEXCAN1_RxDta, false);
			}
			break;
		default:
			break;
	}
}

/*================================================================================================*/
/**
 * @brief          CAN2 normal TX/RX callback function
 * @details        It's invoked when CAN complete TX/RX in ISR.
 * @param[in]      instance, the index of instance of the CAN that tigger this interrupt.
 * 				   eventType, the event type refer to current interrupt.
 * 				   buffIdx, the MB index that trigger this event.
 * 				   flexcanState, tha global state of this can instance.
 * @return         none
 */
void CAN2_ISRCallback(uint8 instance, Flexcan_Ip_EventType eventType, uint32 buffIdx, const Flexcan_Ip_StateType * flexcanState)
{
	(void)flexcanState;
	switch(eventType)
	{
		case FLEXCAN_EVENT_RX_COMPLETE:
			if(buffIdx == FLEXCAN2_RX_MB_IDX)
			{
				/* Reset the RX MB state to BUSY to receive next new message */
				FlexCAN_Ip_Receive(instance, FLEXCAN2_RX_MB_IDX, &FLEXCAN2_RxDta, false);
			}
			break;
		default:
			break;
	}
}

/*================================================================================================*/
/**
 * @brief          CAN3 normal TX/RX callback function
 * @details        It's invoked when CAN complete TX/RX in ISR.
 * @param[in]      instance, the index of instance of the CAN that tigger this interrupt.
 * 				   eventType, the event type refer to current interrupt.
 * 				   buffIdx, the MB index that trigger this event.
 * 				   flexcanState, tha global state of this can instance.
 * @return         none
 */
void CAN3_ISRCallback(uint8 instance, Flexcan_Ip_EventType eventType, uint32 buffIdx, const Flexcan_Ip_StateType * flexcanState)
{
	(void)flexcanState;
	switch(eventType)
	{
		case FLEXCAN_EVENT_RX_COMPLETE:
			if(buffIdx == FLEXCAN3_RX_MB_IDX)
			{
				LOGI("CAN", "CAN3 received message. Timestamp=0x%04X, ID=0x%04X\r\n", (unsigned int)(FLEXCAN3_RxDta.time_stamp), (unsigned int)(FLEXCAN3_RxDta.msgId));
				/* Reset the RX MB state to BUSY to receive next new message */
				FlexCAN_Ip_Receive(instance, FLEXCAN3_RX_MB_IDX, &FLEXCAN3_RxDta, false);
			}
			break;
		default:
			break;
	}
}

/*==================================================================================================
*                                       GLOBAL FUNCTIONS
==================================================================================================*/
/*================================================================================================*/
/**
 * @brief          Example_FlexCAN_Init
 * @details        This function will initialize all the configured CAN channels and RX MB.
 * @param[in]      none.
 * @return         none.
 */
void Example_FlexCAN_Init(void)
{
	/* FlexCAN0 Init */
	FlexCAN_Ip_Init(FLEXCAN0_INST, &FlexCAN_State0, &FlexCAN_Config0);
	FlexCAN_Ip_ConfigRxMb(FLEXCAN0_INST, FLEXCAN0_RX_MB_IDX, &FLEXCAN_RxTx_info, FLEXCAN0_RX_MSG_ID);
	FlexCAN_Ip_SetStartMode(INST_FLEXCAN_0);

	/* FlexCAN1 Init */
	FlexCAN_Ip_Init(FLEXCAN1_INST, &FlexCAN_State1, &FlexCAN_Config1);
	FlexCAN_Ip_ConfigRxMb(FLEXCAN1_INST, FLEXCAN1_RX_MB_IDX, &FLEXCAN_RxTx_info, FLEXCAN1_RX_MSG_ID);
	FlexCAN_Ip_SetStartMode(INST_FLEXCAN_1);

	/* FlexCAN2 Init */
	FlexCAN_Ip_Init(FLEXCAN2_INST, &FlexCAN_State2, &FlexCAN_Config2);
	FlexCAN_Ip_ConfigRxMb(FLEXCAN2_INST, FLEXCAN2_RX_MB_IDX, &FLEXCAN_RxTx_info, FLEXCAN2_RX_MSG_ID);
	FlexCAN_Ip_SetStartMode(INST_FLEXCAN_2);

	/* FlexCAN3 Init */
	FlexCAN_Ip_Init(FLEXCAN3_INST, &FlexCAN_State3, &FlexCAN_Config3);
	FlexCAN_Ip_ConfigRxMb(FLEXCAN3_INST, FLEXCAN3_RX_MB_IDX, &FLEXCAN_RxTx_info, FLEXCAN3_RX_MSG_ID);
	FlexCAN_Ip_SetStartMode(INST_FLEXCAN_3);

	FlexCAN_Ip_Receive(FLEXCAN0_INST, FLEXCAN0_RX_MB_IDX, &FLEXCAN0_RxDta, false);
	FlexCAN_Ip_Receive(FLEXCAN1_INST, FLEXCAN1_RX_MB_IDX, &FLEXCAN1_RxDta, false);
	FlexCAN_Ip_Receive(FLEXCAN2_INST, FLEXCAN2_RX_MB_IDX, &FLEXCAN2_RxDta, false);
	FlexCAN_Ip_Receive(FLEXCAN3_INST, FLEXCAN3_RX_MB_IDX, &FLEXCAN3_RxDta, false);
}

/*================================================================================================*/
/**
 * @brief          TJA1145_Init
 * @details        This function will initialize the CAN PHY TJA1145 which connected to CAN2 and CAN3.
 * @param[in]      none.
 * @return         uint8_t.
 */
uint8_t TJA1145_Init(void)
{
	StdReturn_t ret = TJA1145_E_OK;

	if(LPSPI_IP_UNINIT==Lpspi_Ip_GetStatus(TJA1145_LPSPI_INSTANCE))		//if LPSPI3 is not initialized, run the LPSPI initialization.
		Lpspi_Ip_Init(&Lpspi_Ip_PhyUnitConfig_SpiPhyUnit_3_Instance_3_BOARD_InitPeripherals);

    TJA1145_Select(0);	//selelct TJA1145_1 (LPSPI3, PCS1)
    ret = StartupOperation();
    if(NXP_TJA1145==DeviceType){
    	LOGI("CAN", "TJA11xx device 1 is TJA1145.\r\n");
    } else if(NXP_TJA1145FD==DeviceType){
    	LOGI("CAN", "TJA11xx device 1 is TJA1145FD.\r\n");
    } else {
    	LOGI("CAN", "TJA11xx device 1 is unknown type.\r\n");
    }
    if(TJA1145_E_OK==ret){
    	LOGI("CAN", "TJA11xx device 1 initialization OK.\r\n");
    } else {
    	LOGI("CAN", "TJA11xx device 1 initialization fail.\r\n");
    }
    if(TJA1145FD_NMS_NORMAL_MODE_ENTERED == mainStatusReg.TJA1145FD_NMS){
    	LOGI("CAN", "TJA11xx device 1 entered normal mode.\r\n");
    } else {
    	LOGI("CAN", "TJA11xx device 1 not in normal mode.\r\n");
    }

    TJA1145_Select(1);	//selelct TJA1145_2 (LPSPI3, PCS3)
    ret = StartupOperation();
    if(NXP_TJA1145==DeviceType){
    	LOGI("CAN", "TJA11xx device 2 is TJA1145.\r\n");
    } else if(NXP_TJA1145FD==DeviceType){
    	LOGI("CAN", "TJA11xx device 2 is TJA1145FD.\r\n");
    } else {
    	LOGI("CAN", "TJA11xx device 2 is unknown type.\r\n");
    }
    if(TJA1145_E_OK==ret){
    	LOGI("CAN", "TJA11xx device 2 initialization OK.\r\n");
    } else {
    	LOGI("CAN", "TJA11xx device 2 initialization fail.\r\n");
    }
    if(TJA1145FD_NMS_NORMAL_MODE_ENTERED == mainStatusReg.TJA1145FD_NMS){
		LOGI("CAN", "TJA11xx device 2 entered normal mode.\r\n");
	} else {
		LOGI("CAN", "TJA11xx device 2 not in normal mode.\r\n");
	}

	return 0;
}

/*================================================================================================*/
/**
 * @brief          TJA1044_Init
 * @details        This function will initialize the CAN PHY TJA1044 which connected to CAN0 and CAN1.
 * @param[in]      none.
 * @return         uint8_t.
 */
uint8_t TJA1044_Init(void)
{
	Siul2_Dio_Ip_WritePin(TJA1044_1_STB_PORT, TJA1044_1_STB_PIN, 0);
	Siul2_Dio_Ip_WritePin(TJA1044_2_STB_PORT, TJA1044_2_STB_PIN, 0);

	return 0;
}

/*================================================================================================*/
/**
 * @brief          CAN_Task_Init
 * @details        This function will initialize the CAN channels and PHY.
 * @param[in]      none.
 * @return         Std_ReturnType.
 */
Std_ReturnType CAN_Task_Init(void){
	Std_ReturnType retCode = E_OK;
	/* FlexCAN ISR installation and IRQ enable are configured in IntCtrl_Ip
	 * by calling the API "IntCtrl_Ip_Init" and "IntCtrl_Ip_ConfigIrqRouting".
	 * If these are not configured in IntCtrl_Ip component, user need call the
	 * API "IntCtrl_Ip_InstallHandler" and "IntCtrl_Ip_EnableIrq" */
	retCode = TJA1044_Init();
	retCode = TJA1145_Init();
	Example_FlexCAN_Init();
	return retCode;
}

/*================================================================================================*/
/**
 * @brief          CAN_Task_Runtime
 * @details        The main runtime task of this CAN example. Sending the CAN frames of CAN0 and CAN2.
 * @param[in]      none.
 * @return         none.
 */
void CAN_Task_Runtime(void)
{
	/* CAN0 send a message with ID==FLEXCAN1_RX_MSG_ID to CAN1 */
	(void)FlexCAN_Ip_Send(FLEXCAN0_INST, FLEXCAN0_TX_MB_IDX, &FLEXCAN_RxTx_info, FLEXCAN1_RX_MSG_ID, (uint8_t*)&FLEXCAN0_Tx_Data);
	/* CAN2 send a message with ID==FLEXCAN3_RX_MSG_ID to CAN3 */
	(void)FlexCAN_Ip_Send(FLEXCAN2_INST, FLEXCAN2_TX_MB_IDX, &FLEXCAN_RxTx_info, FLEXCAN3_RX_MSG_ID, (uint8_t*)&FLEXCAN2_Tx_Data);

}


#ifdef __cplusplus
}
#endif

/** @} */
