// ==========================================================================
// rtc.c
// (c) 2020, Aurel Dumitru
//
// Description:
// Real time clock operations
// =========================================================================


#include "rtc.h"
#include "rgbled.h"
#include "utils.h"
#include "config.h"
#include "calibrations.h"

RTC_TimeTypeDef Rtc_Time =
{
		0x00,            /*!< Specifies the RTC Time Hour.
		                                 This parameter must be a number between Min_Data = 0 and Max_Data = 12 if the RTC_HourFormat_12 is selected.
		                                 This parameter must be a number between Min_Data = 0 and Max_Data = 23 if the RTC_HourFormat_24 is selected */

		0x00,           /*!< Specifies the RTC Time Minutes.
		                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

		0x00,          /*!< Specifies the RTC Time Seconds.
		                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

		RTC_HOURFORMAT12_AM,       /*!< Specifies the RTC AM/PM Time.
		                                 This parameter can be a value of @ref RTC_AM_PM_Definitions */

		0,     /*!< Specifies the RTC_SSR RTC Sub Second register content.
		                                 This parameter corresponds to a time unit range between [0-1] Second
		                                 with [1 Sec / SecondFraction +1] granularity */

		0,  /*!< Specifies the range or granularity of Sub Second register content
		                                 corresponding to Synchronous pre-scaler factor value (PREDIV_S)
		                                 This parameter corresponds to a time unit range between [0-1] Second
		                                 with [1 Sec / SecondFraction +1] granularity.
		                                 This field will be used only by HAL_RTC_GetTime function */

		RTC_DAYLIGHTSAVING_NONE,  /*!< Specifies RTC_DayLightSaveOperation: the value of hour adjustment.
		                                 This parameter can be a value of @ref RTC_DayLightSaving_Definitions */

		RTC_STOREOPERATION_RESET,  /*!< Specifies RTC_StoreOperation value to be written in the BKP bit
		                                 in CR register to store the operation.
		                                 This parameter can be a value of @ref RTC_StoreOperation_Definitions */
};

RTC_DateTypeDef Rtc_Date =
{
		RTC_WEEKDAY_SUNDAY,  /*!< Specifies the RTC Date WeekDay.
		                         This parameter can be a value of @ref RTC_WeekDay_Definitions */

		0,    /*!< Specifies the RTC Date Month (in BCD format).
		                         This parameter can be a value of @ref RTC_Month_Date_Definitions */

		0,     /*!< Specifies the RTC Date.
		                         This parameter must be a number between Min_Data = 1 and Max_Data = 31 */

		0,     /*!< Specifies the RTC Date Year.
		                         This parameter must be a number between Min_Data = 0 and Max_Data = 99 */
};


uint8_t Rtc_ConvCharPairToBCD(uint8_t* Text)
{
	return ((Text[0]-'0')<<4) + (Text[1]-'0');
}

uint32_t Rtc_UpdateTimeDate(uint8_t* Text)
{
	RTC_TimeTypeDef sTime;
	RTC_DateTypeDef sDate;

	/* Example: 08/11/28,12:30:33+32 */
	Rtc_Date.Year    = Rtc_ConvCharPairToBCD(&Text[0]);
	Rtc_Date.Month   = Rtc_ConvCharPairToBCD(&Text[3]);
	Rtc_Date.Date    = Rtc_ConvCharPairToBCD(&Text[6]);
	Rtc_Time.Hours   = Rtc_ConvCharPairToBCD(&Text[9]);
	Rtc_Time.Minutes = Rtc_ConvCharPairToBCD(&Text[12]);
	Rtc_Time.Seconds = Rtc_ConvCharPairToBCD(&Text[15]);
	if ((Rtc_Date.Year >= 0x21) && (Rtc_Date.Year <= 0x40))
	{
		HAL_RTC_SetTime(&hrtc, &Rtc_Time, RTC_FORMAT_BCD);
		HAL_RTC_SetDate(&hrtc, &Rtc_Date, RTC_FORMAT_BCD);
		Utils_DelayMicroseconds(1000); // wait RTC shadow to be updated
		// Dummy read time and date
		HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BCD);
		HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BCD);
		return 1;
	}
	return 0;
}


uint32_t Rtc_GetCurrentHour(void)
{
	RTC_TimeTypeDef TmpTimeRtc;
	RTC_DateTypeDef sDate;
	HAL_RTC_GetTime(&hrtc, &TmpTimeRtc, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BCD);
	return TmpTimeRtc.Hours;
}


void Rtc_GetCurrentTime(uint8_t* Hours, uint8_t* Minutes, uint8_t* Seconds)
{
	RTC_TimeTypeDef TmpTimeRtc;
	RTC_DateTypeDef sDate;
	HAL_RTC_GetTime(&hrtc, &TmpTimeRtc, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BCD);
	*Hours   = TmpTimeRtc.Hours;
	*Minutes = TmpTimeRtc.Minutes;
	*Seconds = TmpTimeRtc.Seconds;
}

void Rtc_GetCurrentTimeAndDate(int32_t* Time, int32_t* Year, int32_t* Month, int32_t* Day)
{
	RTC_TimeTypeDef TmpTimeRtc;
	RTC_DateTypeDef sDate;
	HAL_RTC_GetTime(&hrtc, &TmpTimeRtc, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
	*Time   = ((int32_t)TmpTimeRtc.Hours)*3600 + ((int32_t)TmpTimeRtc.Minutes)*60 + TmpTimeRtc.Seconds;
	*Year    = sDate.Year;
	*Month   = sDate.Month;
	*Day	 = sDate.Date;
}


void Rtc_CheckAndUpdateNextWakeUp(void)
{
	RTC_TimeTypeDef TmpTimeRtc;
	RTC_DateTypeDef sDate;

	// read the RTC time register
	HAL_RTC_GetTime(&hrtc, &TmpTimeRtc, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BCD);

	uint32_t Hour = TmpTimeRtc.Hours;
	do
	{
		Hour++;
		if (Hour == 24) Hour = 0;
	} while ((Config_TimeEventsTable[Hour].ModemReq == 0) &&
			 (Config_TimeEventsTable[Hour].PheromoneFlapReq == 0) &&
			 (Config_TimeEventsTable[Hour].SensorsReq == 0) &&
			 (Config_TimeEventsTable[Hour].RgbLedColor > 0xFFFFFF));

	// write next wake up hour in BKP2 register
	__HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);
	HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (Hour/10)*16 + (Hour%10));
	__HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);
}


uint32_t Rtc_GetRtcTimeSetStatus(void)
{
	return READ_REG(RTC->ICSR) & RTC_ICSR_INITS;
};

