/***********************************************************************************************************
 * Copyright (c)  2021 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : rtc.c
 * Description : rtc driver source file
 * Author(s)   : yanhaihua
 * Version     : V1.0
 * Modify date : 2021-09-23
 ***********************************************************************************************************/
#include "rtc.h"

#ifdef UM2080F32_USING_RTC

#define RTC_IRQ_ENABLE  	1
#define RTC_IRQ_DISABLE  	0

/******************RTC中断使能寄存器位定义******************************/
#define RTC_RTCIE_STPR1IE				(1<<16)	//RTC STAMP1 上升沿事件中断使能
#define RTC_RTCIE_STPF1IE				(1<<15)	//RTC STAMP1 下降沿事件中断使能
#define RTC_RTCIE_STPR0IE				(1<<14)	//RTC STAMP0 上升沿事件中断使能
#define RTC_RTCIE_STPF0IE				(1<<13)	//RTC STAMP0 下降沿事件中断使能
#define RTC_RTCIE_ADJ128_IE				(1<<12)	//128秒中断使能
#define RTC_RTCIE_ALARM_IE				(1<<11)	//闹钟中断使能
#define RTC_RTCIE_1KHZ_IE				(1<<10)	//1khz中断使能
#define RTC_RTCIE_256HZ_IE				(1<<9)	//256hz中断使能
#define RTC_RTCIE_64HZ_IE				(1<<8)	//64hz中断使能
#define RTC_RTCIE_16HZ_IE				(1<<7)	//16hz中断使能
#define RTC_RTCIE_8HZ_IE				(1<<6)	//8hz中断使能
#define RTC_RTCIE_4HZ_IE				(1<<5)	//4hz中断使能
#define RTC_RTCIE_2HZ_IE				(1<<4)	//2hz中断使能
#define RTC_RTCIE_SEC_IE				(1<<3)	//秒中断使能
#define RTC_RTCIE_MIN_IE				(1<<2)	//分中断使能
#define RTC_RTCIE_HOUR_IE				(1<<1)	//小时中断使能
#define RTC_RTCIE_DATE_IE				(1<<0)	//天中断使能

/******************RTC中断标志寄存器位定义****************************/
#define RTC_RTCIF_STPR1IF				(1<<16)	//RTC STAMP1 上升沿事件中断标志
#define RTC_RTCIF_STPF1IF				(1<<15)	//RTC STAMP1 下降沿事件中断标志
#define RTC_RTCIF_STPR0IF				(1<<14)	//RTC STAMP0 上升沿事件中断标志
#define RTC_RTCIF_STPF0IF				(1<<13)	//RTC STAMP0 下降沿事件中断标志
#define RTC_RTCIF_ADJ128_IF				(1<<12)	//128秒中断标志
#define RTC_RTCIF_ALARM_IF				(1<<11)	//闹钟中断标志
#define RTC_RTCIF_1KHZ_IF				(1<<10)	//1khz中断标志
#define RTC_RTCIF_256HZ_IF				(1<<9)	//256hz中断标志
#define RTC_RTCIF_64HZ_IF				(1<<8)	//64hz中断标志
#define RTC_RTCIF_16HZ_IF				(1<<7)	//16hz中断标志
#define RTC_RTCIF_8HZ_IF				(1<<6)	//8hz中断标志
#define RTC_RTCIF_4HZ_IF				(1<<5)	//4hz中断标志
#define RTC_RTCIF_2HZ_IF				(1<<4)	//2hz中断标志
#define RTC_RTCIF_SEC_IF				(1<<3)	//秒中断标志
#define RTC_RTCIF_MIN_IF				(1<<2)	//分中断标志
#define RTC_RTCIF_HOUR_IF				(1<<1)	//小时中断标志
#define RTC_RTCIF_DATE_IF				(1<<0)	//天中断标志


void (*rtc_callback[16])(void) = {0};
/***********************************************************************************************************
 * Function		: rtc_enable
 * Description	: rtc init
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_init(void)
{
	REG_SCU_PERIRESET |= ((uint32_t)0x01<<13);      														/* 释放rtc复位 */
	REG_SCU_PERICLKEN |= ((uint32_t)0x01<<13);       														/* 使能rtc时钟 */
}

/***********************************************************************************************************
 * Function		: rtc_deinit
 * Description	: rtc deinit
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_deinit(void)
{
	REG_SCU_PERICLKEN &= ~((uint32_t)0x01<<13);       														/* 关闭rtc时钟 */ 
	REG_SCU_PERIRESET &= ~((uint32_t)0x01<<13);      														/* rtc复位 */
}

/***********************************************************************************************************
 * Function		: rtc_set_datetime
 * Description	: 设置时间
 * Input		: s_datetime_t datetime:日期时间（10进制）
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_set_datetime(s_datetime_t datetime)   
{
	/* 10进制转换成BCD码 */
	datetime.year = datetime.year/10*16 + datetime.year%10;
	datetime.month = datetime.month/10*16 + datetime.month%10;
	datetime.day = datetime.day/10*16 + datetime.day%10;
	datetime.week = datetime.week/10*16 + datetime.week%10;
	datetime.hour = datetime.hour/10*16 + datetime.hour%10;
	datetime.min = datetime.min/10*16 + datetime.min%10;
	datetime.sec = datetime.sec/10*16 + datetime.sec%10;
	
	REG_RTC_RTCWE = 0xACACACAC;  
	REG_RTC_BCDYEAR = datetime.year;
	REG_RTC_BCDMONTH = datetime.month;
	REG_RTC_BCDDATE = datetime.day;
	REG_RTC_BCDWEEK = datetime.week;
	REG_RTC_BCDHOUR = datetime.hour;
	REG_RTC_BCDMIN = datetime.min;
	REG_RTC_BCDSEC = datetime.sec;
	REG_RTC_RTCWE = 0xFFFFFFFF;
}

/***********************************************************************************************************
 * Function		: rtc_get_datetime
 * Description	: 获取时间
 * Input		: none
 * Output		: none
 * Return		: s_datetime_t datetime:日期时间（10进制）
 ***********************************************************************************************************/
s_datetime_t rtc_get_datetime(void)   
{
	s_datetime_t datetime;
	datetime.year = REG_RTC_BCDYEAR;
	datetime.month = REG_RTC_BCDMONTH;
	datetime.day = REG_RTC_BCDDATE;
	datetime.week = REG_RTC_BCDWEEK;
	datetime.hour = REG_RTC_BCDHOUR;
	datetime.min = REG_RTC_BCDMIN;
	datetime.sec = REG_RTC_BCDSEC;

	/* BCD码转换成10进制 */
	datetime.year = datetime.year/16*10 + datetime.year%16;
	datetime.month = datetime.month/16*10 + datetime.month%16;
	datetime.day = datetime.day/16*10 + datetime.day%16;
	datetime.week = datetime.week/16*10 + datetime.week%16;
	datetime.hour = datetime.hour/16*10 + datetime.hour%16;
	datetime.min = datetime.min/16*10 + datetime.min%16;
	datetime.sec = datetime.sec/16*10 + datetime.sec%16;
	
	return datetime;
}

/***********************************************************************************************************
 * Function		: rtc_set_alarm
 * Description	: rtc set alarm
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_set_alarm(uint8_t hour, uint8_t min, uint8_t sec)
{
	/* 10进制转换成BCD码 */
	hour = hour/10*16 + hour%10;
	min = min/10*16 + min%10;
	sec = sec/10*16 + sec%10;
	
	REG_RTC_ALARM = 0x00000000;
	REG_RTC_ALARM |= ((uint32_t)hour<<16);
	REG_RTC_ALARM |= ((uint32_t)min<<8);
	REG_RTC_ALARM |= ((uint32_t)sec<<0);
}

/***********************************************************************************************************
 * Function		: rtc_ltbc_init
 * Description	: RTC_LTBC数字校准
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_ltbc_init(void) 
{
	REG_RTC_ADJUST = 0x08D;																					/* 最大值0x7ff */          				
	REG_RTC_ADSIGN = 0x00;																					/* 正向调整 */          					
	REG_RTC_PRISEN = 0x00;																					/* 虚拟调校 */
}

/***********************************************************************************************************
 * Function		: rtc_stamp0_enable
 * Description	: 使能触发时间戳
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_stamp0_enable(void) 
{
	REG_RTC_STAMPEN |= (1<<0);   
}

/***********************************************************************************************************
 * Function		: rtc_get_stamp0_rising_edge
 * Description	: 获取上升沿触发的时间戳
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
s_datetime_t rtc_get_stamp0_rising_edge(void)
{
	s_datetime_t datetime;
	datetime.year = (REG_RTC_CALSTAMP0R>>24 ) & 0xFF;
	datetime.month = (REG_RTC_CALSTAMP0R>>16) & 0x3F;
	datetime.day = (REG_RTC_CALSTAMP0R>>0) & 0x3F;
	datetime.week = (REG_RTC_CALSTAMP0R>>8)&0x07;
	
	datetime.hour = (REG_RTC_CLKSTAMP0R>>16) & 0x7F;
	datetime.min = (REG_RTC_CLKSTAMP0R>>8) & 0x7F;
	datetime.sec = (REG_RTC_CLKSTAMP0R>>0) & 0x7F;

	/* BCD码转换成10进制 */
	datetime.year = datetime.year/16*10 + datetime.year%16;
	datetime.month = datetime.month/16*10 + datetime.month%16;
	datetime.day = datetime.day/16*10 + datetime.day%16;
	datetime.week = datetime.week/16*10 + datetime.week%16;
	datetime.hour = datetime.hour/16*10 + datetime.hour%16;
	datetime.min = datetime.min/16*10 + datetime.min%16;
	datetime.sec = datetime.sec/16*10 + datetime.sec%16;
	
	return datetime;
}

/***********************************************************************************************************
 * Function		: rtc_stamp0_enable
 * Description	: 获取下降沿触发的时间戳
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
s_datetime_t rtc_get_stamp0_falling_edge(void)
{
	s_datetime_t datetime;
	datetime.year = (REG_RTC_CALSTAMP0F>>24 ) & 0xFF;
	datetime.month = (REG_RTC_CALSTAMP0F>>16) & 0x3F;
	datetime.day = (REG_RTC_CALSTAMP0F>>0) & 0x3F;
	datetime.week = (REG_RTC_CALSTAMP0F>>8)&0x07;
	
	datetime.hour = (REG_RTC_CLKSTAMP0F>>16) & 0x7F;
	datetime.min = (REG_RTC_CLKSTAMP0F>>8) & 0x7F;
	datetime.sec = (REG_RTC_CLKSTAMP0F>>0) & 0x7F;

	/* BCD码转换成10进制 */
	datetime.year = datetime.year/16*10 + datetime.year%16;
	datetime.month = datetime.month/16*10 + datetime.month%16;
	datetime.day = datetime.day/16*10 + datetime.day%16;
	datetime.week = datetime.week/16*10 + datetime.week%16;
	datetime.hour = datetime.hour/16*10 + datetime.hour%16;
	datetime.min = datetime.min/16*10 + datetime.min%16;
	datetime.sec = datetime.sec/16*10 + datetime.sec%16;
	
	return datetime;
}

/***********************************************************************************************************
 * Function		: rtc_stamp1_enable
 * Description	: 使能触发时间戳1
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_stamp1_enable(void) 
{
	REG_RTC_STAMPEN |= (1<<1);
}

/***********************************************************************************************************
 * Function		: rtc_get_stamp1_rising_edge
 * Description	: 获取上升沿触发的时间戳
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
s_datetime_t rtc_get_stamp1_rising_edge(void)
{
	s_datetime_t datetime;
	datetime.year = (REG_RTC_CALSTAMP0R>>24 ) & 0xFF;
	datetime.month = (REG_RTC_CALSTAMP0R>>16) & 0x3F;
	datetime.day = (REG_RTC_CALSTAMP0R>>0) & 0x3F;
	datetime.week = (REG_RTC_CALSTAMP0R>>8)&0x07;
	
	datetime.hour = (REG_RTC_CLKSTAMP0R>>16) & 0x7F;
	datetime.min = (REG_RTC_CLKSTAMP0R>>8) & 0x7F;
	datetime.sec = (REG_RTC_CLKSTAMP0R>>0) & 0x7F;

	/* BCD码转换成10进制 */
	datetime.year = datetime.year/16*10 + datetime.year%16;
	datetime.month = datetime.month/16*10 + datetime.month%16;
	datetime.day = datetime.day/16*10 + datetime.day%16;
	datetime.week = datetime.week/16*10 + datetime.week%16;
	datetime.hour = datetime.hour/16*10 + datetime.hour%16;
	datetime.min = datetime.min/16*10 + datetime.min%16;
	datetime.sec = datetime.sec/16*10 + datetime.sec%16;
	
	return datetime;
}

/***********************************************************************************************************
 * Function		: rtc_stamp1_enable
 * Description	: 获取下降沿触发的时间戳
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
s_datetime_t rtc_get_stamp1_falling_edge(void)
{
	s_datetime_t datetime;
	datetime.year = (REG_RTC_CALSTAMP0F>>24 ) & 0xFF;
	datetime.month = (REG_RTC_CALSTAMP0F>>16) & 0x3F;
	datetime.day = (REG_RTC_CALSTAMP0F>>0) & 0x3F;
	datetime.week = (REG_RTC_CALSTAMP0F>>8)&0x07;
	
	datetime.hour = (REG_RTC_CLKSTAMP0F>>16) & 0x7F;
	datetime.min = (REG_RTC_CLKSTAMP0F>>8) & 0x7F;
	datetime.sec = (REG_RTC_CLKSTAMP0F>>0) & 0x7F;

	/* BCD码转换成10进制 */
	datetime.year = datetime.year/16*10 + datetime.year%16;
	datetime.month = datetime.month/16*10 + datetime.month%16;
	datetime.day = datetime.day/16*10 + datetime.day%16;
	datetime.week = datetime.week/16*10 + datetime.week%16;
	datetime.hour = datetime.hour/16*10 + datetime.hour%16;
	datetime.min = datetime.min/16*10 + datetime.min%16;
	datetime.sec = datetime.sec/16*10 + datetime.sec%16;
	
	return datetime;
}

/***********************************************************************************************************
 * Function		: rtc_irq_init
 * Description	: rtc deinit
 * Input		: em_rtc_irq_t irq_type : 中断类型
 *              : em_enable_t irq_enable ：中断使能
 *              : void (*pfunc)() ： 中断处理函数
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void rtc_irq_init(em_rtc_irq_t irq_type,em_enable_t irq_enable, void (*pfunc)())
{
	if(irq_enable == RTC_IRQ_ENABLE)
	{
		REG_RTC_RTCIE |= (1<<irq_type);																		/* 使能秒中断 */
		
		NVIC_ClearPendingIRQ(RTC_IRQn);
		NVIC_EnableIRQ(RTC_IRQn);
		
		rtc_callback[irq_type] = pfunc;
	}
	else
	{
		REG_RTC_RTCIE &= ~(1<<irq_type);																	/* 关闭秒中断 */
		rtc_callback[irq_type] = NULL;
	}
	
}

/***********************************************************************************************************
 * Function		: RTC_IRQHandler
 * Description	: RTC_IRQHandler
 * Input		: none
 * Output		: none
 * Return		: none
 ***********************************************************************************************************/
void RTC_IRQHandler(void)
{
	for(uint8_t i=0;i<17;i++)
	{
		if((REG_RTC_RTCIF & (1<<i)) != 0x00)
		{
			if(rtc_callback[i] != NULL)
			{
				((void(*)())(rtc_callback[i]))();
			}
			REG_RTC_RTCIF = (1<<i);
		}
	}
}

#endif
