/*
 * CanDrv.c
 *
 *  Created on: Oct 15, 2020
 *      Author: yang_p1
 */

#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "Driver/CAN/CAN_Transciever_drv.h"
#include "CANMID.h"
#include "ccl_inc.h"
#include "S32K148.h"
#include "interrupt_manager.h"
#include "Abstraction/Include/OS_Interface.h"
#include "Abstraction/Driver/GPIO/Gpio_abs.h"
#include "Driver/GPIO/Gpio_drv.h"
#include "Driver/Interrupt/Interrupt.h"
#include "pins_driver.h"


#define HW_LOOP_TIMER_EXPIRED   0
#define HW_LOOP_TIMER_RUNNING   1



static uint32 T_HwloopTimer=0;
static uint8 CanTrcvSts=TRCV_INIT;

typedef enum {
    CAN_INT_RX_WARNING = CAN_CTRL1_RWRNMSK_MASK,     /*!< RX warning interrupt*/
    CAN_INT_TX_WARNING = CAN_CTRL1_TWRNMSK_MASK,     /*!< TX warning interrupt*/
    CAN_INT_ERR        = CAN_CTRL1_ERRMSK_MASK,      /*!< Error interrupt*/
    CAN_INT_BUSOFF     = CAN_CTRL1_BOFFMSK_MASK,     /*!< Bus off interrupt*/
} can_int_type_t;

void Can_trans_goto_sleep_mode();
void Can_trans_goto_standby_mode();
void Can_trans_goto_wakeup_mode();
void Can_trans_goto_off_mode();

void Can_trans_init();
void CanMid_CanDrvInit(void );
void CAN_Interrupt_Enable(void);
void CanMidDrv_Deinit(void);
void CAN_EnterFreezeMode(CAN_Type * base);
void CAN_Disable(CAN_Type * base);
void CAN_SetErrIntCmd(CAN_Type * base, can_int_type_t errType, bool enable);
void CCL_API_CALLBACK_TYPE ApplCclBusOffStart(void);
void CCL_API_CALLBACK_TYPE ApplCclBusOffEnd(void);
void ApplCbdWrpBusOffNotification( CBDWRP_CHANNEL_APPLTYPE_ONLY );
void CCL_API_CALLBACK_TYPE ApplCclInitTrcv(void);
void CCL_API_CALLBACK_TYPE ApplCclWakeUpTrcv(void);
void CCL_API_CALLBACK_TYPE ApplCclStandbyTrcv(void);
void CCL_API_CALLBACK_TYPE ApplCclSleepTrcv(void);
void CanMidDriver_ClearTrcvInt(void);
void CanMidDriver_ConfigTrcvInt(void);
void CanMidDriver_EnableTrcvInt(void);
void CanMidDriver_DisableTrcvInt(void);
uint8 CanDrvTrcvStsGet();
C_CALLBACK_1 void     C_CALLBACK_2 ApplCanTimerStart(CAN_CHANNEL_CANTYPE_FIRST vuint8 source);
C_CALLBACK_1 vuint8 C_CALLBACK_2 ApplCanTimerLoop (CAN_CHANNEL_CANTYPE_FIRST vuint8 source);
C_CALLBACK_1 void     C_CALLBACK_2 ApplCanTimerEnd  (CAN_CHANNEL_CANTYPE_FIRST vuint8 source);

void Can_trans_goto_sleep_mode()
{
	transceiver_sleep_mode();
}

void Can_trans_goto_standby_mode()
{
	transceiver_standby_mode();
}

void Can_trans_goto_wakeup_mode()
{
	transceiver_wakeup_mode();
}

void Can_trans_goto_off_mode()
{
	CanTransCaptureCfg cap_cfg=
	{
		.OTWE = TRANS_DISABLE,
		.SPIFE = TRANS_DISABLE,
		.CBSE = TRANS_DISABLE,
		.CFE = TRANS_DISABLE,
		.CWE = TRANS_DISABLE,
		.WPRE = TRANS_DISABLE,
		.WPFE = TRANS_DISABLE
	};

	transceiver_event_capture_cfg(cap_cfg);
	Can_trans_goto_sleep_mode();
}


void Can_trans_init()
{
	uint8_t mask_data[8] = {0,0,0,0,0,0,0,0};/*Data7 - Data0*/


	CanTransControlCfg control_cfg=
	{
		.CAN_Mode_Select = CAN_ACTIVE,
		.CAN_Partial_Cfg=1,
		.CAN_Select_WK=1,
		.CAN_Type=CAN_TYPE
	};

	CanTransPartialNetwork partial_cfg=
	{
		.DataRate = DATA_RATE_500,
		.Data_len = 8,
		.Data_mask = mask_data,
		.Data_mask_en = TRANS_ENABLE,
		.Id_format = MSG_ID_STANDARD,
		.MsgID = 0x500,
		.MsgID_mask =0x07F,
	};


	CanTransCaptureCfg cap_cfg=
	{
		.OTWE = TRANS_DISABLE,
		.SPIFE = TRANS_DISABLE,
		.CBSE = TRANS_DISABLE,
		.CFE = TRANS_DISABLE,
		.CWE = TRANS_ENABLE,
		.WPRE = TRANS_ENABLE,
		.WPFE = TRANS_DISABLE
	};

	transceiver_control_cfg(control_cfg);
	transceiver_partial_network_cfg(partial_cfg);
	transceiver_event_capture_cfg(cap_cfg);

}


void CanMid_CanDrvInit(void )
{
	unsigned char NmUserData[6]={0,0,0,0,0,0};
	CAN_Interrupt_Enable();
#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CclInitPowerOn Start]---",OS_GetCurrentTime());
#endif
	CclInitPowerOn();
#ifdef OPEN_LOG_NW
	  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CclInitPowerOn End]---",OS_GetCurrentTime());
#endif


	CanNm_SetUserData(0,NmUserData);


}

void CAN_Interrupt_Enable(void)
{
	/* Install FlexCAN5 interrupts */
	 INT_SYS_InstallHandler(CAN0_ORed_IRQn,   			&CanBusOffIsr_5, (isr_t*) 0);
	 INT_SYS_InstallHandler(CAN0_ORed_0_15_MB_IRQn,   &CanMailboxIsr_5, (isr_t*) 0);
	 INT_SYS_InstallHandler(CAN0_ORed_16_31_MB_IRQn,   &CanMailboxIsr_5, (isr_t*) 0);
	/* Enable FlexCAN5 interrupts */
	INT_SYS_EnableIRQ(CAN0_ORed_IRQn);
	INT_SYS_EnableIRQ(CAN0_ORed_0_15_MB_IRQn);
	INT_SYS_EnableIRQ(CAN0_ORed_16_31_MB_IRQn);


	//IHN
	INT_WakeUp_Set(PORTC,PIN_INDEX_11,PORT_INT_FALLING_EDGE);
	INT_SYS_InstallHandler(PORTC_IRQn, &PORTC_IRQHandler, NULL);
	INT_SYS_EnableIRQ(PORTC_IRQn);
}

void CanMidDrv_Deinit(void)
{

   ApplCclSleepTrcv();

   //if(CclGetChannelState()!=kCclStateSleep)
   {

	   CclReleaseCommunication(0);
	   OS_sleep(10);
   }
   /* Disable all MB interrupts */
    CAN1->IMASK1=0;
    //CAN1->IMASK2=0;
    //CAN1->IMASK3=0;
    CAN_SetErrIntCmd((CAN_Type *)CAN1_BASE, CAN_INT_ERR, false);
    CAN_SetErrIntCmd((CAN_Type *)CAN1_BASE, CAN_INT_RX_WARNING, false);
    CAN_SetErrIntCmd((CAN_Type *)CAN1_BASE, CAN_INT_TX_WARNING, false);
    CAN_SetErrIntCmd((CAN_Type *)CAN1_BASE, CAN_INT_BUSOFF, false);

	INT_SYS_DisableIRQ(CAN1_ORed_IRQn);
	INT_SYS_DisableIRQ(CAN1_Error_IRQn);
	INT_SYS_DisableIRQ(CAN1_ORed_0_15_MB_IRQn);
	INT_SYS_DisableIRQ(CAN1_ORed_16_31_MB_IRQn);

    /* Clear all MB interrupt flags */
	CAN1->IFLAG1=0xFFFFFFFF;
	//CAN1->IFLAG2=0xFFFFFFFF;
	//CAN1->IMASK3=0xFFFFFFFF;

    /* Clear error interrupt flags */
	CAN1->ESR1= 0x3B0007;

 /* Enter Freeze Mode Required before to enter Disabled Mode */
    CAN_EnterFreezeMode((CAN_Type *)CAN1_BASE);
    /* Disable FlexCAN.*/
    CAN_Disable((CAN_Type *)CAN1_BASE);




}


void CAN_EnterFreezeMode(CAN_Type * base)
{
	bool enabled = false;
	unsigned int HwLoopTout=0;

    base->MCR = (base->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(1U);
    base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U);
    if (((base->MCR & CAN_MCR_MDIS_MASK) >> CAN_MCR_MDIS_SHIFT) == 0U)
	{
		enabled = true;
	}
	else
	{
		base->MCR &= ~CAN_MCR_MDIS_MASK;
	}

    base->TIMER = 0U;
    uint32_t aux=0U;
    while ((((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) == 0U) && (aux < 730U))
    {
    	/* Wait until finish counting 730 bit times and exit*/
        aux = (uint32_t)base->TIMER;
    }
    if (((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) == 0U)
    {
    	/* Save registers before Soft Reset */
        uint32_t tempIMSK[2],tempMCR;
        tempIMSK[0] = base->IMASK1;
        //tempIMSK[1] = base->IMASK2;
        tempMCR = base->MCR;
        /* Soft Reset FlexCan */
        base->MCR |= CAN_MCR_SOFTRST(1U);
        HwLoopTout=0;
        while (((base->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT) != 0U) {
        	HwLoopTout++;
            if(HwLoopTout>10000)
            	break;
        }
        /* Restore registers after Soft Reset */
        base->IMASK1 = tempIMSK[0];
        //base->IMASK2 = tempIMSK[1];
        base->MCR = tempMCR;
    }

    /* Wait for entering the freeze mode */
    while (((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) == 0U)
	{
		HwLoopTout++;
		if(HwLoopTout>10000)
			break;
	}
    if (false == enabled)
    {
    	base->MCR |= CAN_MCR_MDIS_MASK;
    	/* Wait until disable mode acknowledged */
		HwLoopTout=0;
        while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 0U)
		{
			HwLoopTout++;
			if(HwLoopTout>10000)
				break;
		}
    }
}

void CAN_Disable(CAN_Type * base)
{
	uint32_t aux=0U;

    /* To access the memory mapped registers */
    /* Entre disable mode (hard reset). */
    if(((base->MCR & CAN_MCR_MDIS_MASK) >> CAN_MCR_MDIS_SHIFT) == 0U)
    {
        /* Clock disable (module) */
        base->MCR = (base->MCR & ~CAN_MCR_MDIS_MASK) | CAN_MCR_MDIS(1U);

        /* Wait until disable mode acknowledged */
        while ((((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 0U) && (aux < 2U) )
		{
        	aux = (uint32_t)base->TIMER;
		}
    }
}


void CAN_SetErrIntCmd(CAN_Type * base, can_int_type_t errType, bool enable)
{
    uint32_t temp = (uint32_t)errType;
    if (enable)
    {
        if((errType == CAN_INT_RX_WARNING) || (errType == CAN_INT_TX_WARNING))
        {
           base->MCR = (base->MCR & ~CAN_MCR_WRNEN_MASK) | CAN_MCR_WRNEN(1U);
        }
#if FEATURE_CAN_HAS_FD
        if (errType == CAN_INT_ERR)
        {
           base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_ERRMSK_FAST_MASK) | CAN_CTRL2_ERRMSK_FAST(1U);
        }
#endif
        (base->CTRL1) = ((base->CTRL1) | (temp));
    }
    else
    {
    	(base->CTRL1) = ((base->CTRL1) & ~(temp));
#if FEATURE_CAN_HAS_FD
                if (errType == CAN_INT_ERR)
                {
                   base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_ERRMSK_FAST_MASK) | CAN_CTRL2_ERRMSK_FAST(0U);
                }
#endif
        temp = base->CTRL1;
		if (((temp & (uint32_t)CAN_INT_RX_WARNING) == 0U) && ((temp & (uint32_t)CAN_INT_TX_WARNING) == 0U))
		{
		   /* If WRNEN disabled then both FLEXCAN_INT_RX_WARNING and FLEXCAN_INT_TX_WARNING will be disabled */
		   base->MCR = (base->MCR & ~CAN_MCR_WRNEN_MASK) | CAN_MCR_WRNEN(0U);
		}
    }
}

void CCL_API_CALLBACK_TYPE ApplCclBusOffStart(void)
{
	//CanFaultChk_BusOffStart();
}
void CCL_API_CALLBACK_TYPE ApplCclBusOffEnd(void)
{
}
void ApplCbdWrpBusOffNotification( CBDWRP_CHANNEL_APPLTYPE_ONLY )
{
	//CanMidDtc_BusOffOccur();

}

void CCL_API_CALLBACK_TYPE ApplCclInitTrcv(void)
{

   	//GPIO_Set(CAN5_STB);
   	//GPIO_Set(CAN5_EN);
	//GPIO_Set(PE_14);// add by zhaowei for temporarily test, it will be controlled by power in the future
#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplCclInitTrcv]---",OS_GetCurrentTime());
#endif
	CanTrcvSts=TRCV_INIT;

}
void CCL_API_CALLBACK_TYPE ApplCclWakeUpTrcv(void)
{
	Can_trans_goto_wakeup_mode();

#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplCclWakeUpTrcv]---",OS_GetCurrentTime());
#endif
	CanTrcvSts=TRCV_WAKEUP;

}
void CCL_API_CALLBACK_TYPE ApplCclStandbyTrcv(void)
{
	Can_trans_goto_standby_mode();
#ifdef OPEN_LOG_NW
	  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplCclStandbyTrcv]---",OS_GetCurrentTime());
#endif
	CanTrcvSts=TRCV_STANDBY;


}
void CCL_API_CALLBACK_TYPE ApplCclSleepTrcv(void)
{

	Can_trans_goto_sleep_mode();
#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplCclSleepTrcv]---",OS_GetCurrentTime());
#endif
	CanTrcvSts=TRCV_SLEEP;

}




void CanMidDriver_ClearTrcvInt(void)
{
#ifdef OPEN_LOG_NW
	  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CanMidDriver_ClearTrcvInt]---",OS_GetCurrentTime());
#endif
	//wvdWkpu_ClearIntFlag();

}

void CanMidDriver_ConfigTrcvInt(void)
{
#ifdef OPEN_LOG_NW
		  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CanMidDriver_ConfigTrcvInt]---",OS_GetCurrentTime());
#endif
	//WKPU_DRV_SetInterruptNormalMode(INST_WKPU1, WKPU_HW_CHANNEL14);     /* CAN1_INH         */

}

void CanMidDriver_EnableTrcvInt(void)
{
#ifdef OPEN_LOG_NW
			  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CanMidDriver_EnableTrcvInt]---",OS_GetCurrentTime());
#endif

}

void CanMidDriver_DisableTrcvInt(void)
{
#ifdef OPEN_LOG_NW
				  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CanMidDriver_DisableTrcvInt]---",OS_GetCurrentTime());
#endif

}

uint8 CanDrvTrcvStsGet()
{
	return CanTrcvSts;

}


C_CALLBACK_1 void     C_CALLBACK_2 ApplCanTimerStart(CAN_CHANNEL_CANTYPE_FIRST vuint8 source)
{
	CAN_Type * base;
	base = (CAN_Type *)CAN0_BASE;
	base->TIMER = 0U;
	T_HwloopTimer=0;
	switch(source)
	{
		case kCanLoopMsgReception:
			T_HwloopTimer = 20;
			break;
		case kCanLoopResetInit:
			T_HwloopTimer = 1000;
			break;
		case kCanLoopStart: case kCanLoopWakeup:
			T_HwloopTimer = 9;
			break;
		case kCanLoopStop: case kCanLoopSleep:case kCanLoopEnterFreezeModeInit:case kCanLoopLeaveDisableModeInit:case kCanLoopEnterDisableModeInit:
			T_HwloopTimer = 0;
			break;
		default:
			break;

	}

}

C_CALLBACK_1 vuint8 C_CALLBACK_2 ApplCanTimerLoop (CAN_CHANNEL_CANTYPE_FIRST vuint8 source)
{
	CAN_Type * base;
	vuint8 ret=HW_LOOP_TIMER_EXPIRED;
	base = (CAN_Type *)CAN0_BASE;

	switch(source)
	{
		case kCanLoopEnterDisableModeInit:
			T_HwloopTimer = base->TIMER;
			if(T_HwloopTimer<=2)
			{
				ret = HW_LOOP_TIMER_RUNNING;
			}else
			{
				ret = HW_LOOP_TIMER_EXPIRED;
			}
			break;
		case kCanLoopMsgReception:case kCanLoopStart: case kCanLoopWakeup:case kCanLoopResetInit:
			T_HwloopTimer--;
			if(T_HwloopTimer>0)
			{
				ret = HW_LOOP_TIMER_RUNNING;
			}else
			{
				ret = HW_LOOP_TIMER_EXPIRED;
			}
			break;
		case kCanLoopStop: case kCanLoopSleep:case kCanLoopEnterFreezeModeInit:case kCanLoopLeaveDisableModeInit:
			T_HwloopTimer = base->TIMER;
			if(T_HwloopTimer<=750)
			{
				ret = HW_LOOP_TIMER_RUNNING;
			}else
			{
				ret = HW_LOOP_TIMER_EXPIRED;
			}
			break;
		default:
			break;

	}

	return ret;

}

C_CALLBACK_1 void     C_CALLBACK_2 ApplCanTimerEnd  (CAN_CHANNEL_CANTYPE_FIRST vuint8 source)
{

}
