/**
  ******************************************************************************
  * @file    ys32md211_rtc.c
  * @author  YSPRING Application Team
  * @version V1.0.1
  * @date    2023.3.24
  * @brief   This file provides firmware functions to manage the following 
  *          functionalities of the Real-Time Clock (RTC) peripheral:
  *           + Initialization
  *           + Output pin Configuration
  *           + Digital Calibration configuration  
  *           + Output Type Config configuration
  *           + Shift control synchronisation  
  *           + Interrupts and flags management
  *
 @verbatim
 ===============================================================================                                                                                    
                     ##### How to use this driver #####
 ===============================================================================

  ***RTC initialization steps***
 ===============================
    1. Enable the RTC clock: 
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE).

    2. Enable DBPRTC write protection (PWR_CR1): 
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE),
        PWR_BackupAccessCmd(ENABLE).

    3. Select the RTC clock source(LSE, LSI or HSE divided by 128):
        RCC_RTCCLKConfig().

    4. Configure the RTC,.
        RTC_Init().
        
    (#) All RTC registers are Write protected. Writing to the RTC registers
        is enabled by writing a key into the Write Protection register, RTC_WPR.
  
 ***Outputs configuration ***
 ============================
    [..] The RTC has 2 different outputs:         
        (+) AFO_CALIB: this output is 256Hz signal or 1Hz .
            To output the RTC Clock on RTC_AF1 pin, use the RTC_CalibOutputCmd()
            function.                
  
 ***Original Digital Calibration configuration ***
 =================================================
    [..] Configure the RTC Original Digital Calibration Value and the corresponding
         calibration cycle period (32s,16s and 8s) using the RTC_SmoothCalibConfig()
         function.
  
 *** RTC and low power modes ***
 ===============================
    [..] The MCU can be woken up from a low power mode by an RTC alternate 
         function.
    [..] The RTC provides a programmable time base for waking up from the 
         Stop or Standby mode at regular intervals.
         Wakeup from STOP and Standby modes is possible only when the RTC 
         clock source is LSE or LSI.
         The RTC clock source cannot be changed after selection unless the 
         RTC is reset.
 @endverbatim
 
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "ys32md211_rtc.h"

/** @addtogroup YS32MD211_StdPeriph_Driver
  * @{
  */

/** @defgroup RTC 
  * @brief RTC driver modules
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/* Masks Definition */
#define RECALPF_TIMEOUT          ((uint32_t) 0x00001000)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

/** @defgroup RTC_Private_Functions
  * @{
  */ 

/** @defgroup RTC_Group1 Initialization and Configuration functions
 *  @brief   Initialization and Configuration functions 
 *
@verbatim   
 ===============================================================================
            ##### Initialization and Configuration functions #####
 ===============================================================================  

    [..] This section provide functions allowing to initialize and configure the RTC
         Prescaler (Synchronous and Asynchronous), RTC Hour format, disable RTC registers
         Write protection, enter and exit the RTC initialization mode, RTC registers
         synchronization check and reference clock detection enable.
  
@endverbatim
  * @{
  */

/**
  * @brief  Deinitializes the RTC registers to their default reset values.
  * @note   This function doesn't reset the RTC Clock source and RTC Backup Data
  *         registers.       
  * @param  None
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: RTC registers are deinitialized
  *          - ERROR: RTC registers are not deinitialized
  */
ErrorStatus RTC_DeInit(void)
{
  ErrorStatus status = SUCCESS;
  
  /* Disable the write protection for RTC registers */
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;

  /* Reset TR, DR and CR registers */
  RTC->CR  &= (uint32_t)0x00000000;
  RTC->PRER = (uint32_t)0x007F00FF;
  RTC->CALR = (uint32_t)0x00000000;

  /* Enable the write protection for RTC registers */
  RTC->WPR = 0xFF;  

  return status;
}

/**
  * @brief  Initializes the RTC registers according to the specified parameters 
  *         in RTC_InitStruct.
  * @param  RTC_InitStruct: pointer to a RTC_InitTypeDef structure that contains 
  *         the configuration information for the RTC peripheral.
  * @note   The RTC Prescaler register is write protected and can be written in 
  *         initialization mode only.  
  * @retval None
  */
void RTC_Init(RTC_InitTypeDef* RTC_InitStruct)
{
  /* Check the parameters */
  assert_param(IS_RTC_ASYNCH_PREDIV(RTC_InitStruct->RTC_AsynchPrediv));
  assert_param(IS_RTC_SYNCH_PREDIV(RTC_InitStruct->RTC_SynchPrediv));

  /* Disable the write protection for RTC registers */
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;

  /* Configure the RTC PRER */
  RTC->PRER = (uint32_t)(RTC_InitStruct->RTC_SynchPrediv);
  RTC->PRER |= (uint32_t)(RTC_InitStruct->RTC_AsynchPrediv << 16);

  /* Enable the write protection for RTC registers */
  RTC->WPR = 0xFF;
}

/**
  * @brief  Fills each RTC_InitStruct member with its default value.
  * @param  RTC_InitStruct: pointer to a RTC_InitTypeDef structure which will be 
  *         initialized.
  * @retval None
  */
void RTC_StructInit(RTC_InitTypeDef* RTC_InitStruct)
{
  /* Initialize the RTC_AsynchPrediv member */
  RTC_InitStruct->RTC_AsynchPrediv = (uint32_t)0x7F;

  /* Initialize the RTC_SynchPrediv member */
  RTC_InitStruct->RTC_SynchPrediv = (uint32_t)0xFF; 
}

/**
  * @brief  Enables or disables the RTC registers write protection.
  * @note   All the RTC registers are write protected except for RTC_ISR[13:8], 
  *         RTC_TAFCR and RTC_BKPxR.
  * @note   Writing a wrong key reactivates the write protection.
  * @note   The protection mechanism is not affected by system reset.
  * @param  NewState: new state of the write protection.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RTC_WriteProtectionCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    /* Enable the write protection for RTC registers */
    RTC->WPR = 0xFF;
  }
  else
  {
    /* Disable the write protection for RTC registers */
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
  }
}

/** @defgroup RTC_Group7 Digital Calibration configuration functions
 *  @brief   Digital Calibration configuration functions 
 *
@verbatim   
 ===============================================================================
          ##### Digital Calibration configuration functions #####
 ===============================================================================

@endverbatim
  * @{
  */

/**
  * @brief  Enables or disables the RTC clock to be output through the relative pin.
  * @param  NewState: new state of the digital calibration Output.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RTC_CalibOutputCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  /* Disable the write protection for RTC registers */
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;
  
  if (NewState != DISABLE)
  {
    /* Enable the RTC clock output */
    RTC->CR |= (uint32_t)RTC_CR_COE;
  }
  else
  { 
    /* Disable the RTC clock output */
    RTC->CR &= (uint32_t)~RTC_CR_COE;
  }
  
  /* Enable the write protection for RTC registers */
  RTC->WPR = 0xFF; 
}

/**
  * @brief  Configure the Calibration Pinout (RTC_CALIB) Selection (1Hz or 256Hz).
  * @param  RTC_CalibOutput: Select the Calibration output Selection .
  *          This parameter can be one of the following values:
  *            @arg RTC_CalibOutput_256Hz: A signal has a regular waveform at 256Hz. 
  *            @arg RTC_CalibOutput_1Hz: A signal has a regular waveform at 1Hz.
  * @retval None
*/
void RTC_CalibOutputConfig(uint32_t RTC_CalibOutput)
{
  /* Check the parameters */
  assert_param(IS_RTC_CALIB_OUTPUT(RTC_CalibOutput));

  /* Disable the write protection for RTC registers */
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;
  
  /*clear flags before config*/
  RTC->CR &= (uint32_t)~RTC_CR_COSEL;

  /* Configure the RTC_CR register */
  RTC->CR |= (uint32_t)RTC_CalibOutput;

  /* Enable the write protection for RTC registers */
  RTC->WPR = 0xFF;
}

/**
  * @brief  Configures the Smooth Calibration Settings.
  * @param  RTC_SmoothCalibPeriod: Select the Smooth Calibration Period.
  *          This parameter can be can be one of the following values:
  *            @arg RTC_SmoothCalibPeriod_32sec: The smooth calibration periode is 32s.
  *            @arg RTC_SmoothCalibPeriod_16sec: The smooth calibration periode is 16s.
  *            @arg RTC_SmoothCalibPeriod_8sec: The smooth calibartion periode is 8s.
  * @param  RTC_SmoothCalibPlusPulses: Select to Set or reset the CALP bit.
  *          This parameter can be one of the following values:
  *            @arg RTC_SmoothCalibPlusPulses_Set: Add one RTCCLK puls every 2**11 pulses.
  *            @arg RTC_SmoothCalibPlusPulses_Reset: No RTCCLK pulses are added.
  * @param  RTC_SmouthCalibMinusPulsesValue: Select the value of CALM[8:0] bits.
  *          This parameter can be one any value from 0 to 0x000001FF.
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: RTC Calib registers are configured
  *          - ERROR: RTC Calib registers are not configured
*/
ErrorStatus RTC_SmoothCalibConfig(uint32_t RTC_SmoothCalibPeriod,
                                  uint32_t RTC_SmoothCalibPlusPulses,
                                  uint32_t RTC_SmouthCalibMinusPulsesValue)
{
  ErrorStatus status = ERROR;
  uint32_t recalpfcount = 0;

  /* Check the parameters */
  assert_param(IS_RTC_SMOOTH_CALIB_PERIOD(RTC_SmoothCalibPeriod));
  assert_param(IS_RTC_SMOOTH_CALIB_PLUS(RTC_SmoothCalibPlusPulses));
  assert_param(IS_RTC_SMOOTH_CALIB_MINUS(RTC_SmouthCalibMinusPulsesValue));

  /* Disable the write protection for RTC registers */
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;
  
  /* check if a calibration is pending*/
  if ((RTC->ICSR & RTC_ICSR_RECALPF) != RESET)
  {
    /* wait until the Calibration is completed*/
    while (((RTC->ICSR & RTC_ICSR_RECALPF) != RESET) && (recalpfcount != RECALPF_TIMEOUT))
    {
      recalpfcount++;
    }
  }

  /* check if the calibration pending is completed or if there is no calibration operation at all*/
  if ((RTC->ICSR & RTC_ICSR_RECALPF) == RESET)
  {
    /* Configure the Smooth calibration settings */
    RTC->CALR = (uint32_t)((uint32_t)RTC_SmoothCalibPeriod | (uint32_t)RTC_SmoothCalibPlusPulses | (uint32_t)RTC_SmouthCalibMinusPulsesValue);

    status = SUCCESS;
  }
  else
  {
    status = ERROR;
  }

  /* Enable the write protection for RTC registers */
  RTC->WPR = 0xFF;
  
  return (ErrorStatus)(status);
}

/**
  * @}
  */

/** @defgroup RTC_Group13 Interrupts and flags management functions
 *  @brief   Interrupts and flags management functions  
 *
@verbatim   
 ===============================================================================
            ##### Interrupts and flags management functions #####
 ===============================================================================  
    [..] All RTC interrupts are connected to the EXTI controller.
         (+) To enable the RTC TimeStamp interrupt, the following sequence is required:
             (++) Configure and enable the EXTI Line 19 in interrupt mode and select the rising 
                  edge sensitivity using the EXTI_Init() function.
             (++) Configure and enable the TAMP_STAMP IRQ channel in the NVIC using the NVIC_Init()
                  function.
             (++) Configure the RTC.

@endverbatim
  * @{
  */

/**
  * @brief  Enables or disables the specified RTC interrupts.
  * @param  RTC_IT: specifies the RTC interrupt sources to be enabled or disabled. 
  *          This parameter can be any combination of the following values:
  *            @arg RTC_IT_SIE:  Time Stamp interrupt mask
  * @param  NewState: new state of the specified RTC interrupts.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RTC_CONFIG_IT(RTC_IT));
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  /* Disable the write protection for RTC registers */
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;

  if (NewState != DISABLE)
  {
    /* Configure the Interrupts in the RTC_CR register */
    RTC->CR |= (uint32_t)RTC_IT;
  }
  else
  {
    /* Configure the Interrupts in the RTC_CR register */
    RTC->CR &= (uint32_t)~RTC_IT;
  }
  /* Enable the write protection for RTC registers */
  RTC->WPR = 0xFF; 
}

/**
  * @brief  Checks whether the specified RTC flag is set or not.
  * @param  RTC_FLAG: specifies the flag to check.
  *          This parameter can be one of the following values:
  *            @arg RTC_FLAG_SF: Time Stamp event flag
  * @retval The new state of RTC_FLAG (SET or RESET).
  */
FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG)
{
  FlagStatus bitstatus = RESET;
  
  /* Check the parameters */
  assert_param(IS_RTC_GET_FLAG(RTC_FLAG));

  if((RTC->SR & RTC_FLAG) != 0)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

/**
  * @brief  Clears the RTC's pending flags.
  * @param  RTC_FLAG: specifies the RTC flag to clear.
  *          This parameter can be any combination of the following values:
  *            @arg RTC_FLAG_SF: Time Stamp event flag
  * @retval None
  */
void RTC_ClearFlag(uint32_t RTC_FLAG)
{
  /* Check the parameters */
  assert_param(IS_RTC_GET_FLAG(RTC_FLAG));

  /* Clear the Flags in the RTC_ISR register */
  RTC->SCR |= (uint32_t)RTC_FLAG;    
}

/**
  * @}
  */ 

/**
  * @}
  */ 

/**
  * @}
  */ 

/**
  * @}
  */ 

/**
  * @}
  */ 
  

