/**
  ******************************************************************************
  * @file    hal_rtc.c
  * @brief   RTC module driver.
  *          This file provides firmware functions to manage the following
  *          functionalities of the RTC peripheral:
  *           + Initialization  functions
  *           + Time and date functions
  *           + Alarm functions
  *           + Time stamp functions
  *           + Tamper functions
  *           + Wake-up functions
  *           + Clock output functions
  *           + Peripheral Control functions
  * @version V1.0
  * @date    25 Apr 2017
  * @author  AE Team
  *
  * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
  *
  ********************************************************************************
  * @verbatim
  ==============================================================================
                        ##### How to use this driver #####
  ==============================================================================
    [..]
      (+) Enable the RTC controller interface clock.
      (+) Configure the RTC asynchronous prescaler, synchronous prescaler and hour
          format using the rtc_init() function.

     *** Time and date operation ***
     =================================
     [..]
       (+) To configure the time use the rtc_set_time() function.
       (+) To configure the date use the rtc_set_date() function.
       (+) To read the time use the rtc_get_time() function.
       (+) To read the date use the rtc_get_date() function.

     *** Alarm operation ***
     ===================================
     [..]
       (+) To configure the alarm use rtc_set_alarm() function
       (+) To read the alarm use rtc_get_alarm() function
       (+) To cancel the alarm use rtc_alarm_cmd() function

     *** Time stamp operation ***
     ===================================
     [..]
       (+) To configure the time stamp use rtc_set_time_stamp() function
       (+) To read the time stamp use rtc_get_time_stamp() function
       (+) To cancel the time stamp use rtc_cancel_time_stamp() function

     *** Tamper operation ***
     ===================================
     [..]
       (+) To configure the tamper use rtc_set_tamper() function
       (+) To cancel the tamper use rtc_alarm_cmd() function

     *** Wake-up operation ***
     ===================================
     [..]
       (+) To configure the wake-up parameters use rtc_set_wakeup() function
       (+) To read the re-load register value use rtc_get_wakeup_timer_value() function
       (+) To cancel the wake-up use rtc_cancel_wakeup() function

     *** Output clock operation ***
     ===================================
     [..]
       (+) To configure the clock output type use rtc_set_clock_output() function
       (+) To cancel the clock output use rtc_cancel_clock_output() function

     *** Control functions ***
     ===================================
     [..]
       (+) Configure interrupt enable/disable.
       (+) Enable/disable alarm.
       (+) Configure rtc shift.
       (+) Calibrate time.
       (+) Get interrupt source status.
       (+) Get interrupt flag status.
       (+) Clear interrupt flag.

  ==================================================================
                  ##### RTC and low power modes #####
  ==================================================================
  [..] The MCU can be woken up from a low power mode by an RTC alternate function.
  [..] The RTC alternate functions are the RTC alarms (Alarm A and Alarm B),
       RTC wake-up, RTC tamper event detection and RTC time stamp event detection.
       These RTC alternate functions can wake up the system from the Stop and
       Standby low power modes.
  [..] The system can also wake up from low power modes without depending
       on an external interrupt (Auto-wake-up mode), by using the RTC alarm
       or the RTC wake-up events.
  [..] The RTC provides a programmable time base for waking up from the Stop or
       Standby mode at regular intervals. Wake-up from STOP and STANDBY modes
       is possible only when the RTC clock source is LSE or LSI.

     *** RTC driver macros list ***
     =============================================
     [..]
       Below the list of most used macros in RTC driver.

      (+) RTC_UNLOCK() Disable the protect.
      (+) RTC_LOCK() Enable the protect.
      (+) RTC_BY_PASS_ENABLE() Enable the by-pass shadow register.
      (+) RTC_BY_PASS_DISABLE() Disable the by-pass shadow register.
      (+) RTC_SUMMER_TIME_ENABLE() Enable summer time.
      (+) RTC_SUMMER_TIME_DISABLE() Disable summer time.
      (+) RTC_WINTER_TIME_ENABLE() Enable winter time.
      (+) RTC_WINTER_TIME_DISABLE() Disable winter time.
     [..]
      (@) You can refer to the RTC driver header file for used the macros

    @endverbatim
  ******************************************************************************
  */

#include "hal_rtc.h"


/** @addtogroup ES32FXXX_HAL
  * @{
  */

/** @defgroup RTC RTC
  * @brief RTC module driver
  * @{
  */
#ifdef HAL_RTC

/** @addtogroup RTC_Private_Functions  RTC Private Functions
  * @{
  */
/**
  * @brief  Converts form 2 digit BCD to Binary.
  * @param  bcd: BCD value to be converted.
  * @retval Converted word.
  */
static uint32_t bcd_to_dec(uint32_t bcd)
{
	return ((bcd & 0xF) + ((bcd >> 4) & 0xF) * 10);
}

/**
  * @brief  Converts a 2 digit decimal to BCD format.
  * @param  dec: Byte to be converted.
  * @retval Converted byte.
  */
static uint32_t dec_to_bcd(uint32_t dec)
{
	return (((dec / 10) << 4) | (dec % 10));
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions RTC Public Functions
  * @{
  */

/** @defgroup RTC_Public_Functions_Group1 Initialization functions
  * @brief    Initialization functions
  *
  * @verbatim
 ===============================================================================
              ##### Initialization function #####
 ===============================================================================
   [..] This section provides functions allowing to initialize and configure the
         RTC Prescaler (Synchronous and Asynchronous), RTC Hour format, disable
         RTC registers Write protection.
         (#) The RTC Prescaler is programmed to generate the RTC 1Hz time base.
             It is split into 2 programmable prescalers to minimize power consumption.
             (++) A 7-bit asynchronous prescaler and a 13-bit synchronous prescaler.
             (++) When both prescalers are used, it is recommended to configure the
                 asynchronous prescaler to a high value to minimize power consumption.
         (#) All RTC registers are Write protected. Writing to the RTC registers
             is enabled by writing a key into the Write Protection register.

    @endverbatim
  * @{
  */

/**
  * @brief  Initialize the RTC module.
  * @param  init: Pointer to rtc_init_t structure which contains
  *         the configuration parameters.
  * @retval None
  */
void rtc_init(rtc_init_t *init)
{
	assert_param(IS_RTC_HOUR_FORMAT(init->hour_format));
	assert_param(IS_RTC_OUTPUT_SEL(init->output));
	assert_param(IS_RTC_OUTPUT_POLARITY(init->output_polarity));

	RTC_UNLOCK();

	RTC->CR.HFM   = init->hour_format;
	RTC->CR.OSEL  = init->output;
	RTC->CR.POL   = init->output_polarity;
	RTC->PSR.SPRS = init->synch_pre_div;
	RTC->PSR.APRS = init->asynch_pre_div << 16;
	RTC->CR.GO    = 1;

	RTC_LOCK();
	return;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group2 Time and Date functions
  * @brief    RTC Time and Date functions
  *
  * @verbatim
 ===============================================================================
                 ##### Time and Date functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) To configure the time use the rtc_set_time() function.
       (+) To configure the date use the rtc_set_date() function.
       (+) To read the time use the rtc_get_time() function.
       (+) To read the date use the rtc_get_date() function.

    @endverbatim
  * @{
  */

/**
  * @brief  Set specified time.
  * @param  time: pointer to a rtc_time_t structure.
  * @retval HAL status.
  */
hal_status_t  rtc_set_time(rtc_time_t *time)
{
	uint32_t tmp;

	assert_param(time != NULL);

	tmp = (dec_to_bcd(time->second)) |
	      (dec_to_bcd(time->minute) << 8) |
	      (dec_to_bcd(time->hour) << 16);

	RTC_UNLOCK();
	RTC->TR.Word = tmp;
	RTC_LOCK();

	tmp = __get_tick();

	while (RTC->CR.BUSY) {
		if ((__get_tick() - tmp) > RTC_TIMEOUT_VALUE)
			return TIMEOUT;
	}

	return OK;
}

/**
  * @brief  Set specified date.
  * @param  date: pointer to a rtc_date_t structure.
  * @retval HAL status.
  */
hal_status_t rtc_set_date(rtc_date_t *date)
{
	uint32_t tmp;

	assert_param(date != NULL);

	tmp = (dec_to_bcd(date->day)) |
	      (dec_to_bcd(date->month) << 8) |
	      (dec_to_bcd(date->year) << 16) |
	      (dec_to_bcd(date->week) << 24);

	RTC_UNLOCK();
	RTC->DR.Word = tmp;
	RTC_LOCK();

	while (RTC->CR.BUSY) {
		if ((__get_tick() - tmp) > RTC_TIMEOUT_VALUE)
			return TIMEOUT;
	}

	return OK;
}

/**
  * @brief  Set specified time.
  * @param  time: pointer to a rtc_time_t structure.
  * @retval None
  */
void rtc_get_time(rtc_time_t *time)
{
	uint32_t tmp;

	assert_param(time != NULL);

	time->sub_sec = RTC->SSR.SS;
	tmp = RTC->TR.Word;

	time->second = bcd_to_dec(tmp & 0x7F);
	time->minute = bcd_to_dec((tmp >> 8) & 0x7F);
	time->hour   = bcd_to_dec((tmp >> 16) & 0x7F);

	return;
}

/**
  * @brief  Set specified date.
  * @param  date: pointer to a rtc_date_t structure.
  * @retval None
  */
void rtc_get_date(rtc_date_t *date)
{
	uint32_t tmp = RTC->DR.Word;

	assert_param(date != NULL);

	date->day   = bcd_to_dec(tmp & 0x3F);
	date->month = bcd_to_dec((tmp >> 8) & 0x1F);
	date->year  = bcd_to_dec((tmp >> 16) & 0xFF);
	date->week  = bcd_to_dec((tmp >> 24) & 0x7);

	return;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group3 Alarm functions
  * @brief    RTC alarm functions
  *
  * @verbatim
 ===============================================================================
                 ##### Alarm functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) To configure the alarm use rtc_set_alarm() function
       (+) To read the alarm use rtc_get_alarm() function

    @endverbatim
  * @{
  */

/**
  * @brief  Set alarm.
  * @param  alarm: pointer to rtc_alarm_t struct.
  * @retval None
  */
void rtc_set_alarm(rtc_alarm_t *alarm)
{
	unsigned int tmp, ss_tmp;

	assert_param(IS_RTC_ALARM(alarm->idx));
	assert_param(IS_RTC_ALARM_SEL(alarm->sel));
	assert_param(IS_RTC_ALARM_SS_MASK(alarm->ss_mask));

	tmp = (dec_to_bcd(alarm->time.second)) |
	      (dec_to_bcd(alarm->time.minute) << 8) |
	      (dec_to_bcd(alarm->time.hour) << 16) |
	      alarm->mask;

	if (alarm->sel == RTC_SELECT_DAY) {
		tmp |= (dec_to_bcd(alarm->day) << 24);
		tmp &= 0x7FFFFFFF; /* Reset bit31 */
	}
	else {
		tmp |= (1 << (alarm->week + 24));
		tmp |= 0x80000000; /* Set bit31 */
	}

	ss_tmp = (alarm->time.sub_sec & 0x7F) |
	         (alarm->ss_mask << 24);

	RTC_UNLOCK();

	if (alarm->idx == RTC_ALARM_A) {
		RTC->ALMAR.Word   = tmp;
		RTC->ALMASSR.Word = ss_tmp;
		RTC->CR.ALMAEN    = ENABLE;
	}
	else {
		RTC->ALMBR.Word   = tmp;
		RTC->ALMBSSR.Word = ss_tmp;
		RTC->CR.ALMBEN    = ENABLE;
	}

	RTC_LOCK();
	return;
}

/**
  * @brief  Get alarm parameters.
  * @param  alarm: pointer to rtc_alarm_t struct.
  * @retval None
  */
void rtc_get_alarm(rtc_alarm_t *alarm)
{
	uint8_t week;
	uint32_t tmp, ss_tmp;

	assert_param(alarm != NULL);

	if (alarm->idx == RTC_ALARM_A) {
		tmp    = RTC->ALMAR.Word;
		ss_tmp = RTC->ALMASSR.Word;
	}
	else {
		tmp    = RTC->ALMBR.Word;
		ss_tmp = RTC->ALMBSSR.Word;
	}

	if ((tmp >> 31) & 0x1) {
		alarm->sel = RTC_SELECT_WEEK;
		week = ((tmp >> 24) & 0x7F);

		switch (week) {
		case 1:
			alarm->week = 0;
			break;
		case 2:
			alarm->week = 1;
			break;
		case 4:
			alarm->week = 2;
			break;
		case 8:
			alarm->week = 3;
			break;
		case 16:
			alarm->week = 4;
			break;
		case 32:
			alarm->week = 5;
			break;
		case 64:
			alarm->week = 6;
			break;
		default:
			break;
		}
	}
	else {
		alarm->sel = RTC_SELECT_DAY;
		alarm->day = bcd_to_dec((tmp >> 24) & 0x3F);
	}

	alarm->time.second  = bcd_to_dec(tmp & 0x7F);
	alarm->time.minute  = bcd_to_dec((tmp >> 8) & 0x7F);
	alarm->time.hour    = bcd_to_dec((tmp >> 16) & 0x3F);
	alarm->time.sub_sec = ss_tmp & 0x7FFF;
	alarm->ss_mask      = (rtc_sub_second_mask_t)((ss_tmp >> 24) & 0xF);
	alarm->mask         = tmp & ALARM_MASK_ALL;

	return;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group4 Time stamp functions
  * @brief    RTC time stamp functions
  *
  * @verbatim
 ===============================================================================
                 ##### Time stamp functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) To configure the time stamp use rtc_set_time_stamp() function
       (+) To read the time stamp use rtc_get_time_stamp() function
       (+) To cancel the time stamp use rtc_cancel_time_stamp() function

    @endverbatim
  * @{
  */

/**
  * @brief  Set time stamp.
  * @param  sel: time stamp signal select:
  *           @arg RTC_TS_SIGNAL_SEL_TAMPER0
  *           @arg RTC_TS_SIGNAL_SEL_TAMPER1
  * @param  style: time stamp trigger style:
  *           @arg RTC_TS_RISING_EDGE
  *           @arg RTC_TS_FALLING_EDGE
  * @retval None
  */
void rtc_set_time_stamp(rtc_ts_signal_sel_t sel, rtc_ts_trigger_style_t style)
{
	assert_param(IS_RTC_TS_SIGNAL(sel));
	assert_param(IS_RTC_TS_STYLE(style));

	RTC_UNLOCK();

	RTC->CR.TSEN   = DISABLE;
	RTC->CR.TSSEL  = sel;
	RTC->CR.TSEDGE = style;
	RTC->CR.TSEN   = ENABLE;

	RTC_LOCK();
	return;
}

/**
  * @brief  Cancel time stamp.
  * @retval None
  */
void rtc_cancel_time_stamp(void)
{
	RTC_UNLOCK();
	RTC->CR.TSEN = DISABLE;
	RTC_LOCK();

	return;
}

/**
  * @brief  Get time stamp value.
  * @param  ts_time: pointer to rtc_time_t structure.
  * @param  ts_date: pointer to rtc_date_t structure.
  * @retval None
  */
void rtc_get_time_stamp(rtc_time_t *ts_time, rtc_date_t *ts_date)
{
	uint32_t tmp0, tmp1;

	assert_param(ts_time != NULL);
	assert_param(ts_date != NULL);

	ts_time->sub_sec = RTC->TSSSR.SS;
	tmp0 = RTC->TSTR.Word;
	tmp1 = RTC->TSDR.Word;

	ts_time->second = bcd_to_dec(tmp0 & 0x7F);
	ts_time->minute = bcd_to_dec((tmp0 >> 8) & 0x7F);
	ts_time->hour   = bcd_to_dec((tmp0 >> 16) & 0x3F);
	ts_date->day    = bcd_to_dec(tmp1 & 0x3F);
	ts_date->month  = bcd_to_dec((tmp1 >> 8) & 0x1F);
	ts_date->year   = bcd_to_dec((tmp1 >> 16) & 0xFF);
	ts_date->week   = bcd_to_dec((tmp1 >> 24) & 0x7);

	return;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group5 Tamper functions
  * @brief    RTC tamper functions
  *
  * @verbatim
 ===============================================================================
                 ##### Tamper functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) To configure the tamper use rtc_set_tamper() function
       (+) To cancel the tamper use rtc_alarm_cmd() function

    @endverbatim
  * @{
  */
/**
  * @brief  Set tamper parameters.
  * @param  tamper: pointer to rtc_tamper_t structure.
  * @retval None
  */
void rtc_set_tamper(rtc_tamper_t *tamper)
{
	assert_param(IS_RTC_TAMPER(tamper->idx));
	assert_param(IS_RTC_TAMPER_TRIGGER(tamper->trig));
	assert_param(IS_RTC_TAMPER_SAMPLING_FREQ(tamper->freq));
	assert_param(IS_RTC_TAMPER_DURATION(tamper->dur));
	assert_param(IS_FUNC_STATE(tamper->ts));

	RTC_UNLOCK();

	RTC->TAMPCR.TAMPTS  = tamper->ts;
	RTC->TAMPCR.TAMPCKS = tamper->freq;
	RTC->TAMPCR.TAMPFLT = tamper->dur;

	if (tamper->idx == RTC_TAMPER_0) {
		RTC->TAMPCR.TAMP0LVL = tamper->trig;
		RTC->TAMPCR.TAMP0EN  = ENABLE;
	}
	else {
		RTC->TAMPCR.TAMP1LVL = tamper->trig;
		RTC->TAMPCR.TAMP1EN  = ENABLE;
	}

	RTC_LOCK();
	return;
}

/**
  * @brief  Cancel tamper.
  * @param  idx: index of tamper:
  *           @arg RTC_TAMPER_0
  *           @arg RTC_TAMPER_1
  * @retval None
  */
void rtc_cancel_tamper(rtc_tamper_idx_t idx)
{
	assert_param(IS_RTC_TAMPER(idx));

	RTC_UNLOCK();

	if (idx == RTC_TAMPER_0)
		RTC->TAMPCR.TAMP0EN = 0;
	else
		RTC->TAMPCR.TAMP1EN = 0;

	RTC_LOCK();
	return;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group6 Wake-up functions
  * @brief    RTC wake-up functions
  *
  * @verbatim
 ===============================================================================
                 ##### Wake-up functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) To configure the wake-up parameters use rtc_set_wakeup() function
       (+) To read the re-load register value use rtc_get_wakeup_timer_value() function
       (+) To cancel the wake-up use rtc_cancel_wakeup() function

    @endverbatim
  * @{
  */
/**
  * @brief  Set wake-up parameters.
  * @param  clock: pointer to rtc_wakeup_clock_t structure.
  * @param  value: re-load value.
  * @retval None
  */
void rtc_set_wakeup(rtc_wakeup_clock_t clock, uint16_t value)
{
	assert_param(IS_RTC_WAKEUP_CLOCK(clock));

	RTC_UNLOCK();
	RTC->CR.WUSEL = clock;
	RTC->WUTR.WUT = value;
	RTC->CR.WUTE  = ENABLE;
	RTC_LOCK();

	return;
}

/**
  * @brief  Cancel wake-up.
  * @retval None
  */
void rtc_cancel_wakeup(void)
{
	RTC_UNLOCK();
	RTC->CR.WUTE = DISABLE;
	RTC_LOCK();

	return;
}

/**
  * @brief  Get wake-up re-load register value.
  * @retval Value of re-load register.
  */
uint16_t rtc_get_wakeup_timer_value(void)
{
	return RTC->WUTR.WUT & 0xFFFF;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group7 Clock output functions
  * @brief    RTC clock output functions
  *
  * @verbatim
 ===============================================================================
                 ##### Clock output functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) To configure the clock output type use rtc_set_clock_output() function
       (+) To cancel the clock output use rtc_cancel_clock_output() function

    @endverbatim
  * @{
  */
/**
  * @brief  Set clock output parameters.
  * @param  clock: pointer to rtc_clock_output_t structure.
  * @retval HAL status.
  */
hal_status_t rtc_set_clock_output(rtc_clock_output_t clock)
{
	assert_param(IS_RTC_CLOCK_OUTPUT(clock));

	if (RTC->CR.OSEL)
		return ERROR;

	RTC_UNLOCK();
	RTC->CR.COSEL = clock;
	RTC->CR.COE   = ENABLE;
	RTC_LOCK();

	return OK;
}

/**
  * @brief  Cancel clock output.
  * @retval None
  */
void rtc_cancel_clock_output(void)
{
	RTC_UNLOCK();
	RTC->CR.COE = DISABLE;
	RTC_LOCK();

	return;
}
/**
  * @}
  */

/** @defgroup RTC_Public_Functions_Group8 Control functions
  * @brief    RTC control functions
  *
  * @verbatim
 ===============================================================================
                 ##### Control functions #####
 ===============================================================================

 [..] This section provides functions allowing:
     [#]
       (+) Configure interrupt enable/disable.
       (+) Enable/disable alarm.
       (+) Configure rtc shift.
       (+) Calibrate time.
       (+) Get interrupt source status.
       (+) Get interrupt flag status.
       (+) Clear interrupt flag.

    @endverbatim
  * @{
  */
/**
  * @brief  Enable/disable the specified RTC interrupts.
  * @param  it: Specifies the RTC interrupt sources to be enabled or disabled.
  *         This parameter can be one of the @ref rtc_it_t.
  * @param  state: New state of the specified RTC interrupts.
  *         This parameter can be:
  *           @arg ENABLE
  *           @arg DISABLE
  * @retval None
  */
void rtc_interrupt_config(rtc_it_t it, type_func_t state)
{
	assert_param(IS_RTC_IT(it));
	assert_param(IS_FUNC_STATE(state));

	RTC_UNLOCK();

	if (state == ENABLE)
		RTC->IER.Word |= it;
	else
		RTC->IER.Word &= ~it;

	RTC_LOCK();
	return;
}

/**
  * @brief  Enable/Disable alarm.
  * @param  idx: index of alarm:
  *           @arg RTC_ALARM_A
  *           @arg RTC_ALARM_B
  * @param  state: New status of the specified alarm:
  *           @arg ENABLE
  *           @arg DISABLE
  * @retval None
  */
void rtc_alarm_cmd(rtc_alarm_idx_t idx, type_func_t state)
{
	assert_param(IS_RTC_ALARM(idx));
	assert_param(IS_FUNC_STATE(state));

	RTC_UNLOCK();

	if (idx == RTC_ALARM_A)
		RTC->CR.ALMAEN = state;
	else
		RTC->CR.ALMBEN = state;

	RTC_LOCK();
	return;
}

/**
  * @brief  Set shift parameters.
  * @param  add_1s: Enable/Disable added 1 second.
  * @param  sub_ss: value of sub-sconde.
  * @retval HAL status.
  */
hal_status_t rtc_set_shift(type_func_t add_1s, uint16_t sub_ss)
{
	uint32_t tick;

	assert_param(IS_FUNC_STATE(add_1s));
	assert_param(IS_SHIFT_SUB_SS(sub_ss));

	RTC_UNLOCK();
	RTC->SHIFTR.ADDSEC = add_1s;
	RTC->SHIFTR.SUBSS  = sub_ss;

	RTC_LOCK();

	tick = __get_tick();

	while (RTC->CR.SHIFT) {
		if ((__get_tick() - tick) > RTC_TIMEOUT_VALUE)
			return TIMEOUT;
	}

	return OK;
}

/**
  * @brief  Set calibation
  * @param  config: pointer to rtc_cali_t structure.
  * @retval None
  */
void rtc_set_cali(rtc_cali_t *config)
{
	assert_param(IS_RTC_CALI_FREQ(config->cali_freq));
	assert_param(IS_RTC_CALI_TC(config->tc));
	assert_param(IS_RTC_CALC_FREQ(config->calc_freq));
	assert_param(IS_RTC_CALI_CALC(config->calc));
	assert_param(IS_FUNC_STATE(config->acc));

	RTC_CALI_UNLOCK();
	RTC->CALCR.CALP   = config->cali_freq;
	RTC->CALCR.TCM    = config->tc;
	RTC->CALCR.TCP    = config->calc_freq;
	RTC->CALCR.ALG    = config->calc;
	RTC->CALCR.DCMACC = config->acc;
	RTC->CALCR.CALEN  = ENABLE;
	RTC_CALI_LOCK();

	return;
}

/**
  * @brief  Cancel calibration
  * @retval None
  */
void rtc_cancel_cali(void)
{
	RTC_CALI_UNLOCK();
	RTC->CALCR.CALEN = DISABLE;
	RTC_CALI_LOCK();

	return;
}

/**
  * @brief  Get calibration status.
  * @retval HAL status.
  */
hal_status_t rtc_get_cali_status(void)
{
	if (RTC->CALCR.ERR)
		return ERROR;
	else
		return OK;
}

/**
  * @brief  Write temperature value.
  * @param  temp: the value of temperature.
  * @retval None
  */
void rtc_write_temp(uint16_t temp)
{
	RTC_CALI_UNLOCK();
	RTC->TEMPR.TEMP_V = temp;
	RTC_CALI_LOCK();

	return;
}

/**
  * @brief  Get the status of RTC interrupt source.
  * @param  it: Specifies the RTC interrupt source.
  *         This parameter can be one of the @ref rtc_it_t.
  * @retval Status:
  *           - 0: RESET
  *           - 1: SET
  */
it_status_t rtc_get_it_status(rtc_it_t it)
{
	assert_param(IS_RTC_IT(it));

	if (RTC->IER.Word & it)
		return SET;

	return RESET;
}

/**
  * @brief  Get the status of RTC interrupt flag.
  * @param  flag: Specifies the RTC interrupt flag.
  *         This parameter can be one of the @ref rtc_flag_t.
  * @retval Status:
  *           - 0: RESET
  *           - 1: SET
  */
flag_status_t rtc_get_flag_status(rtc_flag_t flag)
{
	assert_param(IS_RTC_IF(flag));

	if (RTC->IFR.Word & flag)
		return SET;

	return RESET;
}

/** @brief  Clear the specified RTC pending flag.
  * @param  flag: specifies the flag to check.
  * @retval None.
  */
void rtc_clear_flag_status(rtc_flag_t flag)
{
	assert_param(IS_RTC_IF(flag));

	RTC_UNLOCK();
	RTC->IFCR.Word = flag;
	RTC_LOCK();

	return;
}
/**
  * @}
  */
/**
  * @}
  */
#endif /* HAL_RTC */
/**
  * @}
  */
/**
  * @}
  */
