/*******************************************************************************
版权所有：	
版本号：    1.00 
文件名：    sysTime.c 
生成日期：  2008.8.16    
作者：      
功能说明：系统时间维护及GPS对时处理   
修改日志：  
日志1：           
修改者：    
修改日期：
修改内容：
修改原因：
****************************************************************************/
#include "head.h"
#ifdef CPU_FUXI
#include <sys/time.h>
#include <sys/timeb.h>
#include <mb.h>
#include <my_rtc.h>
#endif

extern unsigned int g_keep_alive_gps;
#ifdef CPU_FUXI
int g_rtc_ok;
#endif

void sys_time_get(struct rtc_time_t *pct)
{
	struct timespec ts;

	clk_time_get(&ts);
	timespec_to_rtc(ts,pct,1);
}

#ifdef CPU_FUXI
int sys_time_set(struct rtc_time_t *pct)
{
	int ret = 0;
	char pchDT[30];
	struct timespec ts;
	SHM_TS_T shm_ts;

	if(rtc_to_timespec(pct,&ts) != 0)
	{
		return -1;
	}

	// shm_ts.ts = ts;
	// shm_comm_packet_write(SHM_ADDR_D_TIME, (uint8_t *)&shm_ts, sizeof(SHM_TS_T));
	// mb_notice_time_update();

	sprintf(pchDT, "date -s '%04d-%02d-%02d %02d:%02d:%02d'", pct->year + 2000, pct->month, pct->day, pct->hour, pct->min, pct->ms / 1000);
	system(pchDT);
	system("hwclock -w");
	system("sync");
	
	rt_printf("设置系统时间: %s\n", pchDT);
	ret = gps_set_time(&ts);

	return ret;
}

int sys_time_set_kernal(struct rtc_time_t *pct)
{
	int ret = 0;
	char pchDT[30];
	struct timespec ts;

	if(rtc_to_timespec(pct,&ts) != 0)
	{
		return -1;
	}

	sprintf(pchDT, "date -s '%04d-%02d-%02d %02d:%02d:%02d'", pct->year + 2000, pct->month, pct->day, pct->hour, pct->min, pct->ms / 1000);
	system(pchDT);
	system("hwclock -w");
	system("sync");
	
	printf("设置系统时间: %s\n", pchDT);
	ret = gps_set_time(&ts);

	return ret;	
}

void sys_time_check(void)
{
	struct rtc_time_t ct;
	SHM_TS_T shm_ts;	
	int ret;
	
	if(g_rtc_ok < 0)
	{
		ret = shm_comm_packet_read(SHM_ADDR_U_TIME, sizeof(SHM_TS_T), (uint8_t *)&shm_ts, sizeof(SHM_TS_T));
		if(ret >= 0)
		{
			g_rtc_ok = 0;
			timespec_to_rtc(shm_ts.ts, &ct, 1);
			if(ct.hour>=24||ct.min>=60||ct.month>12||ct.day>31||ct.day==0||ct.month==0)  // 读取时钟错误
			{
				rt_printf("app read rtc data error.");
				return;
			}
			sys_time_set_kernal(&ct);
			rt_printf("app read rtc succeed.");
		}
	}
}

#else
int sys_time_set(struct rtc_time_t *pct)
{
	int ret;
	struct timespec ts;

	if(rtc_to_timespec(pct,&ts) != 0)
	{
		return -1;
	}
	
	ret = clk_time_set(&ts);
	return ret;
}
#endif

void sys_time_set_rmt(struct rtc_time_t *pt)  
{
	sys_time_set(pt);
}


void sys_time_init_zero(struct rtc_time_t *p_mt)
{
	p_mt->year=8;
	p_mt->month=8;
	p_mt->day=8;
	p_mt->hour=8;
	p_mt->min=8;
	p_mt->ms=8000;
}

// 系统时钟已在clk_init中初始化，此处重新初始化是为了保存SOE.
#ifdef CPU_FUXI
void sys_time_init(void)
{
	struct rtc_time_t ct;
	SHM_TS_T shm_ts;
	bool err=false;
	int ret,i;

	// GPS已ok，不检查实时时钟
	if(g_keep_alive_gps)
	{
		return;

	}
#if 0	
	if(rtc_time_read((struct rtc_time_t*)&ct)!=0)
	{
		err=true;
	}
#else
	i = 0;
	while(1)
	{
		ret = shm_comm_packet_read(SHM_ADDR_U_TIME, sizeof(SHM_TS_T), (uint8_t *)&shm_ts, sizeof(SHM_TS_T));
		if(ret >= 0)
		{
			break;
		}
		i++;
		if(i > 100)
		{
			err=true;
			break;
		}
		msleep(100);// 延时100ms
	}
	timespec_to_rtc(shm_ts.ts, &ct, 1);
#endif

	if(ct.hour>=24||ct.min>=60||ct.month>12||ct.day>31||ct.day==0||ct.month==0)  // 读取时钟错误
	{
		err=true;
	}
	
 	if(err)
 	{
	 	sys_time_init_zero(&ct);
		rt_err_set(ERR_CODE_RTC,0);
#if 0		
		sys_time_set(&ct);
#endif
		g_rtc_ok = -1;
		
		return;
	}
	sys_time_set_kernal(&ct);
}

#else

void sys_time_init(void)
{
	struct rtc_time_t ct;
	bool err=false;

	// GPS已ok，不检查实时时钟
	if(g_keep_alive_gps)
	{
		return;

	}
	
	if(rtc_time_read((struct rtc_time_t*)&ct)!=0)
	{
		err=true;
	}
	if(ct.hour>=24||ct.min>=60||ct.month>12||ct.day>31||ct.day==0||ct.month==0)  // 读取时钟错误
	{
		err=true;
	}
	
 	if(err)
 	{
		extern struct timespec g_sys_time;
		int ret;
	 	sys_time_init_zero(&ct);		
		rtc_to_timespec(&ct,&g_sys_time);
		ret = rtc_time_write(&ct);
		if(ret == 0)
		{
			rt_err_clr(ERR_CODE_RTC,0);
		}
	}
}
#endif

void sys_time_change(struct rtc_time_t *p_ct)
{
	p_ct->min++;
	if(p_ct->min>=60)
	{
		p_ct->min=0;
		p_ct->hour++;
		if(p_ct->hour>=24)
		{
			bool bdayflag=false;
			p_ct->hour=0;
			p_ct->day++;
			if(p_ct->month==2)  // 2月
			{
				if(p_ct->day>28)
				{
					WORD year=p_ct->year+2000;
					if(year%4==0)  //闰年 2月29天，其他28天
					{
						if(p_ct->day>29)
						{
							bdayflag=true;
						}
					}
					else
					{
						bdayflag=true;
					}
				}
			}
			else
			{
				if(p_ct->day>30)
				{
					if(p_ct->month==2||p_ct->month==4||p_ct->month==6||p_ct->month==9||p_ct->month==11)
					{
						bdayflag=true;					
					}
					if(p_ct->day>31)
					{
						bdayflag=true;					
					}
				}
			}
			if(bdayflag)
			{
				p_ct->day=1;
				p_ct->month++;
				if(p_ct->month>12)
				{
					p_ct->month=1;
					p_ct->year++;
				}
			}
		}
	}
}


#define RTC_WRITE_PERIOD (600UL*USTIMER_SEC)
void clk_app(void)  
{
	static uint32_t us0 = -(RTC_WRITE_PERIOD -20*USTIMER_SEC); // 启动20S后更新一次
	struct timespec ts;
	struct rtc_time_t rtc;
	
	// 旧系统的时间更新策略是有GPS对时，每隔10分钟，更新一次时钟芯片时间
	// 没有外部对时1000秒从时钟芯片更新一次系统时间。这种策略将导致没有外部
	// 对时的时候，系统时间波动较大，导致时间测量不准。
	// 新系统的时间策略是，不管什么情况，每隔10分钟，更新一次时钟芯片时间.
	// 这样系统时间就不会有较大波动。
	
	// 每隔10分钟，更新一次时钟芯片时间
	if(ustimer_delay_origin2(&us0,RTC_WRITE_PERIOD) != 1)
	{
		return;
	}

	gps_get_time(&ts);
	if(timespec_to_rtc(ts,&rtc,1) != 0)
	{
		rt_printf("clk_app:timespec_to_rtc err.\r\n");
		return;
	}
	if(rtc_time_write(&rtc) != 0)
	{
		rt_printf("clk_app:rtc_time_write err.\r\n");
		return;
	}

	rt_err_clr(ERR_CODE_RTC,0);
}
 
