/*
 * drv_clock.c
 *
 *  Created on: 24 февр. 2025 г.
 *      Author: basov.g
 */

#include "drv_clock.h"
#include "MDR32VF0xI_port.h"
#include "MDR32VF0xI_rst_clk.h"
#include "MDR32VF0xI_bkp.h"
#include "MDR32VF0xI_timer.h"
#include "stdbool.h"
#include "drv_button.h"
#include "../utils/utils.h"
//#define CLOCKUPDATE
#define RTCCLK1HZ_PORT  MDR_PORTD
#define RTCCLK1HZ_PIN   PORT_PIN_15
#define RTCTIMERIN_PORT MDR_PORTB
#define RTCTIMERIN_PIN  PORT_PIN_8
#define RTCOUT_PORT 	MDR_PORTB
#define RTCOUT_PIN  	PORT_PIN_3
#define RTCINTIMER		MDR_TIMER3
BKP_RTC_DateTime_TypeDef dateTime = {0};
#define COUNTTAMPERS 3
typedef struct
{
	uint32_t statusTamper[COUNTTAMPERS];
	uint32_t time[COUNTTAMPERS];
	uint32_t date[COUNTTAMPERS];
}TamperValuesInEnergyMem;
BKP_RTC_DateTime_TypeDef tamperDateTime[COUNTTAMPERS]={0};
#define TAMPERSAVEDATA_BASE                    0x50061000U
#define TAMPERSAVEDATA	((TamperValuesInEnergyMem *) TAMPERSAVEDATA_BASE)

void __attribute__ ((interrupt)) BKP_IRQHandler( void )
{

	for(int i = 0; i < COUNTTAMPERS; i++)
	{
		if(MDR_BKP->RTC_TAFCR&(BKP_RTC_TAFCR_TAMP_IN_SEL1<<i))
		{
			MDR_BKP->WPR = BKP_WPR_BKP_WPR_UNLOCK; // fast version of BKP_DisableWP();
			TAMPERSAVEDATA->statusTamper[i] = true;
			TAMPERSAVEDATA->time[i] = *((uint32_t*)(&MDR_BKP->RTC_TSTR1 + i));
			TAMPERSAVEDATA->date[i] = *((uint32_t*)(&MDR_BKP->RTC_TSDR1 + i));
			MDR_BKP->WPR = 0;           // fast version of BKP_EnableWP();
		}
	}

	MDR_BKP->WPR = BKP_WPR_BKP_WPR_UNLOCK; // fast version of BKP_DisableWP();
	MDR_BKP->RTC_TAFCR |= 0;        // fast version of BKP_SetTamperNewState(ENABLE);
	MDR_BKP->WPR = 0;           // fast version of BKP_EnableWP();
}

void drv_clock_initGPIO(void)
{
	RST_CLK_PCLKCmd(RST_CLK_PCLK_PORTD | RST_CLK_PCLK_PORTB, ENABLE);

	PORT_InitTypeDef PORT_InitStructure;
	PORT_InitStructure.PORT_Direction    	= PORT_DIRECTION_OUTPUT;
	PORT_InitStructure.PORT_Mode  			= PORT_MODE_DIGITAL;
	PORT_InitStructure.PORT_Power 			= PORT_POWER_NOMINAL_UPTO_2mA;
	PORT_InitStructure.PORT_PullDown  		= PORT_PULL_DOWN_OFF;
	PORT_InitStructure.PORT_PullUp  		= PORT_PULL_UP_OFF;

	PORT_InitStructure.PORT_Function  		= PORT_FUNCTION_ALTERNATIVE;
	PORT_InitStructure.PORT_Pin =  RTCCLK1HZ_PIN;
	PORT_Init(RTCCLK1HZ_PORT, &PORT_InitStructure);

	PORT_InitStructure.PORT_Function  		= PORT_FUNCTION_OVERRIDDEN;
	PORT_InitStructure.PORT_Pin =  RTCOUT_PIN;
	PORT_Init(RTCTIMERIN_PORT, &PORT_InitStructure);

	PORT_InitStructure.PORT_Direction  		= PORT_DIRECTION_INPUT;
	PORT_InitStructure.PORT_Pin =  RTCTIMERIN_PIN;
	PORT_Init(RTCTIMERIN_PORT, &PORT_InitStructure);
}

void drv_clock_initTimer(void)
{

	RST_CLK_PCLKCmd(RST_CLK_PCLK_TIMER3, ENABLE);
	TIMER_CNT_InitTypeDef timerCntInitTypeDef= {0};
	TIMER_CNT_StructInit(&timerCntInitTypeDef);

	timerCntInitTypeDef.TIMER_CNT_Counter		= 0;
	timerCntInitTypeDef.TIMER_CNT_Prescaler  	= 0;
	timerCntInitTypeDef.TIMER_CNT_Period     	= 1;
	timerCntInitTypeDef.TIMER_CNT_EventSource   = TIMER_CNT_EVNT_SRC_ETR_RE;
	timerCntInitTypeDef.TIMER_CNT_Mode		   	= TIMER_CNT_MODE_CLK_FIXED_DIR;
	timerCntInitTypeDef.TIMER_CNT_Direction   	= TIMER_CNT_DIR_UP;
	timerCntInitTypeDef.TIMER_FDTS_Prescaler 	= TIMER_FDTS_PRESCALER_DIV_1;
	timerCntInitTypeDef.TIMER_ETR_Filter 	= TIMER_ETR_FILTER_1FF_AT_FDTS;
	timerCntInitTypeDef.TIMER_ETR_Prescaler  	= TIMER_ETR_PRESCALER_DIV_1;
	timerCntInitTypeDef.TIMER_ETR_Polarity  	= TIMER_ETR_POLARITY_NON_INV;
	timerCntInitTypeDef.TIMER_BRK_Polarity  	= TIMER_BRK_POLARITY_NON_INV;
	TIMER_CNT_Init(RTCINTIMER,&timerCntInitTypeDef);


	RTCINTIMER->CH2_CNTRL0 = 0x200;
	RTCINTIMER->CH2_CNTRL1 = 0x0909;
	RTCINTIMER->CH2_CCR = 0x00000001;

	TIMER_CNT_Cmd(RTCINTIMER,ENABLE);
}

void drv_clock_initBKP(void)
{
	BKP_SetRegistersLock(RESET);

	BKP_LSE_Config(BKP_LSE_ON);
	BKP_LSE_Cmd(ENABLE);


	BKP_JTAG_Cmd(ENABLE);
	BKP_SW_Cmd(ENABLE);

	BKP_LDO_SetBoostTrim(0x0);
	/* RTC control */

	BKP_RTC_Cmd(DISABLE);
	BKP_RTC_Reset(DISABLE);
	BKP_RTC_SetClkSource(BKP_RTC_CLK_SRC_LSE);
	BKP_RTC_SetPrescaler(32768);
	BKP_RTC_SetPrescalerCounter(1);
	BKP_RTC_SetClkCalibration(1);
	/* wake up configuration */
	BKP_RTC_WUT_SetClkSource(BKP_RTC_WUT_CLK_SRC_SEC_CLK);
	BKP_RTC_WUT_SetCounter(0);
	BKP_RTC_WUT_SetAlarm(3600);
	BKP_RTC_WUT_SetSWControl(BKP_RTC_WUT_SW_CONTROL_SW_PWR_HIGH);
#ifdef CLOCKUPDATE

	drv_clock_setDate(3,3,2025);
	drv_clock_setTime(15,54,0);
	drv_clock_update();

#endif

	BKP_RTC_Cmd(ENABLE);

	MDR_BKP->RTC_TMPCAL3 |= (1<<4); //TEMP EN
	BKP_SetRegistersLock(SET);
}

void drv_clock_initTumper(void)
{
	RST_CLK_PCLKCmd(RST_CLK_PCLK_BKP, ENABLE);
	BKP_SetRegistersLock(RESET);
    for(int i = 0; i < COUNTTAMPERS; i++)
    {
    	if(MDR_BKP->RTC_TAFCR&(BKP_RTC_TAFCR_TS_EDGE1<<i))
    	{
    		MDR_BKP->WPR = BKP_WPR_BKP_WPR_UNLOCK; // fast version of BKP_DisableWP();
    		TAMPERSAVEDATA->statusTamper[i] = true;
    		TAMPERSAVEDATA->time[i] = *((uint32_t*)&MDR_BKP->RTC_TSTR1 + i);
    		TAMPERSAVEDATA->date[i] = *((uint32_t*)&MDR_BKP->RTC_TSDR1 + i);
    		MDR_BKP->WPR = BKP_WPR_BKP_WPR_LOCK;           // fast version of BKP_EnableWP();
    	}
    }

    BKP_RTC_TAMPER_Cmd(BKP_RTC_TAMPER_ALL, ENABLE);
	BKP_RTC_TAMPER_SetEvent(BKP_RTC_TAMPER_W1 | BKP_RTC_TAMPER_W2 | BKP_RTC_TAMPER_W3,BKP_RTC_TAMPER_EVNT_EDGE_RISING);
	BKP_SetRegistersLock(SET);
	// SPL don't support EDGE interrupt, so do it manually
	MDR_BKP->WPR = BKP_WPR_BKP_WPR_UNLOCK; // fast version of BKP_DisableWP();
	MDR_BKP->RTC_TAFCR|= (uint32_t)((1<<31)|(1<<30)|(1<<29)); // interrupt on EDGE
	MDR_BKP->RTC_TAFCR |= (uint32_t)((1<<25)|(1<<24)|(1<<23)); // interrupt on EDGE

	MDR_BKP->RTC_TAFCR |= 1<<5;//save time by wakeup;
	MDR_BKP->RTC_TAFCR |= 1<<22;//wakeup sw;
	MDR_BKP->WPR = BKP_WPR_BKP_WPR_LOCK;           // fast version of BKP_EnableWP();

	CLIC_SetPriorityIRQ(BKP_IRQn,0);
	CLIC_EnableIRQ(BKP_IRQn);
}

void drv_clock_clearTumpers(void)
{
	MDR_BKP->WPR = BKP_WPR_BKP_WPR_UNLOCK; // fast version of BKP_DisableWP();
	for(int i = 0; i < COUNTTAMPERS; i++)
	{
		TAMPERSAVEDATA->statusTamper[i] = false;
		TAMPERSAVEDATA->time[i] = 0;
		TAMPERSAVEDATA->date[i] = 0;
	}
	MDR_BKP->WPR = BKP_WPR_BKP_WPR_LOCK;           // fast version of BKP_EnableWP();
}

void drv_clock_init(void)
{
	drv_clock_initTumper();
	drv_clock_initGPIO();
	drv_clock_initTimer();
	drv_clock_initBKP();

    drv_Button_SetEvent(ButtonFirst,ButtonLongPress,drv_clock_clearTumpers);
}


void MY_RTC_GetDateTimeReg(uint32_t DateRegVal, uint32_t TimeRegVal, BKP_RTC_DateTime_TypeDef* RTC_DateTime)
{
    RTC_DateTime->RTC_Year    = (uint8_t)((DateRegVal & (BKP_RTC_DR_YU_Msk | BKP_RTC_DR_YT_Msk)) >> BKP_RTC_DR_YU_Pos);
    RTC_DateTime->RTC_Month   = (uint8_t)((DateRegVal & (BKP_RTC_DR_MU_Msk | BKP_RTC_DR_MT_Msk)) >> BKP_RTC_DR_MU_Pos);
    RTC_DateTime->RTC_Day     = (uint8_t)((DateRegVal & (BKP_RTC_DR_DU_Msk | BKP_RTC_DR_DT_Msk)) >> BKP_RTC_DR_DU_Pos);
    RTC_DateTime->RTC_WeekDay = (BKP_RTC_WeekDays_TypeDef)((DateRegVal & BKP_RTC_DR_WDU_Msk) >> BKP_RTC_DR_WDU_Pos);

    RTC_DateTime->RTC_TimeFormat = (BKP_RTC_FMT_TypeDef)((TimeRegVal & BKP_RTC_TR_PM) >> BKP_RTC_TR_PM_Pos);
    RTC_DateTime->RTC_Hours      = (uint8_t)((TimeRegVal & (BKP_RTC_TR_HU_Msk | BKP_RTC_TR_HT_Msk)) >> BKP_RTC_TR_HU_Pos);
    RTC_DateTime->RTC_Minutes    = (uint8_t)((TimeRegVal & (BKP_RTC_TR_MNU_Msk | BKP_RTC_TR_MNT_Msk)) >> BKP_RTC_TR_MNU_Pos);
    RTC_DateTime->RTC_Seconds    = (uint8_t)((TimeRegVal & (BKP_RTC_TR_SU_Msk | BKP_RTC_TR_ST_Msk)) >> BKP_RTC_TR_SU_Pos);
}

void drv_clock_update(void)
{
	static uint64_t timeLastTimeUpdate = 0;
	if(getMillis() - timeLastTimeUpdate<100) return;
	timeLastTimeUpdate=getMillis();

	BKP_RTC_GetDateTimeBCD(&dateTime);
	BKP_RTC_ConvertToBINFormat(&dateTime);
	for(int i = 0; i < COUNTTAMPERS; i++)
	{
		MY_RTC_GetDateTimeReg(TAMPERSAVEDATA->date[i],TAMPERSAVEDATA->time[i], &tamperDateTime[i]);
		BKP_RTC_ConvertToBINFormat(&tamperDateTime[i]);
	}
}


void drv_clock_setDate(int day, int month,int year)
{
	BKP_RTC_DateTime_TypeDef currentTime;
	BKP_RTC_GetDateTimeBCD(&currentTime);
	BKP_RTC_ConvertToBINFormat(&currentTime);
	if(year >= 2000) year -= 2000;
	currentTime.RTC_Year = (uint8_t)year;
	currentTime.RTC_Month = (uint8_t)month;
	currentTime.RTC_Day = (uint8_t)day;
	BKP_RTC_ConvertToBCDFormat(&currentTime);

	BKP_SetRegistersLock(RESET);
	BKP_RTC_Cmd(DISABLE);
	BKP_RTC_SetDateTimeBCD(&currentTime,1,0);
	BKP_RTC_Cmd(ENABLE);
	BKP_SetRegistersLock(SET);
}

void drv_clock_setTime(int hours, int minutes, int seconds)
{
	BKP_RTC_DateTime_TypeDef currentTime;
	BKP_RTC_GetDateTimeBCD(&currentTime);
	BKP_RTC_ConvertToBINFormat(&currentTime);
	currentTime.RTC_Hours = (uint8_t)hours;
	currentTime.RTC_Minutes = (uint8_t)minutes;
	currentTime.RTC_Seconds = (uint8_t)seconds;
	BKP_RTC_ConvertToBCDFormat(&currentTime);


	BKP_SetRegistersLock(RESET);
	BKP_RTC_Cmd(DISABLE);
	BKP_RTC_SetDateTimeBCD(&currentTime,0,1);
	BKP_RTC_Cmd(ENABLE);
	BKP_SetRegistersLock(SET);
}

void drv_clock_setCalibration(void)
{

}


int drv_clock_getSeconds(void)
{
	return dateTime.RTC_Seconds;
}

int drv_clock_getMinutes(void)
{
	return dateTime.RTC_Minutes;
}

int drv_clock_getHour(void)
{
	return dateTime.RTC_Hours;
}

int drv_clock_getDay(void)
{
	return dateTime.RTC_Day;
}

int drv_clock_getMonth(void)
{
	return dateTime.RTC_Month;
}

int drv_clock_getYear(void)
{
	return dateTime.RTC_Year +2000;
}


bool drv_getStatusTampers(void)
{
	for(uint8_t i = 0; i < COUNTTAMPERS; i++)
		if(drv_getStatusTamperNumber(i)) return false;
	return true;
}
bool drv_getStatusTamperNumber(uint8_t number)
{
	return TAMPERSAVEDATA->statusTamper[number];
}
int drv_clock_getTamperSeconds(uint8_t number)
{
	return (tamperDateTime[number].RTC_Seconds);
}
int drv_clock_getTamperMinutes(uint8_t number)
{
	return (tamperDateTime[number].RTC_Minutes);
}
int drv_clock_getTamperHour(uint8_t number)
{
	return (tamperDateTime[number].RTC_Hours);
}
int drv_clock_getTamperDay(uint8_t number)
{
	return (tamperDateTime[number].RTC_Day);
}
int drv_clock_getTamperMonth(uint8_t number)
{
	return (tamperDateTime[number].RTC_Month);
}
int drv_clock_getTamperYear(uint8_t number)
{
	return (tamperDateTime[number].RTC_Year)+2000;
}
uint8_t drv_clock_getCalibValue(void)
{
	return MDR_BKP->RTC_CR>>3 & 0xFF;
}
uint8_t drv_clock_getTempRes(void)
{
	return (MDR_BKP->RTC_TMPCAL3>>24) &0x0F;
}
uint8_t drv_clock_getTempConst(uint8_t number)
{
	switch(number)
	{
	case 0:	case 1:	case 2:	case 3:	case 4:	case 5:
		return (MDR_BKP->RTC_TMPCAL1>>(number*5)) & 0x1F;
	case 6:
		return (MDR_BKP->RTC_TMPCAL2 << 2  | MDR_BKP->RTC_TMPCAL1 >> 30) & 0x1F;
	case 7:	case 8:	case 9:	case 10: case 11:
		return (MDR_BKP->RTC_TMPCAL2 >> ((number-7)*5+3)) & 0x1F;
	case 12:
		return (MDR_BKP->RTC_TMPCAL3 >> 4 | MDR_BKP->RTC_TMPCAL2 >> 28) & 0x1F;
	case 13: case 14: case 15:
		return (MDR_BKP->RTC_TMPCAL3>>((number-13)*5+9)) & 0x1F;

	}
	return 0;
}
