//==========================================================================
//**************************************************************************
// Header File Included Area
//**************************************************************************
#include "GPL951_Body.h"


//**************************************************************************
// Contant Defintion Area
//**************************************************************************

//**************************************************************************
// Function Call Publication Area
//**************************************************************************
//void RTC_CheckRDY(void);
//void Check_Reg(void);
//void RTCWCMD(int Addr,int WData);
//void RTCRCMD(int Addr,int RData,int check);
//void RTC_CheckRTCBusy();
//void RTC_SECINT_TEST();
//
//void RTC_TEST_OUT_SET();
//void RTC_INT_TEST(int CheckWK); 

//**************************************************************************
// Global Variable Defintion Area
//************************************************************************** 
unsigned int RDATA1, Wakeup_Flag;       
long RDATA0;                                                                                                                                                         
unsigned int R_Sec, R_Minute, R_Hour, R_Day, R_Week, R_Month, R_Year;

void RTC_Initial()
{
	*P_RTC_Ctrl = C_RTC_SerialIF_En;

	RTCRDATA(0x02);			// First time power on, RTC Reliable Code = 0x0, initial timer and calendar
	
// ============================= If user wants to remove external 32768 x'tal, please remove below code mask =====================================
//	RTCWCMD(0x1,0x09);		// When user remove external 32768 x'tal, change 32768 source to internal slow clock for save more power consumption
//	RTC_CheckRTCBusy();		// Check RTC Macro Write OK 	
//	RTCRDATA(0x01);	
// ===============================================================================================================================================	
	while(RDATA0 != 0x5A)
	{
		RDATA1 = 0;
		R_Sec = 0;
		R_Minute = 0;
		R_Hour = 9;
		R_Day = 26;
		R_Month = 12;
		R_Year = 2016;			
				
		// RTC Reliable Code
		RTCWCMD(0x2,0x5A);
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 		
	
		// Load Timer Value		
		RTCWCMD(0x10,0x00);		
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 	
		RTCWCMD(0x11,0x00);	
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 		
		RTCWCMD(0x12,0x00);	
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 	
		RTCWCMD(0x13,0x00);	
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 	
		RTCWCMD(0x14,0x00);	
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 
		RTCWCMD(0x15,0x00);	
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 	
		RTCRDATA(0x02);
	}

//	 Clear INT Flag
	RTCWCMD(0x40,0xF0);
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 		
	
	// Enable Sec INT
	RTCWCMD(0x50,0x01);	
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 
	RTCRCMD(0x50,0x01,0x1);	
}

//================================================================================
//	Description:	Calendar Function
//	Function:		Calendar_Function()
//	Syntax:			void	Calendar_Function();
//	Input Paramter:	none	
//	Return: 		none
//  Note:			
//================================================================================
void Calendar_Function()
{
	if (R_Sec == 60)
	{
		R_Minute +=1;
		R_Sec = 0;
	}
		
	if (R_Minute == 60)
	{
		R_Hour +=1;
		R_Minute = 0;
	}
		
	if (R_Hour == 24)
	{
		R_Day +=1;
		R_Hour = 0;	
		if (R_Month == 2 && R_Day > 28)
		{
			// Leap Year
			if(R_Year%4==0 && R_Year%100!=0 || R_Year%400==0)
			{
   				if(R_Day > 29)
   				{
     				R_Day = 1;
   					R_Month +=1;
       			}
			}
       				
			else
			{
   				R_Day = 1;
   				R_Month +=1;
			}	
   					
		}		
			
		if (R_Month == 1 || R_Month == 3 || R_Month == 5 || R_Month == 7 || R_Month == 8 || R_Month == 10 || R_Month == 12)
		{
			if (R_Day > 31)
			{					
				R_Day = 1;
   				R_Month +=1;					
			}
		}
			
		if (R_Month == 4 || R_Month == 6 || R_Month == 9 || R_Month == 11)				
		{
			if (R_Day > 30)
			{					
				R_Day = 1;
   				R_Month +=1;					
			}				
		}
	}
		
		if (R_Month == 13)
		{
			R_Month = 1;
			R_Day = 1;
			R_Year+=1;
		}		
			
		R_Week = getWeekday(R_Year,R_Month,R_Day);
		*P_WatchDog_Clear = C_WDT_Clear;

}


//================================================================================
//	Description:	Enter halt mode
//	Function:		Enter_HaltMode()
//	Syntax:			void	Enter_HaltMode();
//	Input Paramter:	none	
//	Return: 		none
//  Note:			Set IOB[7:0] as key wakeup, user can set CPU reset after wake-up or continue the next instruction after wake-up (0x7803[1])
//					This function only enable key chane wakeup, if WDT enable, and user do not clear WDT, GPL951 will reset (WDT default = 2s)
//					Watchdog period set through 0x780A[2:0]
//					This sample code set WDT disable at GPL951_startup.asm
//================================================================================
void Enter_HaltMode()
{
	int i,latch_key_temp;	
//	 Clear INT Flag
	RTCWCMD(0x40,0xF0);
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 		
	// Disable Sec, Alarm INT
	RTCWCMD(0x50,0x00);	
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 
	
	*P_PM_Ctrl = 0x0BFC;
		
	*P_SYS_Ctrl &= ~(0x0002 + 0x0001);	
	*P_SYS_Ctrl |= C_Halt_Wakeup_NextINS + C_CLK32K_External;			
	*P_IOB_KeyChange_En = 0x00FF;
	
	// Set LDO = 1.1V into Halt mode, reduce more power consumption
	*P_SYS_Misc |= C_Halt_LDO_1v1;	
	
	// Enable IOB[7:0] key change interrupt
	*P_IOAB_KCIEN = 0xFF00;		
								
			
	// Must latch IO first, than clear Key Change Interrupt Flag
	// If clear Key Change Interrupt Flag first, than latch IO => function fail	
	// Latch IOB
	latch_key_temp = *P_IOB_Latch;	
	latch_key_temp = *P_IOB_Data;	
			
	// Clear Key Change Interrupt Flag			
	i = *P_IOAB_KCIFC;
	*P_IOAB_KCIFC = i;	
	// Enter halt mode
	Halt();	
	// Clear Key Change Interrupt Flag			
	i = *P_IOAB_KCIFC;
	*P_IOAB_KCIFC = i;		
	*P_IOAB_KCIEN = 0x0000;		// Disable IOB[7:0] key change interrupt

	RTCWCMD(0x40,0xF0);
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 		
	// Enable Sec INT
	RTCWCMD(0x50,0x01);	
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 	
	
}

//================================================================================
//	Description:	Enter deep halt mode
//	Function:		Enter_DeepHaltMode(int Data)
//	Syntax:			void	Enter_DeepHaltMode(int Data);
//	Input Paramter:	Alarm (Unit : Sec) 	
//	Return: 		none
//  Note:			V33_REG, V18_REG power down, only V18_RTC exist
//					Only RTC function work
//					1. Enable RTC Alarm INT
//					2. PWR_On pin must be low status, or it can't go to deep halt mode	
//					3. When GPL951 enter deep halt mode, only power on key and RTC (0.5s, 1s, Alarm) can wakeup
//================================================================================
void Enter_DeepHaltMode(int Data)
{
	unsigned long RTC_Timer, Alarm;
	int i;
	int Set_AlarmTimer; // Unit : Sec
	
	Set_AlarmTimer = Data;
	
	// Read RTC Timer
	*P_RTC_Ctrl = 0x1;		// Serial I/F Enable	
	RTCRDATA(0x30);
	RTC_Timer = RDATA0;	
	*P_RTC_Ctrl = 0x0;		// Serial I/F Disable	
	
	*P_RTC_Ctrl = 0x1;		// Serial I/F Enable	
	RTCRDATA(0x31);
	RTC_Timer |= RDATA0<<8;
	*P_RTC_Ctrl = 0x0;		// Serial I/F Disable	
	
	*P_RTC_Ctrl = 0x1;		// Serial I/F Enable	
	RTCRDATA(0x32);
	RTC_Timer |= RDATA0<<16;
	*P_RTC_Ctrl = 0x0;		// Serial I/F Disable	
	
	*P_RTC_Ctrl = 0x1;		// Serial I/F Enable	
	RTCRDATA(0x33);
	RTC_Timer |= RDATA0<<24;	
	*P_RTC_Ctrl = 0x0;		// Serial I/F Disable				

	//timer data + alaram data for write alarm data into alarm register
	Alarm = (Set_AlarmTimer * 32768) + RTC_Timer;
	Alarm = Alarm>>8;		// Bit[7:0] not exist	 
		
	// Set Alarm Data
	for (i=0x21; i<=0x25;i++)	//0x21 ~ 0x25 : RTC Alarm Register
	{
		*P_RTC_Ctrl = 0x1;		// Serial I/F Enable		
		RTCWCMD(i,(Alarm&0xFF));
		RTC_CheckRTCBusy();	//Check RTC Macro Write OK 	
		Alarm = Alarm>>8;		
		*P_RTC_Ctrl = 0x0;		// Serial I/F Disable
	}			
		
	*P_RTC_Ctrl = 0x1;		// Serial I/F Enable
	RTCWCMD(0x40,0xF0);
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 
	*P_RTC_Ctrl = 0x0;		// Serial I/F Disable				
		
	// Enable Alarm INT
	*P_RTC_Ctrl = 0x1;		// Serial I/F Enable	
	RTCWCMD(0x50,0x06);		
	RTC_CheckRTCBusy();	//Check RTC Macro Write OK 		
	RTCRCMD(0x50,0x06,0x1);			
		
	while ((*P_PwrKey_State & 0x01) != 0)
	{
		__asm ("nop");
		*P_WatchDog_Clear = C_WDT_Clear;
	}		
		
	// Deep Halt Mode, give on hold high pulse for quicky deep power down
	*P_PM_Ctrl |= C_PWON_Hold200ms_Dis;
		__asm ("NOP");
		__asm ("NOP");		
	*P_PM_Ctrl &= ~C_PWON_Hold200ms_Dis;	
	*P_SYS_Ctrl &= ~C_SYSPW_ON;	
	// Deep halt mode wakeup => reset
}


//================================================================================
//	Description:	RTC function code
//	Function:		
//	Syntax:			void	RTC_CheckRDY();
//					void 	RTCWCMD(int Addr,int WData)
//					void 	RTCRCMD(int Addr,int RData,int check)
//					void 	RTC_CheckRTCBusy()
//					void 	RTCRDATA(int Addr)
//	Input Paramter:	Alarm (Unit : Sec) 	
//	Return: 		none
//  Note:			
//================================================================================
void RTC_CheckRDY(){	//Check Serial signal Send Done
	while((*P_RTC_Ready&0x1)!=0x1){}
}

//
void RTCWCMD(int Addr,int WData)
{	
	*P_RTC_Addr = Addr;
	*P_RTC_WriteData = WData;
	*P_RTC_Request = 0x1;//[0]: Write Req [1]: Read Req
	RTC_CheckRDY();
}


void RTCRCMD(int Addr,int RData,int check)
{
	*P_RTC_Addr = Addr;
	RTC_CheckRDY();	//Make Sure can send Data
	*P_RTC_Request = 0x2;//[0]: Write Req [1]: Read Req
	RTC_CheckRDY();
	if(check ==1){
		RDATA0 = *P_RTC_ReadData;
		if(RDATA0 != RData)
		{
			while(1);
		}		
	}
}

void RTC_CheckRTCBusy(){
//Read RTC Macro Address0[4] Busy State 1: In Busy Stata
	RTC_CheckRDY();	//Make Sure can send Serial Data
	*P_RTC_Addr = 0x0;
	*P_RTC_Request = 0x2;//[0]: Write Req [1]: Read Req
	RTC_CheckRDY();
	RDATA0 = *P_RTC_ReadData;
	
	while((RDATA0&0x10)==0x10){
		RTC_CheckRDY();	//Make Sure can send Data
		*P_RTC_Request = 0x2;//[0]: Write Req [1]: Read Req
		RTC_CheckRDY();
		RDATA0 = *P_RTC_ReadData;

	}		
}

void RTCRDATA(int Addr)
{
	*P_RTC_Addr = Addr;
	RTC_CheckRDY();	//Make Sure can send Data
	*P_RTC_Request = 0x2;//[0]: Write Req [1]: Read Req
	RTC_CheckRDY();
	RDATA0 = *P_RTC_ReadData;
	
}

//================================================================================
//	Description:	LeapYear judge
//	Function:		isLeapYear()
//	Syntax:			int	isLeapYear();
//	Input Paramter:	none	
//	Return: 		none
//  Note:			
//================================================================================
int isLeapYear(int R_Year) 
{
	return (R_Year%400==0) || ((R_Year%4==0) && (R_Year%100!=0));
}

int getWeekday(int year, int month, int day) 
{
	//the days of 12 month 
	int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int d, i;
	// If leap year, Month "2" of last day should be "29"
	days[1] += isLeapYear(year);	
	d = day;
	for (i=0; i<month-1; i++) {
		d += days[i];
	}
	// judge this day is week?
	year--;
	d += year + (year/4) - (year/100) + (year/400);
//	d += offset + 7; //Avoid d is negative.
	d %= 7; //0 : Sun, 1 : Mon, 2 : Tue, 3 :Wen, 4: Thu, 5:Fri, 6 : Sat
	return d;

}