#include "drv_rtc.h"
#include "drv_clk.h"

#include "bsp_task.h"

#include "kit_time.h"
#include "kit_data.h"
#include "kit_debug.h"

#define LSE_NOT_READY			0
#define RCC_BDCR_RTCEN_POS		KIT_BIT_MASK_32(15)
#define RCC_BDCR_LSEDY_POS		((uint32_t)0x00000002)
#define RCC_BDCR_LSEON_POS		KIT_BIT_MASK_32(0)


#define RCC_RTCCLKSource_LSE    KIT_BIT_MASK_32(8)
#define RTC_FLAG_RTOFF       ((uint16_t)0x0020)  /*!< RTC Operation OFF flag */
/******************************************************************************************
1.写RTC寄存器前必须使能PWR_CR中的DBP,且必须等待操作完成才能清0 DBP
2.stm32f10x RTC 进行写操作前必须判断上一次操作是否完成(RTOFF)
3.写RTC_CNT、RTC_ALR或RTC_PRL寄存器时必须先置位CNF,写完后必须清0才会执行写操作
4.读RTC_CNT、RTC_ALR或RTC_PRL寄存器时前必须清0RSF,等其被硬件置位时表示同步完成,可以读取
5.低速时钟起振时间1-5s
******************************************************************************************/

#define RTC_INIT_MASK           ((uint32_t)0xFFFFFFFF) 
bool drv_rtc_enable_init_mode(void)
{
	uint32_t dly = 0;
	
//	//对RTC寄存器操作前先要使能备份区
//	PWR->CR |= PWR_CR_DBP;
	//关闭RTC寄存器写保护
	RTC->WPR = 0xCA;
	RTC->WPR = 0x53;
	//进入RTC初始化模式
	if((RTC->ISR &= RTC_ISR_INITF) == 0)
	{
        RTC->ISR = RTC_INIT_MASK;
        //等待进入RTC初始化模式成功
		while(((RTC->ISR & RTC_ISR_INITF)==0x00) && (dly++ < 100))
		{
			bsp_task_delay_ms(1);
		}
	}
	return (dly < 100);
}

void drv_rtc_disable_init_mode(void)
{
	RTC->ISR &= ~RTC_ISR_INIT; //退出RTC初始化模式
	RTC->WPR = 0xFF;			//使能RTC寄存器写保护 
}


//由于低速时钟起振较慢,其他任务初始化后再初始化RTC
bool drv_rtc_init(void)
{
    bool res = false;
	uint32_t dly = 0;
	//if((RCC->BDCR & RCC_BDCR_RTCEN_POS) != RCC_BDCR_RTCEN_POS)
	{
        KIT_DEBUG_PRINTF("rtc init\r\n");
		RCC->APB1ENR |= RCC_APB1Periph_PWR;
        //使能允许写入RTC和后备寄存器
		PWR->CR |= PWR_CR_DBP;	
		//开启LSE
		RCC->BDCR |= RCC_BDCR_LSEON_POS;
		while ((RCC->BDCR & RCC_BDCR_LSEDY_POS) == LSE_NOT_READY)
		{
			bsp_task_delay_ms(10);
			if(dly++ > 500)
            {
                KIT_DEBUG_PRINTF("rtc fail \r\n");
                return res;
            }
		}
        KIT_DEBUG_PRINTF("rtc dly %d\r\n", dly);
		RCC->BDCR |= (RCC_RTCCLKSource_LSE | RCC_BDCR_RTCEN_POS);
		//RTC配置使用默认配置
		//设置同步分频系数和异步分频系数,默认为1Hz = 32768/(同步分频 + 1)/(异步分频 + 1)
        res = drv_rtc_enable_init_mode();
        if(res == true)
        {
            RTC->PRER = 0x001F03FF;
        }
        drv_rtc_disable_init_mode();
        
		//PWR->CR &= ~PWR_CR_DBP_POS;
	}
	return res;
}

//ampm:AM/PM,0=AM/24H,1=PM.
bool drv_rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec)
{
	bool res;
	//关闭RTC寄存器写保护
	res = drv_rtc_enable_init_mode();
	if(res == true)
	{
		RTC->TR = ((uint32_t)kit_dec_to_bcd(hour) << 16) | ((uint32_t)kit_dec_to_bcd(min) << 8) | (kit_dec_to_bcd(sec));
	}
	drv_rtc_disable_init_mode();
	return res; 
}

//year 20xx, month 1-12, day 1-31
bool drv_rtc_set_date(uint16_t year, uint8_t month, uint8_t day)
{
	bool res;
	//关闭RTC寄存器写保护
	res = drv_rtc_enable_init_mode();
	if((res == true) && (year >= 2000))
	{        
		RTC->DR = ((uint32_t)kit_dec_to_bcd(year - 2000) << 16) | ((uint32_t)kit_dec_to_bcd(month) << 8) | (kit_dec_to_bcd(day)); 
	}
	drv_rtc_disable_init_mode();
	return res; 
}

bool drv_rtc_wait_sync(void)
{ 
	bool res = true;
	uint32_t retry=0xFFFFF; 
	//关闭RTC寄存器写保护
	RTC->WPR = 0xCA;
	RTC->WPR = 0x53; 
	RTC->ISR &= ~(1<<5);		//清除RSF位 
	while(retry&&((RTC->ISR&(1<<5)) == 0x00))//等待影子寄存器同步
	{
		retry--;
	}
    if(retry == 0)
	{
		res = false;
	}
	RTC->WPR = 0xFF;			//使能RTC寄存器写保护  
	
	return res;
}

bool drv_rtc_get_time(int32_t *hour, int32_t *min, int32_t *sec)
{
	uint32_t temp = 0;
 	if(drv_rtc_wait_sync() == true)
	{
		temp = RTC->TR;
		*hour = kit_dcb_to_dec((temp >> 16) & 0x3F);
		*min = kit_dcb_to_dec((temp >> 8) & 0x7F);
		*sec = kit_dcb_to_dec(temp & 0x7F);
		return true;
	}
	else
	{
		*hour = *min = *sec = 0;
		return false;
	}
}

//year 20xx, month 1-12, day 1-31
bool drv_rtc_get_date(int32_t *year, int32_t *month, int32_t *day)
{
	uint32_t temp = 0;
 	if(drv_rtc_wait_sync() == true)
	{
		temp = RTC->DR;
		*year = kit_dcb_to_dec((temp >> 16) & 0xFF) + 2000;
		*month = kit_dcb_to_dec((temp >> 8) & 0x1F);
		*day = kit_dcb_to_dec(temp & 0x3F);
		return true;
	}
	else
	{
		*year = 2000;
		*month = *day = 1;
		return false;
	}
}

uint32_t drv_rtc_get_tick(void)
{
    struct tm tmp;
    uint32_t res = 0;
    
    tmp.tm_year = 0;
	if((drv_rtc_get_time(&tmp.tm_hour, &tmp.tm_min, &tmp.tm_sec) == true)
	&& (drv_rtc_get_date(&tmp.tm_year, &tmp.tm_mon, &tmp.tm_mday) == true))
	{
        tmp.tm_mon--;
        tmp.tm_year = (tmp.tm_year > 2018) ? (tmp.tm_year - 1900) : 119;
		res = kit_time_get_stamp(2019, &tmp);
	}
    
    return res;
}

bool drv_rtc_set_tick(uint32_t tick)
{   
    struct tm *tmp;
    bool res = false;
    
    if(drv_rtc_get_tick() != tick)
    {
        tmp = kit_time_get_date(2019, tick);
        //标准库月0-11 ST月为1-12,ST年从2000开始只保留十位和各位
        if((tmp->tm_year >= 119) && (drv_rtc_set_time(tmp->tm_hour, tmp->tm_min, tmp->tm_sec) == true)
        && (drv_rtc_set_date((tmp->tm_year + 1900), tmp->tm_mon + 1, tmp->tm_mday) == true))
        {
            res = true;
        }
    }
    else
    {
        res = true;
    }
    
    return res;
}

uint16_t drv_rtc_get_ms(void)
{
    uint32_t tmp = 0;
    /*Get sub seconds values from the correspondent registers*/
    tmp = (uint32_t)(RTC->SSR);
    /* Read DR register to unfroze calendar registers */
    (void) (RTC->DR);
    tmp = (0x03FF - tmp) * 1000 / (0x03FF + 1);
    
    return tmp;
}

bool drv_rtc_set_ms(uint16_t ms)
{
    bool res = false;
    uint32_t cur_ms, cnt = 0;
    /* Disable the write protection for RTC registers */
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;

    cur_ms = drv_rtc_get_ms();
    if(ms != cur_ms)
    {
        RTC->WPR = 0xCA;
        RTC->WPR = 0x53;
        /* Check if a Shift is pending*/
        while (((RTC->ISR & RTC_ISR_SHPF) != RESET) && (cnt++ < 1000));
        /* Check if the Shift pending is completed or if there is no Shift operation at all*/
        if ((RTC->ISR & RTC_ISR_SHPF) == RESET)
        {
            /* check if the reference clock detection is disabled */
            if((RTC->CR & RTC_CR_REFCKON) == RESET)
            {
                if(cur_ms > ms)
                {
                    cur_ms = (cur_ms - ms) * (0x3FF + 1) / 1000;
                }
                else
                {
                    cur_ms = (1000 - ms + cur_ms) * (0x3FF + 1) / 1000;
                }
                RTC->SHIFTR = cur_ms;
                res = drv_rtc_wait_sync();
            }
        }
        /* Enable the write protection for RTC registers */
        RTC->WPR = 0xFF;
    }
    return res;
}