/**
*   @file    FS26_Task.c
*   @version 1.0.0
*
*   @brief   FS26 task init and runtime
*   @details The FS26 task includes the following:
*            1) Initialize FS26
*            2) Poll FS26 status
*
*   This example uses S32K3 RTD 2.0.0 and FS26 SBC Autosar 4.4 version 1.0.0
*   Note:
*   The FS26 configuration in "CDD_Sbc_fs26_BOARD_InitPeripherals_PBcfg.c" sets the WD window as infinite.
*   This register value is written into FS26 during FS26 init state.
*   So that the WD refresh can be performed any time to decrement the fault counter to zero.
*   After basic FS26 initialization is done, the WD window can be changed to desired value.
*
*   This file contains sample code only. It is not part of the production code deliverables.
*
*   @addtogroup FS26_Task
*   @{
*/

#ifdef __cplusplus
extern "C" {
#endif

/*==================================================================================================
*                                        INCLUDE FILES
* 1) Basic RTD modules includes
* 2) MCU registers definitions includes
* 3) needed interfaces from external units
==================================================================================================*/
#include "Mcal.h"
#include "Lpspi_Ip.h"
#include "CDD_Sbc_fs26.h"
#include "CDD_Sbc_fs26_Cfg.h"
#include "SchM_Sbc_fs26.h"
#include "Pit_Ip.h"
#include "Adc_Sar_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "FS26_Task.h"

#if ENABLE_FCCU_MON_TEST
#ifdef S32K344
#include "S32K344_FCCU.h"
#endif
#ifdef S32K324
#include "S32K324_FCCU.h"
#endif
void Fccu_Init_EOUT_Test(void);
#endif

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

/*==================================================================================================
*                                       LOCAL MACROS
==================================================================================================*/
/* MACRO to enable measurement of FS26 initialization time using the STM0 timer. */
#define ENABLE_TIME_MEASUREMENT_TEST	1
/* MACRO to enable FS26 WD configuration. For software debug purpose, it can be set as 0. */
#define ENABLE_FS26_WD					0
/* MACRO to enable the operation of exiting debug mode. If kept in debug mode, the FS0b/FS1b cannot be released. */
#define ENABLE_LEAVE_DEBUG_MODE			0
/* MACRO to enable calling printf to output the FS26 status registers. */
#define ENABLE_SBC_MSG_PRINT			1
/* MACRO to enable FCCU1/2 monitor test */
//#define ENABLE_FCCU_MON_TEST			1

#define ENABLE_SBC_FLAG_READ_DURING_INIT 1

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

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

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


/*==================================================================================================
*                                      GLOBAL VARIABLES
==================================================================================================*/

#if ENABLE_SBC_MSG_PRINT
#include "retarget.h"
#include "stdio.h"
void Sbc_Print_Flags(void);
#endif

/* this structure includes all main registers in FS26 */
Sbc_Main_Registers_Struct Sbc_Main_Reg;
/* this structure includes all FS registers in FS26 */
Sbc_FS_Registers_Struct Sbc_FS_Reg;
/* buffer to store a received frame from FS26 */
Sbc_fs26_RxFrameType Sbc_RxFrame_Buffer;
/* variable to indicate an interrupt reported on FS26 INT_B signal */
uint32_t Sbc_Int_Flag = 0;
/* variable to indicate an PIT timeout occurred and a WD refresh is required. */
uint32_t Sbc_Wd_Flag = 0;
/* SBC general status flags */
uint16_t Sbc_General_Status;
/* SBC Main Status register */
uint16_t Sbc_M_Status;
/* Variable to enable reading all SBC registers */
uint32_t Sbc_Read_All_Registers = 1;
/* Index to track currently selected AMUX channel */
uint32_t Sbc_Amux_Chan = 1;
/* bool var to enable AMUX channel switching */
uint32_t Sbc_Amux_Switching_Enable = 1;
/* AMUX sample results */
uint16_t Sbc_Amux_Rslt[24];

uint32_t Sbc_Error_Step = 0;

volatile uint32_t Sbc_WdRefreshCnt = 0;

/* it's from the SBC driver generated code. */
extern Sbc_fs26_ConfigType sbcConfig_BOARD_InitPeripherals;

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

/*==================================================================================================
*                                       External FUNCTIONS
==================================================================================================*/

/*==================================================================================================
*                                       LOCAL FUNCTIONS
==================================================================================================*/

/*==================================================================================================
*                                       Interrupts callback FUNCTIONS
==================================================================================================*/
/*================================================================================================*/
/**
 * @brief          FS26 IRQ callback function
 * @details        It's invoked when FS26 pulls INTB low - SIUL2_IRQ25 falling edge.
 * @param[in]      none.
 * @return         none
 */
void Icu_Fs26_Int_Callback(void){
	Sbc_Int_Flag = 1;
	return;
}

/*==================================================================================================
*                                       GLOBAL FUNCTIONS
==================================================================================================*/

/**************************************************************************
 * Customized initialization process for SBC FS26
 **************************************************************************/
Std_ReturnType FS26_Task_Init(void){
	Std_ReturnType Sbc_Ret = E_OK;
	uint16 u16Tmp;
	(void)u16Tmp;

	/* initialize the pointer to the SPI driver external device configuration structure */
	sbcConfig_BOARD_InitPeripherals.pcSpi->ext = (void *)(&Lpspi_Ip_DeviceAttributes_SPI1_PCS0_FS26_Instance_1_BOARD_InitPeripherals);

	/* *****************************************************************************
	 * for pre-compile option, use NULL_PTR as input parameter.
	 * Note: the Watchdog period is disabled in this example in the mex file configuration,
	 * that means the WD refreshing can be performed at any time (Infinite open window) and
	 * the WD RF Cnt will increment and Fault Error Counter will decrement accordingly.
	 *******************************************************************************/
	Sbc_Ret = Sbc_fs26_Init(&sbcConfig_BOARD_InitPeripherals);
	Sbc_Ret |= Sbc_fs26_InitDevice();
	if(Sbc_Ret != E_OK){
		return Sbc_Ret;
	}
#if ENABLE_SBC_MSG_PRINT
	printf("FS26 basic init done.\r\n");
#endif

	/* Configure MCU corresponding pin as IRQ to monitor FS26_INTB signal */


	/********************************************************************************
	 * After fs26_init, the first correct WD refresh is performed.
	 * FS26 Fail-Safe logic leaves "Init FS" state and enters "Safety Outputs asserted" state.
	 * FS_I_xxxx registers are not writable after this point. (Unless re-enter "Init FS" state.)
	 ********************************************************************************/

	/********************************************************************************
	 * Read all FS26 registers for test purpose.
	 * It's not necessary for production software.
	 ********************************************************************************/
	if(Sbc_Read_All_Registers){
		Sbc_Read_All_Registers = 0;
		Sbc_Ret = Sbc_Read_Main_Registers();
		Sbc_Ret += Sbc_Read_FS_Registers();
		if(Sbc_Ret != E_OK)
			return Sbc_Ret;
	}
#if ENABLE_SBC_MSG_PRINT
	printf("FS26 all registers read OK.\r\n");
#endif

#if ENABLE_SBC_FLAG_READ_DURING_INIT
	/********************************************************************************
	 * Read and clear all interrupt flags registers to find out the cause for the previous reset or interrupt event.
	 ********************************************************************************/
	Sbc_Ret = Sbc_ReadAndClear_Interrupt_Flags();
	Sbc_Parse_Interrupt_Flags();
#endif

	/**************************************************************************************
	 * The Fault Error Counter (FS_I_FSSM FLT_ERR_CNT) in FS26 must be 0 before FS26 can enter normal mode.
	 * Correct WD refresh can decrement this "Fault Error Counter".
	 * Check the FLT_ERR_CNT(fault error counter) and refresh WD to decrement the counter until it's zero.
	 * The FLT_ERR_CNT is 1 by default after POR.
	 * WD_RFR_LIMIT (6/4/2/1) consecutive correct WD refresh (FS_I_WD_CFG WD_RFR_LIMIT) will decrement the FLT_ERR_CNT by 1.
	 * Because the WD window is set to infinite in this example configuration, the WD refresh can be performed at any time.
	 *************************************************************************************/
	do{
		/* refresh watchdog to increment WD RFR CNT and decrement FLT_ERR_CNT */
		Sbc_Ret += Sbc_fs26_WdRefresh();
		/* poll FLT_ERR_CNT value */
		Sbc_Ret += Sbc_fs26_ReadRegister(TRUE, SBC_FS26_FS_I_FSSM_ADDR, &Sbc_RxFrame_Buffer);
		if(Sbc_Ret != E_OK)
			break;

		/* get the received I_FSSM register value from the Rx Buffer */
		Sbc_FS_Reg.Sbc_I_Fssm = Sbc_RxFrame_Buffer.u16ReadData;
		Sbc_WdRefreshCnt++;
	}while(0 != (Sbc_FS_Reg.Sbc_I_Fssm & SBC_FS26_FS_FLT_ERR_CNT_MASK));
	if(Sbc_Ret != E_OK)
		return (Sbc_Ret);
#if ENABLE_SBC_MSG_PRINT
	printf("Refresh FS26 WDG OK.\r\n");
#endif


#if (ENABLE_LEAVE_DEBUG_MODE)
	/**************************************************************************************
	 *  Write FS_STATES register to let FS26 leave debug mode before releasing the FS0b and FS1b safety outputs.
	 *  FS0b/FS1b cannot be released when FS26 is in debug mode.
	 *  According to FS26 data sheet chapter 23 OTP and Debug mode:
	 *  "In Debug mode, the watchdog is disabled, the RSTB 8s counter is disabled, FS0B is stuck low and cannot be released."
	 **************************************************************************************/
	u16Tmp = SBC_FS26_FS_EXIT_DBG_MODE_MASK;
	Sbc_Ret = Sbc_fs26_WriteRegister(TRUE, SBC_FS26_FS_STATES_ADDR, u16Tmp, &Sbc_RxFrame_Buffer);
	if(Sbc_Ret != E_OK)
		return (Sbc_Ret);

	/**************************************************************************************
	 * Call API to release FS0b and FS1b because FS26 just exits Debug mode in previous step.
	 * The FSxb release operation need be done to let Fail-Safe logic enter normal mode.
	 **************************************************************************************/
	Sbc_Ret = Sbc_fs26_FsxbRelease(SBC_FS26_FS_RELEASE_OUTPUT_FS0B_FS1B);
	if(Sbc_Ret != E_OK)
		return (Sbc_Ret);
	/* from this point on, FS26 enters normal state. */
#endif


#if ENABLE_FS26_WD
	/**************************************************************************************
	 * Modify the Watchdog duration and window settings.
	 * This requires writing to both FS_WDW_DURATION and FS_NOT_WDW_DURATION registers.
	 **************************************************************************************/
	u16Tmp = FS26_WD_CONFIGURATION;
	Sbc_Ret += Sbc_fs26_WriteRegister(TRUE, SBC_FS26_FS_WDW_DURATION_ADDR, u16Tmp, &Sbc_RxFrame_Buffer);
	u16Tmp = (~u16Tmp);
	Sbc_Ret += Sbc_fs26_WriteRegister(TRUE, SBC_FS26_FS_WDW_DURATION_ADDR+1, u16Tmp, &Sbc_RxFrame_Buffer);
	if(Sbc_Ret != E_OK)
		return (Sbc_Ret);

	/**************************************************************************************
	 * The above WDW_DURATION update is effective after a correct watchdog refresh.
	 **************************************************************************************/
	Sbc_Ret = Sbc_fs26_WdRefresh();
	if(Sbc_Ret != E_OK)
		while(1);
#endif

#if ENABLE_FS26_WD
	/**************************************************************************************
	 * Since the new WD period/window becomes effect at this moment,
	 * the timer for triggering WD refresh should be stopped and restarted here to make sure the correct timing.
	 **************************************************************************************/
	Pit_Ip_StopChannel(0, 0);		//stop PIT0 ch0
	Pit_Ip_StartChannel(0, 0, 4000000);	//start PIT0 ch0 with 100mS interval
#endif

	/* Initialize AMUX to chan 1, with divider 0 */
	Sbc_fs26_SetAmux(1, 0);

	return (Sbc_Ret);
}

/**************************************************************************
 * This function should be called periodically in a task.
 * It includes all the SPI communication process (FS26 registers read/write) between MCU and FS26.
 * 1) WD refresh;
 * 2) Interrupt flags read and clear
 * 3) AMUX channel update and sampling
 * 4) All SBC registers reading (optional)
 **************************************************************************/
Std_ReturnType FS26_Task_Runtime(void){
	Std_ReturnType sbcSpiStatus = E_OK;

	/* Refresh the SBC watchdog if the timeout flag of the corresponding timer is set. */
	if(Sbc_Wd_Flag){
		sbcSpiStatus += Sbc_fs26_WdRefresh();
		Sbc_Wd_Flag = 0;
	}

	/* If INTB interrupt is detected by MCU ICU channel, read the interrupt flags in SBC */
	if(Sbc_Int_Flag){
		Sbc_Int_Flag = 0;
		printf("FS26 INT event detected.\r\n");

		/* read and clear the flags that may cause INTB interrupt, the flag registers values are updated in Sbc_Main_Reg and Sbc_FS_Reg */
		sbcSpiStatus += Sbc_ReadAndClear_Interrupt_Flags();
		/* Sbc_Parse_Interrupt_Flags(); */

		/* Print all the interrupt flags for debug purpose */
#if ENABLE_SBC_MSG_PRINT
		//Sbc_Print_Flags();
#endif
	}

	/* If set the variable "Sbc_Read_All_Registers", read all the registers in SBC */
	if(Sbc_Read_All_Registers){
		Sbc_Read_All_Registers = 0;
		sbcSpiStatus += Sbc_Read_Main_Registers();
		sbcSpiStatus += Sbc_Read_FS_Registers();
	}

	/********************************************************************************************
	 * If the var Sbc_Amux_Switching_Enable is set, change the AMUX register and sample each AMUX channel.
	 * The AMUX channel settling time is 10uS max.
	 * So this example here samples the AMUX channel that is settled in the previous AMUX register writing,
	 * and then switch the AMUX to the next channel to prepare for the next ADC sampling execution.
	 * *****************************************************************************************/
	if(Sbc_Amux_Switching_Enable){

		/* Adc_Sar_Ip_EnableChannel(2, ADC_SAR_IP_CONV_CHAIN_INJECTED, 7); */
		Adc_Sar_Ip_StartConversion(2, ADC_SAR_IP_CONV_CHAIN_INJECTED);
		while((Adc_Sar_Ip_GetStatusFlags(2) & ADC_SAR_IP_NOTIF_FLAG_INJECTED_ENDCHAIN) == 0);
		Sbc_Amux_Rslt[Sbc_Amux_Chan] = Adc_Sar_Ip_GetConvData(2, 7);
		Sbc_Amux_Rslt[Sbc_Amux_Chan] = Sbc_Amux_Rslt[Sbc_Amux_Chan] * 5000 / 16384;	//change result from count to mVolt
		Adc_Sar_Ip_ClearStatusFlags(2, ADC_SAR_IP_NOTIF_FLAG_INJECTED_ENDCHAIN);

		Sbc_Amux_Chan++;
		if(Sbc_Amux_Chan>22)
			Sbc_Amux_Chan = 1;
		Sbc_fs26_SetAmux(Sbc_Amux_Chan, 0);

	}

	return (sbcSpiStatus);
}

/************************************************************************************************
 *  Read the SBC general status bits FS_G, COM_G, WIO_G, VSUP_G, REG_G, TSD_G.
 *  If any of the above bits are set, read the corresponding flag registers to find out the exact cause for this interrupt.
 *  The received flag registers values are updated into the structure Sbc_FS_Reg and Sbc_Main_Reg,
 *  The stored values are registers values before being cleared.
 *  And clear the interrupt flags after reading - writing 1 to corresponding SBC register bit.
 ************************************************************************************************/
Std_ReturnType Sbc_ReadAndClear_Interrupt_Flags(void){
	Std_ReturnType sbcSpiStatus = E_OK;
	uint16_t sbcFsFlags;

	/* read main status register */
	sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_STATUS_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_Main_Reg.Sbc_Status = Sbc_RxFrame_Buffer.u16ReadData;
	Sbc_General_Status = Sbc_RxFrame_Buffer.u8DeviceStatus;

	/* read FS_GRL_FLAGS register to check safety related flags */
	if(Sbc_General_Status & GS_FS_G_MASK){
		sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_GRL_FLAGS_ADDR, &Sbc_RxFrame_Buffer);
		Sbc_FS_Reg.Sbc_Grl_Flags = Sbc_RxFrame_Buffer.u16ReadData;
		sbcFsFlags = Sbc_RxFrame_Buffer.u16ReadData;
		/* if caused by REG OVUV flags, read the corresponding register and write 1 to clear this register */
		if(sbcFsFlags & SBC_FS26_FS_FS_REG_OVUV_G_MASK){
			sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_OVUV_REG_STATUS_ADDR, &Sbc_RxFrame_Buffer);
			Sbc_FS_Reg.Sbc_Ovuv_Reg_Status = Sbc_RxFrame_Buffer.u16ReadData;
			sbcSpiStatus += Sbc_fs26_WriteRegister(true, SBC_FS26_FS_OVUV_REG_STATUS_ADDR, Sbc_RxFrame_Buffer.u16ReadData, &Sbc_RxFrame_Buffer);
		}
		/* if caused by FCCU1/2/12 or ERRMON event, read the corresponding register and write 1 to clear this register */
		if(sbcFsFlags & SBC_FS26_FS_FS_IO_G_MASK){
			sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_DIAG_SAFETY2_ADDR, &Sbc_RxFrame_Buffer);
			Sbc_FS_Reg.Sbc_Diag_Safety2 = Sbc_RxFrame_Buffer.u16ReadData;
			sbcSpiStatus += Sbc_fs26_WriteRegister(true, SBC_FS26_FS_DIAG_SAFETY2_ADDR, Sbc_RxFrame_Buffer.u16ReadData, &Sbc_RxFrame_Buffer);
		}
		/* if caused by FS_COM, WD, BIST flags, read the corresponding register and write 1 to clear this register */
		if(sbcFsFlags & (SBC_FS26_FS_FS_COM_G_MASK|SBC_FS26_FS_FS_WD_G_MASK|SBC_FS26_FS_FS_BIST_G_MASK)){
			sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_DIAG_SAFETY1_ADDR, &Sbc_RxFrame_Buffer);
			Sbc_FS_Reg.Sbc_Diag_Safety1 = Sbc_RxFrame_Buffer.u16ReadData;
			sbcSpiStatus += Sbc_fs26_WriteRegister(true, SBC_FS26_FS_DIAG_SAFETY1_ADDR, Sbc_RxFrame_Buffer.u16ReadData, &Sbc_RxFrame_Buffer);
		}
		//printf("Ovuv_flag=0x%04X, Safety1=0x%04X, Safety2=0x%04X.\r\n", Sbc_FS_Reg.Sbc_Ovuv_Reg_Status, Sbc_FS_Reg.Sbc_Diag_Safety1, Sbc_FS_Reg.Sbc_Diag_Safety2);
		printf("FS_GRL_FLAGS=0x%04X.\r\n", Sbc_FS_Reg.Sbc_Grl_Flags);
	}

	/* read M_COM_FLG to check spi error flags, read the corresponding register and write 1 to clear this register */
	if(Sbc_General_Status & GS_COM_G_MASK){
		sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_COM_FLG_ADDR, &Sbc_RxFrame_Buffer);
		Sbc_Main_Reg.Sbc_Com_Flg = Sbc_RxFrame_Buffer.u16ReadData;
		sbcSpiStatus += Sbc_fs26_WriteRegister(false, SBC_FS26_M_COM_FLG_ADDR, Sbc_RxFrame_Buffer.u16ReadData, &Sbc_RxFrame_Buffer);
		printf("Com_flag=0x%04X.\r\n", Sbc_Main_Reg.Sbc_Com_Flg);
	}

	/* read M_WIO_FLG to check GPIO flags, read the corresponding register and write 1 to clear this register */
	if(Sbc_General_Status & GS_WIO_G_MASK){
		sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_WIO_FLG_ADDR, &Sbc_RxFrame_Buffer);
		Sbc_Main_Reg.Sbc_Wio_Flg = Sbc_RxFrame_Buffer.u16ReadData;
		/* fs26RxData contains the flags indicating WAKE1/2 or GPIO1/2  */
		sbcSpiStatus += Sbc_fs26_WriteRegister(false, SBC_FS26_M_WIO_FLG_ADDR, 0x8000, &Sbc_RxFrame_Buffer);//clear WIO flags, must write 1 to WU_CLR bit
		printf("Wio_flag=0x%04X.\r\n", Sbc_Main_Reg.Sbc_Wio_Flg);
	}

	/* check power supply flags, read the corresponding register and write 1 to clear this register */
	if(Sbc_General_Status & GS_VSUP_G_MASK){
		sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_VSUP_FLG_ADDR, &Sbc_RxFrame_Buffer);
		Sbc_Main_Reg.Sbc_Vsup_Flg = Sbc_RxFrame_Buffer.u16ReadData;
		sbcSpiStatus += Sbc_fs26_WriteRegister(false, SBC_FS26_M_VSUP_FLG_ADDR, Sbc_RxFrame_Buffer.u16ReadData, &Sbc_RxFrame_Buffer);//clear VSUP flags
		printf("Sup_flag=0x%04X.\r\n", Sbc_Main_Reg.Sbc_Vsup_Flg);
	}

	/* check regulators flags, read the corresponding register and write 1 to clear this register */
	if(Sbc_General_Status & GS_REG_G_MASK){
		sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_REG_FLG_ADDR, &Sbc_RxFrame_Buffer);
		Sbc_Main_Reg.Sbc_Reg_Flg = Sbc_RxFrame_Buffer.u16ReadData;
		sbcSpiStatus += Sbc_fs26_WriteRegister(false, SBC_FS26_M_REG_FLG_ADDR, 0x00FF, &Sbc_RxFrame_Buffer);		//write 1 to clear the flags except VBSTOV_I flag
		printf("Reg_flag=0x%04X.\r\n", Sbc_Main_Reg.Sbc_Reg_Flg);
	}

	/* check TSD thermal shut down flag: TWARN_I, IO1TSD_I, VPRETSD_I, TRK2TSD_I, TRK1TSD_I, CORETSD_I, LDO2TSD_I, LDO1TSD_I */
	if(Sbc_General_Status & GS_TSD_G_MASK){
		sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_TSD_FLG_ADDR, &Sbc_RxFrame_Buffer);
		Sbc_Main_Reg.Sbc_Tsd_Flg = Sbc_RxFrame_Buffer.u16ReadData;
		sbcSpiStatus += Sbc_fs26_WriteRegister(false, SBC_FS26_M_TSD_FLG_ADDR, Sbc_RxFrame_Buffer.u16ReadData, &Sbc_RxFrame_Buffer);		//write 1 to clear the flags
		printf("Tsd_flag=0x%04X.\r\n", Sbc_Main_Reg.Sbc_Tsd_Flg);
	}

	return (sbcSpiStatus);
}

/************************************************************************************************
 *  Check each flag register value to decide whether there is additional handling needed.
 ************************************************************************************************/
void Sbc_Parse_Interrupt_Flags(void){
	/* safety flags reading, these flag registers values are received in above reading procedure */
	if((Sbc_FS_Reg.Sbc_Diag_Safety2 & (SBC_FS26_FS_FCCU12_MASK|SBC_FS26_FS_FCCU1_MASK|SBC_FS26_FS_FCCU2_MASK)) != 0){
		//if previous event include an FCCU12 error.
		printf("FCCU12 flag set.\r\n");
	}
	if((Sbc_FS_Reg.Sbc_Diag_Safety1 & (SBC_FS26_FS_BAD_WD_TIMING_MASK|SBC_FS26_FS_BAD_WD_DATA_MASK)) != 0){
		//if previous event include a Watchdog error.
		printf("WD error flag set.\r\n");
	}
	if((Sbc_FS_Reg.Sbc_Diag_Safety1 & (SBC_FS26_FS_FS_OSC_DRIFT_DRIFT)) != 0){
		//if previous event include a FS Oscillator error.
		printf("FS OSC error flag.\r\n");
	}
	if((Sbc_FS_Reg.Sbc_Diag_Safety1 & (SBC_FS26_FS_SPI_FS_CRC_ERROR|SBC_FS26_FS_SPI_FS_REQ_ERROR|SBC_FS26_FS_SPI_FS_CLK_ERROR)) != 0){
		//if previous event include a SPI comm error.
		printf("FS SPI CRC or REQ or CLK error.\r\n");
	}

	/* The related interrupt flag registers are updated in above codes, so just check each register value */
	/* If there is regulator OV/UV fault */
	if(Sbc_FS_Reg.Sbc_Ovuv_Reg_Status){
		//there is flag set in register FS_OVUV_REG_STATUS
		printf("Regulator OVUV event.\r\n");
	}

	/* If there is Error monitor fault */
	if(Sbc_FS_Reg.Sbc_Diag_Safety2 & SBC_FS26_FS_ERRMON_MASK){
		//there is flag set in register FS_DIAG_SAFETY2
		printf("FS Error monitor error.\r\n");
	}

	/* If there is SPI_Main communication fault */
	if(Sbc_Main_Reg.Sbc_Com_Flg){
		//there is flag set in register M_COM_FLG
		printf("Main SPI CRC or REQ or CLK error.\r\n");
	}

	/* If there is WAKE1/2 or GPIO1/2 event detected */
	if(Sbc_Main_Reg.Sbc_Wio_Flg & 0x001F){
		//there is flag set in register M_WIO_FLG
		printf("WIO flag is 0x%04X.\r\n", Sbc_Main_Reg.Sbc_Wio_Flg);
#if ENABLE_FCCU_MON_TEST
		/* If the WAKE2 event is detected, inject an FCCU monitor fault */
		/* Change "EOUT0==0, EOUT1==1" to be "EOUT0==1, EOUT1==0" to trigger an FCCU Monitor Error on SBC */
		if(Sbc_Main_Reg.Sbc_Wio_Flg & SBC_FS26_M_WK2_I_MASK)
			IP_FCCU->EINOUT = 0x01;
#endif
	}

	/* If there is supply voltage OV/UV fault */
	if(Sbc_Main_Reg.Sbc_Vsup_Flg){
		//there is flag set in register M_VSUP_FLG
		printf("Supply flag set.\r\n");
	}

	/* If there is regulator OV or Over-current fault */
	if(Sbc_Main_Reg.Sbc_Reg_Flg){
		//there is flag set in register M_REG_FLG
		printf("Regulator flag set.\r\n");
	}
	if(Sbc_Main_Reg.Sbc_Tsd_Flg){
		//there is flag set in register M_TSD_FLG
		printf("Thermal shutdown flag set.\r\n");
	}
}

/**************************************************************************
 * Read all Main registers and save the values into the structure Sbc_Main_Reg
 **************************************************************************/
Std_ReturnType Sbc_Read_Main_Registers(void){
	Std_ReturnType eRet = E_OK;
	Sbc_fs26_RxFrameType SbcRxBuf;
	uint32 regAddr;
	uint16 *u16ptr;

	u16ptr = (uint16 *)(&Sbc_Main_Reg.Sbc_DeviceId);
	for(regAddr = SBC_FS26_M_DEVICEID_ADDR; regAddr<SBC_FS26_M_MEMORY1_ADDR; regAddr++){
		eRet += Sbc_fs26_ReadRegister(FALSE, (uint8)regAddr, &SbcRxBuf);
		*u16ptr = SbcRxBuf.u16ReadData;
		u16ptr++;
	}
	Sbc_General_Status = SbcRxBuf.u8DeviceStatus;

	return eRet;
}

/***************************************************************************
 * Read all FS registers and save the values into the structure Sbc_FS_Reg,
 ****************************************************************************/
Std_ReturnType Sbc_Read_FS_Registers(void){
	Std_ReturnType eRet = E_OK;
	Sbc_fs26_RxFrameType SbcRxBuf;
	uint32 regAddr;
	uint16 *u16ptr;

	u16ptr = (uint16 *)(&Sbc_FS_Reg.Sbc_Grl_Flags);
	for(regAddr = SBC_FS26_FS_GRL_FLAGS_ADDR; regAddr<SBC_FS26_FS_LDT_LPSEL_ADDR; regAddr++){
		eRet += Sbc_fs26_ReadRegister(TRUE, (uint8)regAddr, &SbcRxBuf);
		*u16ptr = SbcRxBuf.u16ReadData;
		u16ptr++;
	}
	Sbc_General_Status = SbcRxBuf.u8DeviceStatus;

	return eRet;
}

/*******************************************************************************
 * Clear all flags for proper initialization.
 *****************************************************************************/
Std_ReturnType Sbc_Clear_Flags(void){
	Std_ReturnType eRet = E_OK;
	Sbc_fs26_RxFrameType SbcRxBuf;

	eRet += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_TSD_FLG_ADDR, 0xFFFF, &SbcRxBuf);

	eRet += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_REG_FLG_ADDR, 0x00FF, &SbcRxBuf);

	eRet += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_VSUP_FLG_ADDR, 0xFFFF, &SbcRxBuf);

	eRet += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_WIO_FLG_ADDR, 0xFFFF, &SbcRxBuf);

	eRet += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_COM_FLG_ADDR, 0xFFFF, &SbcRxBuf);

	return eRet;
}

/*********************************************************************
 * Read all flags registers that are linked to certain interrupt events
 * Sbc_Grl_Flags: it's a group of Sbc_Ovuv_Reg_Status, Sbc_Diag_Safety1, and Sbc_Diag_Safety2
 ********************************************************************/
Std_ReturnType Sbc_Read_Interrupt_Flags(void){
	Std_ReturnType sbcSpiStatus = E_OK;

	sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_GRL_FLAGS_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_FS_Reg.Sbc_Grl_Flags = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_OVUV_REG_STATUS_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_FS_Reg.Sbc_Ovuv_Reg_Status = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_DIAG_SAFETY2_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_FS_Reg.Sbc_Diag_Safety2 = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(true, SBC_FS26_FS_DIAG_SAFETY1_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_FS_Reg.Sbc_Diag_Safety1 = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_COM_FLG_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_Main_Reg.Sbc_Com_Flg = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_WIO_FLG_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_Main_Reg.Sbc_Wio_Flg = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_VSUP_FLG_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_Main_Reg.Sbc_Vsup_Flg = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_REG_FLG_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_Main_Reg.Sbc_Reg_Flg = Sbc_RxFrame_Buffer.u16ReadData;

	sbcSpiStatus += Sbc_fs26_ReadRegister(false, SBC_FS26_M_TSD_FLG_ADDR, &Sbc_RxFrame_Buffer);
	Sbc_Main_Reg.Sbc_Tsd_Flg = Sbc_RxFrame_Buffer.u16ReadData;

	return sbcSpiStatus;
}



#if ENABLE_SBC_MSG_PRINT
/****************************************************************
 * Print all the interrupt flags registers.
 ****************************************************************/
void Sbc_Print_Flags(void){
	printf("General Status flag: 0x%02X.\r\n", Sbc_General_Status);
	printf("Sbc_Diag_Safety1: 0x%04X.\r\n", Sbc_FS_Reg.Sbc_Diag_Safety1);
	printf("Sbc_Diag_Safety2: 0x%04X.\r\n", Sbc_FS_Reg.Sbc_Diag_Safety2);
	printf("Sbc_Ovuv_Reg_Status: 0x%04X.\r\n", Sbc_FS_Reg.Sbc_Ovuv_Reg_Status);
	printf("Sbc_Com_Flg: 0x%04X.\r\n", Sbc_Main_Reg.Sbc_Com_Flg);
	printf("Sbc_Wio_Flg: 0x%04X.\r\n", Sbc_Main_Reg.Sbc_Wio_Flg);
	printf("Sbc_Vsup_Flg: 0x%04X.\r\n", Sbc_Main_Reg.Sbc_Vsup_Flg);
	printf("Sbc_Reg_Flg: 0x%04X.\r\n", Sbc_Main_Reg.Sbc_Reg_Flg);
	printf("Sbc_Tsd_Flg: 0x%04X.\r\n", Sbc_Main_Reg.Sbc_Tsd_Flg);
	return;
}
#endif

#if ENABLE_FCCU_MON_TEST
/****************************************************************
 * Modify the FCCU CFG register to set EOUT Test1 mode.
 * In this mode, the EOUT0/1 output level is controlled by the FCCU EINOUT register.
 ****************************************************************/
void Fccu_Init_EOUT_Test(void){
	/* unlock FCCU configuration so that entry into CONFIG state is allowed */
	IP_FCCU->TRANS_LOCK = 0x000000BC;
	/* Poll FCCU status until it's changed to CONFIG state */
	if((IP_FCCU->STAT & FCCU_STAT_STATUS_MASK) != FCCU_STAT_STATUS(1)){
		/* Run the OP1 operation  */
		/* wait if FCCU state transition is progress */
		while((IP_FCCU->CTRL & FCCU_CTRL_OPS_MASK) == FCCU_CTRL_OPS(1));
		/* unlock the operation */
		IP_FCCU->CTRLK = 0x913756AF;
		/* initiate the Op1 operation */
		IP_FCCU->CTRL = 0x00000201;
		/* Check the operation status, wait until the operation is successful */
		while((IP_FCCU->CTRL & FCCU_CTRL_OPS_MASK) != FCCU_CTRL_OPS(3));
	}

	/* EOUT0=high, EOUT1=low to generate FCCU EOUT fault indication signal. */
	IP_FCCU->EINOUT = 0x02;
	/* Modify the CFG register to enable EOUT0/1 signals and enable FOM test1 mode (EOUT0/1 controlled by EINOUT register) */
	IP_FCCU->CFG = FCCU_CFG_FCCU_SET_AFTER_RESET_MASK | FCCU_CFG_FOM(6);

	/* FCCU leaves CONFIG state */
	/* Poll FCCU status until it's changed to NORMAL state */
	if((IP_FCCU->STAT & FCCU_STAT_STATUS_MASK) != FCCU_STAT_STATUS(0)){
		/* Run the OP2 operation  */
		/* wait if FCCU state transition is progress */
		while((IP_FCCU->CTRL & FCCU_CTRL_OPS_MASK) == FCCU_CTRL_OPS(1));
		/* unlock the operation */
		IP_FCCU->CTRLK = 0x825A132B;
		/* initiate the Op1 operation */
		IP_FCCU->CTRL = 0x00000202;
		/* Check the operation status, wait until the operation is successful */
		while((IP_FCCU->CTRL & FCCU_CTRL_OPS_MASK) != FCCU_CTRL_OPS(3));
	}

	return;
}
#endif

/****************************************************************
 * Change SBC to Standby mode (LDO1/LDO2 is ON and Vcore is OFF).
 * Before calling this function:
 * 1) it' recommended to transition MCU from full-performance mode to low speed mode:
 * MCU system clock is changed from PLL 160MHz to FIRC 48MHz.
 * 2) Stop the timer for refreshing SBC WD.
 * 3) Enable the wakeup sources in SBC.
 ****************************************************************/
Std_ReturnType Sbc_User_Enter_Standby(void){
	Std_ReturnType Sbc_Ret = E_OK;

	/* setup the wakeup source: CS pin, GPIO1 falling edge, WAKE1 rising edge£¬ LDT timeout */
	//Sbc_Ret += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_WIO_CFG_ADDR, 0x0435, NULL_PTR);
	Sbc_Ret += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_WIO_CFG_ADDR, FS26_WAKEUP_SOURCE_CFG, NULL_PTR);
	/* Select LDT Function4, wakeup after 12 seconds since entry of low-power mode */
	//Sbc_Ret += Sbc_fs26_SetLDT(SBC_FS26_M_LDT_FNCT_4, SBC_FS26_LDTMODE_LONG, 0, 12, SBC_FS26_LDTLP_STANDBY);
	/* SBC transition to Standby mode */
	Sbc_Ret += Sbc_fs26_SetOperatingMode(SBC_FS26_OPMODE_STANDBY);

	return Sbc_Ret;
}

/****************************************************************
 * Enable and configure the required wakeup source.
 * Transition SBC to LPOFF mode (LDO1/LDO2/Vcore is OFF, MCU is completely powered down).
 * Before calling this function:
 * it' recommended to complete all the necessary clean-up or data storage in MCU because the MCU will be shutdown soon.
  ****************************************************************/
Std_ReturnType Sbc_User_Enter_Lpoff(void){
	Std_ReturnType Sbc_Ret = E_OK;

	/* setup the wakeup source: GPIO1 falling edge, WAKE1 rising edge£¬ LDT timeout */
	Sbc_Ret += Sbc_fs26_WriteRegister(FALSE, SBC_FS26_M_WIO_CFG_ADDR, 0x0415, NULL_PTR);
	/* Select LDT Function4, wakeup after 12 seconds since entry of low-power mode */
	Sbc_Ret += Sbc_fs26_SetLDT(SBC_FS26_M_LDT_FNCT_4, SBC_FS26_LDTMODE_LONG, 0, 12, SBC_FS26_LDTLP_LPOFF);
	/* SBC transition to LPOFF mode */
	Sbc_Ret += Sbc_fs26_SetOperatingMode(SBC_FS26_OPMODE_LPOFF);

	return Sbc_Ret;
}


/*********************************************************************************
 * fs26 enter lp off mode with LDT enabled
 *********************************************************************************/
Std_ReturnType fs26_sleep_with_ldt(void){
	Std_ReturnType sbcSpiStatus = E_OK;
	sbcSpiStatus = Sbc_fs26_SetLDT(SBC_FS26_M_LDT_FNCT_3, SBC_FS26_M_LDT_MODE_LONG, 5, 15, SBC_FS26_FS_LDT_LPSEL_LPOFF);
	return sbcSpiStatus;
}


#ifdef __cplusplus
}
#endif

/** @} */

