/********************************************************************************
*
*  File name:   FrntWiperCtrl.c
*
*********************************************************************************/
/*********************************************************************************
*    Includes
*********************************************************************************/
#include "Rte_App.h"
#include "PassiveStart.h"
#include "FrntWiperCtrl.h"
#include "Eeprom_Ctl.h"

/*********************************************************************************
*   Local  Macros
*********************************************************************************/
#define PAR_FW_WAIT_STALL_TIME						Delay_Base5ms(t1s(18))
#define PAR_FW_WASHER_MAX_ACTIVATION				Delay_Base5ms(t1s(12))
#define PAR_FW_WASH_WIPING_DELAY					Delay_Base5ms(t1ms(280))
#define PAR_FW_WIPING_DELAY_TIME					Delay_Base5ms(t1ms(600))
#define PAR_FW_PROLON_WIPE_CYCLE					3
#define PAR_FW_DRIP_WIPE_WAIT_TIME					Delay_Base5ms(t1s(1))
#define PAR_FW_WASHER_SW_STUCK_TIME					Delay_Base5ms(t1s(60))
#define PAR_FW_MAINTENANCE_MODE_ACTIVE_DELAY_TIMER	Delay_Base5ms(t1s(20))

#define FWIPER_CTL_OFF								0x00
#define FWIPER_CTL_LOW								0x01
#define FWIPER_CTL_HIGH								0x02
#define FWIPER_CTL_INT								0x03
#define FWIPER_CTL_AUTO								0x04
#define FWIPER_CTL_MAINTAIN							0x05

/* Front Wiper State */
#define FWIPER_REQ_STS_OFF							0x01
#define FWIPER_REQ_STS_INT							0x02
#define FWIPER_REQ_STS_LOW							0x03
#define FWIPER_REQ_STS_HIGH							0x04

/*********************************************************************************
*   Local Struct
*********************************************************************************/

/*********************************************************************************
*   Global Variables
*********************************************************************************/

/*********************************************************************************
*   Local Variables
*********************************************************************************/
FWIPER_FLAG_UNION g_uFwiperFlg;
uint8_t g_FwiperPwrMode;
uint8_t g_FwiperDrvMode;
uint8_t g_FwiperSwReqSts;
uint8_t g_FwiperPosSts;
uint8_t g_FwiperCtl;
uint8_t g_FwiperSubStep;
uint16_t g_FwiperIntDly;
uint8_t g_FWipeLevel;
uint8_t g_FwasherStep;
uint8_t g_FrntWiperServiceSts;
uint8_t g_FwiperChangeOffReqSts;

/*********************************************************************************
*   Local Functions
*********************************************************************************/

/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
void Fwiper_DrvSet(uint8_t Speed)
{
	g_FwiperDrvMode = Speed;
	if (WIPER_SPEED_OFF == Speed)
	{
		Rte_Write_Output_FrontWiperEnableOUT(0x00);
		Rte_Write_Output_FrontWiperSpeedOUT(0x00);
		Rte_Write_ComCan_FrnWiprOutpSts(WIPER_SPEED_OFF);	/* Update CAN Sig: Fwiper OFF */
	}
	else if (WIPER_SPEED_LOW == Speed)
	{
		if (0x00 == g_uFwiperFlg.Bits.Blocked) /* Blocked , not allowed to control wiper */
		{
			Rte_Write_Output_FrontWiperEnableOUT(0x01);
			Rte_Write_Output_FrontWiperSpeedOUT(0x00);
			Rte_Write_ComCan_FrnWiprOutpSts(WIPER_SPEED_LOW);	/* Update CAN Sig: Fwiper Low */
		}
	}
	else if (WIPER_SPEED_HIGH == Speed)
	{
		if (0x00 == g_uFwiperFlg.Bits.Blocked) /* Blocked , not allowed to control wiper */
		{
			Rte_Write_Output_FrontWiperEnableOUT(0x01);
			Rte_Write_Output_FrontWiperSpeedOUT(0x01);
			Rte_Write_ComCan_FrnWiprOutpSts(WIPER_SPEED_HIGH);	/* Update CAN Sig: Fwiper High */
		}
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_ReqCtl(uint8_t Req)
{
	if ((WIPER_SPEED_OFF != g_FwiperDrvMode) && (FWIPER_CTL_OFF == Req))
	{
		g_FwiperChangeOffReqSts = 0x01;
	}
	else
	{
		g_FwiperChangeOffReqSts = 0x00;
	}

	g_FwiperCtl = Req;
	g_FwiperSubStep = 0x00;
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Parking_PosChk(void)
{
	static uint16_t FwiperPosBackDly = 0x00;
	static uint16_t FwiperPosAwayDly = 0x00;
	static uint8_t FwiperAwayCnt = 0x00;
	static uint8_t FwiperBackCnt = 0x00;
	static uint8_t s_PrvPwrModeSts = 0x00;

	if (0x00 == Rte_Read_Input_FrontWiperParkSts()) /* Home Position */
	{
		FwiperAwayCnt = 0x00;
		FwiperBackCnt++;
		if ((WIPER_POS_HOME != g_FwiperPosSts) && (Delay_Base5ms(t1ms(18)) <= FwiperBackCnt))
		{
			g_FwiperPosSts = WIPER_POS_HOME;
			Rte_Write_ComCan_FrntWiprParkStsSwt(0x01);
		}
	}
	else
	{
		FwiperAwayCnt++;
		FwiperBackCnt = 0x00;
		if ((WIPER_POS_AWAY != g_FwiperPosSts) && (Delay_Base5ms(t1ms(18)) <= FwiperAwayCnt))
		{
			g_FwiperPosSts = WIPER_POS_AWAY;
			Rte_Write_ComCan_FrntWiprParkStsSwt(0x02);
		}
	}

	if (0x00 == g_uFwiperFlg.Bits.Blocked)
	{
		if (WIPER_SPEED_OFF != g_FwiperDrvMode)
		{
			if (WIPER_POS_AWAY == g_FwiperPosSts)
			{
				FwiperPosBackDly = 0x00;
				FwiperPosAwayDly++;
				if (FwiperPosAwayDly >= PAR_FW_WAIT_STALL_TIME)
				{
					g_uFwiperFlg.Bits.Blocked = 0x01;
					Fwiper_DrvSet(WIPER_SPEED_OFF);
					FwiperPosBackDly = 0x00;
					FwiperPosAwayDly = 0x00;
					/*TODO ADD WIPER BLOCK DTC*/
				}
				else
				{
					/*TODO CLEAR WIPER BLOCK DTC*/
				}
			}
			else
			{
				FwiperPosAwayDly = 0x00;
				FwiperPosBackDly++;
				if (FwiperPosBackDly >= PAR_FW_WAIT_STALL_TIME)
				{
					g_uFwiperFlg.Bits.Blocked = 0x01;
					Fwiper_DrvSet(WIPER_SPEED_OFF);
					FwiperPosBackDly = 0x00;
					FwiperPosAwayDly = 0x00;
					/*TODO ADD WIPER BLOCK DTC*/
				}
				else
				{
					/*TODO CLEAR WIPER BLOCK DTC*/
				}
			}
		}
		else
		{
			FwiperPosBackDly = 0x00;
			FwiperPosAwayDly = 0x00;
		}
	}
	else
	{
		if ((s_PrvPwrModeSts != g_FwiperPwrMode) && (PWRMODE_ON == g_FwiperPwrMode))
		{
			g_uFwiperFlg.Bits.Blocked = 0x00;
			g_FwiperSwReqSts = FWIPER_CTL_OFF;
		}
	}
	s_PrvPwrModeSts = g_FwiperPwrMode;
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void FwiperSw_ReqChk(void)
{
	uint8_t Tmpg_FwiperSwReqSts;

	if (0x00 == g_FrntWiperServiceSts)
	{
		if (0x01 == Rte_Read_ComCan_CIM_FWiperSwtFault())
		{
			Tmpg_FwiperSwReqSts = FWIPER_REQ_STS_INT;
		}
		else
		{
			Tmpg_FwiperSwReqSts = Rte_Read_ComCan_CIM_FWiperSwtReq();
		}
		if ((FWIPER_REQ_STS_HIGH != Tmpg_FwiperSwReqSts) && (0x02 == Rte_Read_ComCan_CIM_FWiperMistReq()))
		{
			Tmpg_FwiperSwReqSts = FWIPER_REQ_STS_LOW;
		}
	}
	else
	{
		Tmpg_FwiperSwReqSts = FWIPER_CTL_MAINTAIN;
	}

	if (g_FwiperSwReqSts == Tmpg_FwiperSwReqSts)
	{
		return;
	}
	if (PWRMODE_ON != g_FwiperPwrMode)
	{
		return;
	}

	g_FwiperSwReqSts = Tmpg_FwiperSwReqSts;
	switch (g_FwiperSwReqSts)
	{
	case FWIPER_REQ_STS_OFF:
		Fwiper_ReqCtl(FWIPER_CTL_OFF);
		break;
	case FWIPER_REQ_STS_LOW:
		g_uFwiperFlg.Bits.Washer = 0x00;
		Fwiper_ReqCtl(FWIPER_CTL_LOW);
		break;
	case FWIPER_REQ_STS_HIGH:
		g_uFwiperFlg.Bits.Washer = 0x00;
		Fwiper_ReqCtl(FWIPER_CTL_HIGH);
		break;
	case FWIPER_REQ_STS_INT:
		if (0x01 == Rte_Read_EepCfg_RAIN_LIGHT_SENSOR_ENABLED()) /*Auto*/
		{
			Fwiper_ReqCtl(FWIPER_CTL_AUTO);
		}
		else
		{
			Fwiper_ReqCtl(FWIPER_CTL_INT);
		}
		break;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void FwiperService_ReqChk(void)
{
	static uint32_t s_FwiperMntnTime = 0x00;
	static uint8_t s_PrvPwrMode = 0x00;
	static uint8_t s_Prvg_FwiperSwReqSts = 0x00;
	uint32_t Tmpg_FwiperSwReqSts = 0;

	if (0x02 == Rte_Read_ComCan_CIM_FWiperMistReq())
	{
		Tmpg_FwiperSwReqSts = FWIPER_REQ_STS_LOW;
	}
	else
	{
		Tmpg_FwiperSwReqSts = Rte_Read_ComCan_CIM_FWiperSwtReq();
	}
	if (s_FwiperMntnTime)
	{
		s_FwiperMntnTime--;
	}

	if (0x00 == g_FrntWiperServiceSts)
	{
		if (s_PrvPwrMode != g_FwiperPwrMode)
		{
			if (PWRMODE_OFF == g_FwiperPwrMode)
			{
				s_FwiperMntnTime = PAR_FW_MAINTENANCE_MODE_ACTIVE_DELAY_TIMER;
			}
			else
			{
				s_FwiperMntnTime = 0x00;
			}
		}

		if ((0x01 == Rte_Read_ComCan_ICC_WiprMntnModSwt()) && (PWRMODE_ON == g_FwiperPwrMode)
			&& (WIPER_SPEED_OFF == g_FwiperDrvMode) && (DOOR_AJAR_CLOSE == Rte_Read_Input_HoodAjarSts()))
		{
			s_FwiperMntnTime = 0x00;
			g_FrntWiperServiceSts = 0x01;
			Fwiper_ReqCtl(FWIPER_CTL_MAINTAIN);
			Rte_Write_ComCan_FrntWiprMntnSts(0x01);
		}
		else if ((0x02 == Rte_Read_ComCan_CIM_FWiperMistReq()) && (0x00 != s_FwiperMntnTime)
			&& (WIPER_POS_HOME == g_FwiperPosSts) && (DOOR_AJAR_CLOSE == Rte_Read_Input_HoodAjarSts()))
		{
			s_FwiperMntnTime = 0x00;
			g_FrntWiperServiceSts = 0x02;
			Fwiper_ReqCtl(FWIPER_CTL_MAINTAIN);
			Rte_Write_ComCan_FrntWiprMntnSts(0x01);
		}
	}
	else
	{
		if (((0x02 == Rte_Read_ComCan_ICC_WiprMntnModSwt()) && (0x01 == g_FrntWiperServiceSts) && (PWRMODE_ON == g_FwiperPwrMode))
			|| ((0x02 == g_FrntWiperServiceSts) && (((s_PrvPwrMode != g_FwiperPwrMode) && (PWRMODE_OFF == g_FwiperPwrMode))
			|| (0x02 == Rte_Read_ComCan_CIM_FWiperWashReq())
			|| ((FWIPER_REQ_STS_OFF == s_Prvg_FwiperSwReqSts) && (FWIPER_REQ_STS_OFF != Tmpg_FwiperSwReqSts)))))
		{
			g_FrntWiperServiceSts = 0x00;
			Rte_Write_ComCan_FrntWiprMntnSts(0x02);
		}
	}

	s_PrvPwrMode = g_FwiperPwrMode;
	s_Prvg_FwiperSwReqSts = Tmpg_FwiperSwReqSts;
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void FwiperWash_ReqChk(void)
{
	static uint32_t FwasherDly;
	static uint8_t FwasherValid = 0x00;
	static uint8_t FwasherSwBlk = 0x00;
	uint8_t TmpWasherReqSts = 0x00;

	if ((PWRMODE_ON != g_FwiperPwrMode) || ((VOLT_MODE_NORMAL != Rte_Read_AppPm_VoltMode()) && (VOLT_MODE_HIGH != Rte_Read_AppPm_VoltMode())))
	{
		if (0x01 == g_uFwiperFlg.Bits.WashSw)
		{
			g_uFwiperFlg.Bits.WashSw = 0x00;
			Rte_Write_Output_FrontWasherOUT(0x00);
			Rte_Write_ComCan_FrntWshrCmd(0x00);
		}
		return;
	}

	FwasherDly++;
	TmpWasherReqSts = Rte_Read_ComCan_CIM_FWiperWashReq();
	if (0x00 == g_uFwiperFlg.Bits.WashSw)
	{
		if (0x02 == TmpWasherReqSts)
		{
			if (0x00 == FwasherSwBlk)
			{
				g_uFwiperFlg.Bits.WashSw = 0x01;
				FwasherDly = 0x00;
				FwasherValid = 0x00;
				Rte_Write_Output_FrontWasherOUT(0x01);
				Rte_Write_ComCan_FrntWshrCmd(0x01);
				/*TODO CLEAR WASH BLOCK DTC*/
			}
			else
			{
				if (PAR_FW_WASHER_SW_STUCK_TIME <= FwasherDly)
				{
					/*TODO ADD WASH BLOCK DTC*/
				}
			}
		}
		else
		{
			FwasherSwBlk = 0x00;
		}
	}
	else
	{
		if (0x02 == TmpWasherReqSts)
		{
			if ((0x00 == FwasherValid) && (PAR_FW_WASH_WIPING_DELAY == FwasherDly))
			{
				FwasherValid = 0x01;
			}
			else if (PAR_FW_WASHER_MAX_ACTIVATION <= FwasherDly)
			{
				FwasherSwBlk = 0x01;
				g_uFwiperFlg.Bits.WashSw = 0x00;
				Rte_Write_Output_FrontWasherOUT(0x00);
				Rte_Write_ComCan_FrntWshrCmd(0x00);
			}
		}
		else
		{
			FwasherSwBlk = 0x00;
			g_uFwiperFlg.Bits.WashSw = 0x00;
			Rte_Write_Output_FrontWasherOUT(0x00);
			Rte_Write_ComCan_FrntWshrCmd(0x00);
		}
	}

	if ((0x01 == FwasherValid) && (PAR_FW_WIPING_DELAY_TIME <= FwasherDly)
		&& (((FWIPER_CTL_AUTO == g_FwiperCtl) && (WIPER_SPEED_OFF == g_FwiperDrvMode))
		|| (FWIPER_CTL_INT == g_FwiperCtl) || (FWIPER_CTL_OFF == g_FwiperCtl)))
	{
		FwasherValid = 0x00;
		g_FwasherStep = WASHER_STEP_START;
		g_uFwiperFlg.Bits.Washer = 0x01; /* Enable Washer Operation */
		g_uFwiperFlg.Bits.Blocked = 0x00;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void FwiperWasher_OutputCtrl(void)
{
	static uint16_t FwasherDly = 0x00;
	static uint8_t FwasherCnt = 0x00;

	if (0x00 == g_uFwiperFlg.Bits.Washer)
	{
		return;
	}
	if ((PWRMODE_ON != g_FwiperPwrMode) || ((VOLT_MODE_NORMAL != Rte_Read_AppPm_VoltMode()) && (VOLT_MODE_HIGH != Rte_Read_AppPm_VoltMode())))
	{
		g_uFwiperFlg.Bits.WashSw = 0x00;
		g_uFwiperFlg.Bits.Washer = 0x00;
		Rte_Write_Output_FrontWasherOUT(0x00);
		Rte_Write_ComCan_FrntWshrCmd(0x00);
		g_FwiperSwReqSts = FWIPER_REQ_STS_OFF;
		Fwiper_ReqCtl(FWIPER_CTL_OFF);
		return;
	}

	switch (g_FwasherStep)
	{
	case WASHER_STEP_START: /* directly start Low Speed, no matter last state */
		FwasherCnt = 0x00;
		Fwiper_DrvSet(WIPER_SPEED_LOW);
		if (0x00 == g_uFwiperFlg.Bits.WashSw) /* Washer Switch Released */
		{
			g_FwasherStep = WASHER_STEP_EXTRA_AWAY;
		}
		else
		{
			g_FwasherStep = WASHER_STEP_CHK_AWAY;
		}
		break;

	case WASHER_STEP_CHK_AWAY: /* make sure WIPER away from STOP position */
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwasherStep = WASHER_STEP_CHK_BACK;
		}
		break;

	case WASHER_STEP_CHK_BACK:
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_LOW);
			if (0x00 == g_uFwiperFlg.Bits.WashSw) /* Washer Switch Released */
			{
				g_FwasherStep = WASHER_STEP_EXTRA_AWAY;
			}
			else
			{
				g_FwasherStep = WASHER_STEP_CHK_AWAY;
			}
		}
		break;

	case WASHER_STEP_EXTRA_AWAY:
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			FwasherCnt++;
			g_FwasherStep = WASHER_STEP_EXTRA_BACK;
		}
		break;

	case WASHER_STEP_EXTRA_BACK:
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			FwasherCnt++;
			if (FwasherCnt >= PAR_FW_PROLON_WIPE_CYCLE) /* WIPER execute 3 loop */
			{
				Fwiper_DrvSet(WIPER_SPEED_OFF);
				FwasherDly = 0x00;
				g_FwasherStep = WASHER_STEP_WAIT_DLY;
			}
			else
			{
				Fwiper_DrvSet(WIPER_SPEED_LOW);
				g_FwasherStep = WASHER_STEP_EXTRA_AWAY;
			}
		}
		break;

	case WASHER_STEP_WAIT_DLY:
		FwasherDly++;
		if(FwasherDly >= PAR_FW_DRIP_WIPE_WAIT_TIME)
		{
			Fwiper_DrvSet(WIPER_SPEED_LOW);		/* WIPER execute extra one loop */
			g_FwasherStep = WASHER_STEP_LAST_AWAY;
		}
		break;

	case WASHER_STEP_LAST_AWAY:
		if(WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwasherStep = WASHER_STEP_LAST_BACK;
		}
		break;

	case WASHER_STEP_LAST_BACK:
		if(WIPER_POS_HOME == g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwasherStep = WASHER_STEP_LAST_WAIT;
		}
		break;

	case WASHER_STEP_LAST_WAIT:
		g_uFwiperFlg.Bits.Washer = 0x00;
		if (FWIPER_CTL_INT == g_FwiperCtl)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwiperIntDly = 0x00;
			g_FwiperSubStep = INT_STEP_WAIT_DLY;
		}
		else if (FWIPER_CTL_AUTO == g_FwiperCtl)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwiperSubStep = AUTO_STEP_AUTO_CHK;
		}
		break;

	default:
		g_FwasherStep = WASHER_STEP_START;
		break;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_OffCtl(void)
{
	if (g_uFwiperFlg.Bits.Washer)
	{
		return;
	}
	switch (g_FwiperSubStep)
	{
	case OFF_STEP_START: /* directly start Low Speed, no matter last state */
		if (0xFF == g_FwiperPosSts)
		{
			break;
		}
		if(WIPER_POS_HOME != g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_LOW);
			g_FwiperSubStep = OFF_STEP_CHK_BACK;
		}
		else
		{
			if (0x01 == g_FwiperChangeOffReqSts)
			{
				Fwiper_DrvSet(WIPER_SPEED_LOW);
				g_FwiperSubStep = OFF_STEP_WAIT_AWAY;
			}
			else
			{
				Fwiper_DrvSet(WIPER_SPEED_OFF);
				g_FwiperSubStep = OFF_STEP_IDLE;
			}
		}
		g_FwiperChangeOffReqSts = 0x00;
		break;
	case OFF_STEP_WAIT_AWAY: /* Wait currently LOOP end*/
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = OFF_STEP_CHK_BACK;
		}
		break;
	case OFF_STEP_CHK_BACK: /* Wait currently LOOP end*/
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			g_FwiperSubStep = OFF_STEP_WAIT_MORE;
		}
		break;
	case OFF_STEP_WAIT_MORE:
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwiperSubStep = OFF_STEP_IDLE;
		}
		else
		{
			g_FwiperSubStep = OFF_STEP_CHK_BACK;
		}
		break;
	case OFF_STEP_IDLE:
		/* Additional Check Make sure Wiper alway Stay Home Postion */
		if ((WIPER_POS_HOME != g_FwiperPosSts) && (PWRMODE_ON == g_FwiperPwrMode))
		{
			g_FwiperSubStep = OFF_STEP_START;
		}
		break;
	default:
		g_FwiperSubStep = OFF_STEP_START;
		break;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_LowCtl(void)
{
	if (PWRMODE_ON != g_FwiperPwrMode)
	{
		g_FwiperSwReqSts = FWIPER_REQ_STS_OFF;
		Fwiper_ReqCtl(FWIPER_CTL_OFF);
		return;
	}

	if (0x00 == g_FwiperSubStep)
	{
		Fwiper_DrvSet(WIPER_SPEED_LOW);
		g_FwiperSubStep++;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_HighCtl(void)
{
	if(PWRMODE_ON != g_FwiperPwrMode)
	{
		g_FwiperSwReqSts = FWIPER_REQ_STS_OFF;
		Fwiper_ReqCtl(FWIPER_CTL_OFF);
		return;
	}

	if(0x00 == g_FwiperSubStep)
	{
		Fwiper_DrvSet(WIPER_SPEED_HIGH);
		g_FwiperSubStep++;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
uint8_t Fwiper_IntDwellTimeChk(void)
{
	const uint16_t FwiperIntTime[4][6] =
	{
		{ Delay_Base5ms(t1ms(18000)), Delay_Base5ms(t1ms(15500)), Delay_Base5ms(t1ms(13000)), Delay_Base5ms(t1ms(11900)), Delay_Base5ms(t1ms(10700)), Delay_Base5ms(t1ms(10100)) },
		{ Delay_Base5ms(t1ms(8000)), Delay_Base5ms(t1ms(6000)), Delay_Base5ms(t1ms(5000)), Delay_Base5ms(t1ms(4600)), Delay_Base5ms(t1ms(4200)), Delay_Base5ms(t1ms(3900)) },
		{ Delay_Base5ms(t1ms(5000)), Delay_Base5ms(t1ms(3500)), Delay_Base5ms(t1ms(3000)), Delay_Base5ms(t1ms(2800)), Delay_Base5ms(t1ms(2600)), Delay_Base5ms(t1ms(2500)) },
		{ Delay_Base5ms(t1ms(2000)), Delay_Base5ms(t1ms(1000)), Delay_Base5ms(t1ms(800)), Delay_Base5ms(t1ms(700)), Delay_Base5ms(t1ms(600)), Delay_Base5ms(t1ms(600)) },
	};
	uint16_t TmpEspVhelSpd;
	static uint8_t PrvIntVhelSpdLev = 0x00;
	uint8_t IntVhelSpdLev = 0x01;
	uint8_t IntRheostatPosLev;

	if (VEH_SPEED_VALID == Rte_Read_ComCan_VehSpdVld())
	{
		TmpEspVhelSpd = Rte_Read_ComCan_VehSpd();
		switch (PrvIntVhelSpdLev)
		{
		case 0x00:
			if (VEH_SPEED_8KM > TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x00;
			}
			else if (((VEH_SPEED_8KM + VEH_SPEED_2KM) <= TmpEspVhelSpd) && (VEH_SPEED_32KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x01;
			}
			else if ((VEH_SPEED_32KM <= TmpEspVhelSpd) && (VEH_SPEED_64KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x02;
			}
			else if ((VEH_SPEED_64KM <= TmpEspVhelSpd) && (VEH_SPEED_96KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x03;
			}
			else if ((VEH_SPEED_96KM <= TmpEspVhelSpd) && (VEH_SPEED_128KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x04;
			}
			else if (VEH_SPEED_128KM <= TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x05;
			}
			break;
		case 0x01:
			if (VEH_SPEED_8KM > TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x00;
			}
			else if ((VEH_SPEED_8KM <= TmpEspVhelSpd) && (VEH_SPEED_32KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x01;
			}
			else if (((VEH_SPEED_32KM + VEH_SPEED_2KM) <= TmpEspVhelSpd) && (VEH_SPEED_64KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x02;
			}
			else if ((VEH_SPEED_64KM <= TmpEspVhelSpd) && (VEH_SPEED_96KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x03;
			}
			else if ((VEH_SPEED_96KM <= TmpEspVhelSpd) && (VEH_SPEED_128KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x04;
			}
			else if (VEH_SPEED_128KM <= TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x05;
			}
			break;
		case 0x02:
			if (VEH_SPEED_8KM > TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x00;
			}
			else if ((VEH_SPEED_8KM <= TmpEspVhelSpd) && (VEH_SPEED_32KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x01;
			}
			else if ((VEH_SPEED_32KM <= TmpEspVhelSpd) && (VEH_SPEED_64KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x02;
			}
			else if (((VEH_SPEED_64KM + VEH_SPEED_2KM) <= TmpEspVhelSpd) && (VEH_SPEED_96KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x03;
			}
			else if ((VEH_SPEED_96KM <= TmpEspVhelSpd) && (VEH_SPEED_128KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x04;
			}
			else if (VEH_SPEED_128KM <= TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x05;
			}
			break;
		case 0x03:
			if (VEH_SPEED_8KM > TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x00;
			}
			else if ((VEH_SPEED_8KM <= TmpEspVhelSpd) && (VEH_SPEED_32KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x01;
			}
			else if ((VEH_SPEED_32KM <= TmpEspVhelSpd) && (VEH_SPEED_64KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x02;
			}
			else if ((VEH_SPEED_64KM <= TmpEspVhelSpd) && (VEH_SPEED_96KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x03;
			}
			else if (((VEH_SPEED_96KM + VEH_SPEED_2KM) <= TmpEspVhelSpd) && (VEH_SPEED_128KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x04;
			}
			else if (VEH_SPEED_128KM <= TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x05;
			}
			break;
		case 0x04:
			if (VEH_SPEED_8KM > TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x00;
			}
			else if ((VEH_SPEED_8KM <= TmpEspVhelSpd) && (VEH_SPEED_32KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x01;
			}
			else if ((VEH_SPEED_32KM <= TmpEspVhelSpd) && (VEH_SPEED_64KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x02;
			}
			else if ((VEH_SPEED_64KM <= TmpEspVhelSpd) && (VEH_SPEED_96KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x03;
			}
			else if ((VEH_SPEED_96KM <= TmpEspVhelSpd) && (VEH_SPEED_128KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x04;
			}
			else if ((VEH_SPEED_128KM + VEH_SPEED_2KM) <= TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x05;
			}
			break;
		case 0x05:
			if (VEH_SPEED_8KM > TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x00;
			}
			else if ((VEH_SPEED_8KM <= TmpEspVhelSpd) && (VEH_SPEED_32KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x01;
			}
			else if ((VEH_SPEED_32KM <= TmpEspVhelSpd) && (VEH_SPEED_64KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x02;
			}
			else if ((VEH_SPEED_64KM <= TmpEspVhelSpd) && (VEH_SPEED_96KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x03;
			}
			else if ((VEH_SPEED_96KM <= TmpEspVhelSpd) && (VEH_SPEED_128KM > TmpEspVhelSpd))
			{
				IntVhelSpdLev = 0x04;
			}
			else if (VEH_SPEED_128KM <= TmpEspVhelSpd)
			{
				IntVhelSpdLev = 0x05;
			}
			break;
		}
	}
	else
	{
		IntVhelSpdLev = 0x01;
	}
	PrvIntVhelSpdLev = IntVhelSpdLev;

	if (0x00 == Rte_Read_EepCfg_FRONT_WIPER_INT())
	{
		IntRheostatPosLev = 0x02;
	}
	else
	{
		IntRheostatPosLev = g_FWipeLevel;
	}
	PrvIntVhelSpdLev = IntVhelSpdLev;

	return FwiperIntTime[IntRheostatPosLev][IntVhelSpdLev];
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_IntCtl(void)
{
	static uint8_t s_PrvFWipeLevel = 0x00;

	if ((g_uFwiperFlg.Bits.Washer) || (PWRMODE_ON != g_FwiperPwrMode))
	{
		g_FwiperSwReqSts = FWIPER_REQ_STS_OFF;
		Fwiper_ReqCtl(FWIPER_CTL_OFF);
		return;
	}

	switch (g_FwiperSubStep)
	{
	case INT_STEP_START: /* directly start Low Speed, no matter last state */
		Fwiper_DrvSet(WIPER_SPEED_LOW);
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = INT_STEP_CHK_BACK;
		}
		else
		{
			g_FwiperSubStep = INT_STEP_CHK_AWAY;
		}
		break;
	case INT_STEP_CHK_AWAY: /* make sure WIPER away from STOP position */
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = INT_STEP_CHK_BACK;
		}
		break;
	case INT_STEP_CHK_BACK: /* waiting WIPER back to STOP POS */
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			g_FwiperSubStep = INT_STEP_WAIT_MORE;
		}
		break;
	case INT_STEP_WAIT_MORE:
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwiperIntDly = 0x00;
			g_FwiperSubStep = INT_STEP_WAIT_DLY;
		}
		else /* Error:  */
		{
			g_FwiperSubStep = INT_STEP_START; /* Start another loop */
		}
		break;
	case INT_STEP_WAIT_DLY: /* waiting INTERVAL delay */
		if ((Fwiper_IntDwellTimeChk() <= g_FwiperIntDly) || (s_PrvFWipeLevel < g_FWipeLevel))
		{
			g_FwiperSubStep = INT_STEP_START; /* Start another loop */
		}
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = INT_STEP_START;
		}
		break;
	default:
		g_FwiperSubStep = INT_STEP_START;
		break;
	}
	s_PrvFWipeLevel = g_FWipeLevel;
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_AutoCtl(void)
{
	static uint8_t s_PrvRlsWiperSpdReq = 0x00;
	uint8_t TmpRlsWiperSpdReq;

	if ((g_uFwiperFlg.Bits.Washer) || (PWRMODE_ON != g_FwiperPwrMode)
		|| ((VOLT_MODE_NORMAL != Rte_Read_AppPm_VoltMode()) && (VOLT_MODE_HIGH != Rte_Read_AppPm_VoltMode())))
	{
		g_FwiperSwReqSts = FWIPER_REQ_STS_OFF;
		Fwiper_ReqCtl(FWIPER_CTL_OFF);
		return;
	}

	if (0x01 == Rte_Read_ComLin_RLS_SplashReq())
	{
		TmpRlsWiperSpdReq = WIPER_SPEED_HIGH;
	}
	else
	{
		switch (Rte_Read_ComLin_RLS_WIPRSPDREQ())
		{
		case 0x00:
			TmpRlsWiperSpdReq = WIPER_SPEED_OFF;
			break;
		case 0x05:
			TmpRlsWiperSpdReq = WIPER_SPEED_LOW;
			break;
		case 0x0F:
			TmpRlsWiperSpdReq = WIPER_SPEED_HIGH;
			break;
		default:
			TmpRlsWiperSpdReq = s_PrvRlsWiperSpdReq;
			break;
		}
	}
	if (0x01 == g_uFwiperFlg.Bits.WashSw)
	{
		if (s_PrvRlsWiperSpdReq > TmpRlsWiperSpdReq)
		{
			TmpRlsWiperSpdReq = s_PrvRlsWiperSpdReq;
		}
	}
	s_PrvRlsWiperSpdReq = TmpRlsWiperSpdReq;

	switch (g_FwiperSubStep)
	{
	case AUTO_STEP_START: /* directly start Low Speed, no matter last state */
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_LOW);
		}
		g_FwiperSubStep = AUTO_STEP_CHK_BACK;
		break;
	case AUTO_STEP_CHK_AWAY: /* make sure WIPER away from STOP position */
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = AUTO_STEP_CHK_BACK;
		}
		break;
	case AUTO_STEP_CHK_BACK: /* waiting WIPER back to STOP POS */
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwiperSubStep = AUTO_STEP_CHK_RLS;
		}
		break;
	case AUTO_STEP_CHK_RLS:
		if (Delay_Base5ms(t1ms(200)) <= g_FwiperIntDly)
		{
			g_FwiperSubStep = AUTO_STEP_AUTO_CHK;
		}
		break;
	case AUTO_STEP_AUTO_CHK:
		if (WIPER_SPEED_OFF != TmpRlsWiperSpdReq)
		{
			Fwiper_DrvSet(TmpRlsWiperSpdReq);
			g_FwiperSubStep = AUTO_STEP_AUTO_AWAY;
		}
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = AUTO_STEP_START;
		}
		break;
	case AUTO_STEP_AUTO_AWAY:
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = AUTO_STEP_AUTO_BACK;
		}
		else
		{
			if (g_FwiperDrvMode != TmpRlsWiperSpdReq)
			{
				if (WIPER_SPEED_OFF == TmpRlsWiperSpdReq)
				{
					Fwiper_DrvSet(WIPER_SPEED_LOW);
				}
				else
				{
					Fwiper_DrvSet(TmpRlsWiperSpdReq);
				}
			}
		}
		break;
	case AUTO_STEP_AUTO_BACK:
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			if (WIPER_SPEED_OFF == TmpRlsWiperSpdReq)
			{
				Fwiper_DrvSet(WIPER_SPEED_OFF);
			}
			g_FwiperSubStep = AUTO_STEP_AUTO_CHK;
		}
		else
		{
			if (g_FwiperDrvMode != TmpRlsWiperSpdReq)
			{
				if (WIPER_SPEED_OFF == TmpRlsWiperSpdReq)
				{
					Fwiper_DrvSet(WIPER_SPEED_LOW);
				}
				else
				{
					Fwiper_DrvSet(TmpRlsWiperSpdReq);
				}
			}
		}
		break;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_MaintainCtl(void)
{
	static uint16_t FwiperServiceDly;
	const uint16_t FwiperMntnRuningTime[8] =
	{
		Delay_Base5ms(t1ms(500)),
		Delay_Base5ms(t1ms(600)),
		Delay_Base5ms(t1ms(700)),
		Delay_Base5ms(t1ms(800)),
		Delay_Base5ms(t1ms(900)),
		Delay_Base5ms(t1ms(1000)),
		Delay_Base5ms(t1ms(1100)),
		Delay_Base5ms(t1ms(1200)),
	};

	if(FwiperServiceDly)
	{
		FwiperServiceDly--;
	}
	switch (g_FwiperSubStep)
	{
	case MTMD_STEP_START: /* directly start Low Speed, no matter last state */
		Fwiper_DrvSet(WIPER_SPEED_LOW);
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			g_FwiperSubStep = MTMD_STEP_WAIT_BACK;
		}
		else
		{
			g_FwiperSubStep = MTMD_STEP_CHK_AWAY;
		}
		break;
	case MTMD_STEP_WAIT_BACK: /* Wait currently LOOP end*/
		if (WIPER_POS_HOME == g_FwiperPosSts)
		{
			g_FwiperSubStep = MTMD_STEP_CHK_AWAY;
		}
		break;
	case MTMD_STEP_CHK_AWAY: /* make sure WIPER away from STOP position */
		if (WIPER_POS_HOME != g_FwiperPosSts)
		{
			FwiperServiceDly = FwiperMntnRuningTime[Rte_Read_Did_FWipeMntnRuningTime()];
			g_FwiperSubStep = MTMD_STEP_CHK_DLY;
		}
		break;
	case MTMD_STEP_CHK_DLY:
		if (0x00 == FwiperServiceDly)
		{
			Fwiper_DrvSet(WIPER_SPEED_OFF);
			g_FwiperSubStep = MTMD_STEP_WAIT;
		}
		else if (DOOR_AJAR_OPEN == Rte_Read_Input_HoodAjarSts())
		{
			if (WIPER_SPEED_OFF != g_FwiperDrvMode)
			{
				Fwiper_DrvSet(WIPER_SPEED_OFF);
			}
			FwiperServiceDly++;
		}
		else
		{
			if (WIPER_SPEED_LOW != g_FwiperDrvMode)
			{
				Fwiper_DrvSet(WIPER_SPEED_LOW);
			}
		}
		break;
	case MTMD_STEP_WAIT:
		break;
	default:
		g_FwiperSubStep = MTMD_STEP_START;
		break;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void Fwiper_ModeCtl(void)
{
	switch (g_FwiperCtl)
	{
	case FWIPER_CTL_LOW:
		Fwiper_LowCtl();
		break;
	case FWIPER_CTL_HIGH:
		Fwiper_HighCtl();
		break;
	case FWIPER_CTL_INT:
		Fwiper_IntCtl();
		break;
	case FWIPER_CTL_AUTO:
		Fwiper_AutoCtl();
		break;
	case FWIPER_CTL_MAINTAIN:
		Fwiper_MaintainCtl();
		break;
	case FWIPER_CTL_OFF:
	default:
		Fwiper_OffCtl();
		break;
	}
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
static void FrntWiper_StsSync(void)
{
	uint8_t Tmp;

	g_FwiperPwrMode = Rte_Read_AppPs_PwrMod();
	if (0x00 == Rte_Read_AppVfmm_RefrshModRestrntFctCmd())
	{
		g_FwiperPwrMode = PWRMODE_OFF;
	}

	Tmp = Rte_Read_ComCan_ICC_BCMWipeLevel();
	if ((0x01 <= Tmp) && (0x04 >= Tmp))
	{
		g_FWipeLevel = Tmp;
	}
	else if (0x00 != Tmp)
	{
		g_FWipeLevel = 0x02;
	}
	Rte_Write_ComCan_WipeLevelFB(g_FWipeLevel);

	g_FwiperIntDly++;
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
void FrntWiper_Init(void)
{
	g_uFwiperFlg.Byte = 0x00;
	g_FwiperPwrMode = Rte_Read_AppPs_PwrMod();
	g_FwiperDrvMode = WIPER_SPEED_OFF;
	g_FwiperPosSts = WIPER_POS_HOME;
	Rte_Write_ComCan_FrntWiprParkStsSwt(0x01);

	g_FwiperIntDly = 0x00;
	g_FwiperSwReqSts = FWIPER_CTL_OFF;
	g_FwiperCtl = FWIPER_MODE_OFF;
	g_FwiperSubStep = OFF_STEP_IDLE;
	g_FwiperChangeOffReqSts = 0x00;
	g_FwasherStep = 0x00;
	g_FrntWiperServiceSts = 0x00;
}
/*********************************************************************************
* Description:
* Para:   NULL
* Para1:  NULL
* Para2:  NULL
* Return: NULL
*********************************************************************************/
void FrntWiper_MainFunction(void)
{
	FrntWiper_StsSync();
	Parking_PosChk();
	//FrntWiper_IOCtrlChk();
	//if(uFwiperIOCtlFlg.Bits.IOCtlFlg)		/* DID IO Control State: Not Execute any Application Function */
	//{
	//	return;
	//}
	FwiperSw_ReqChk();
	FwiperService_ReqChk();
	FwiperWash_ReqChk();
	FwiperWasher_OutputCtrl();
	Fwiper_ModeCtl();
}
