/**
  ******************************************************************************
  * @file     RTC_CFG.c
  * @author   SINOMCU-AE
  * @brief    RTC config
  *    
  *          This file provides functions to RTC config:
  *    Backup Domain reset,enable RTC clock source:LSI or LSE;
  *    init RTC,set date and time if have not set;RTC alarm config 1S interrupt
  * 
  ******************************************************************************
  * @attention 
  *                           DISCLAIMER
  * The present firmware which is for guidance only aims at providing customers
  * with coding information regarding their products in order for them to save
  * time. As a result, SinoMCU shall not be held liable for any direct,indirect
  * or consequential damages with respect to any claims arising from the content 
  * of such firmware and/or the use made by customers of the coding information 
  * contained herein in connection with their products.
  *
  * <h2><center>&copy; Copyright (c) 2021 sinomcu All rights reserved.</center></h2>
  *
  ******************************************************************************
  */
  
#include "stdio.h"
#include "RTC_CFG.h"

/**
  * @brief  Backup Domain Reset function
  * @param  None
  * @retval None
  */
void RCC_BKDomain_Reset(void) {
  __IO uint8_t pwr_clk_en_bk;

  pwr_clk_en_bk = MS32_APB1_GRP1_IsEnabledClock(MS32_APB1_GRP1_PERIPH_PWR);
  MS32_APB1_GRP1_EnableClock(MS32_APB1_GRP1_PERIPH_PWR);   // enable power interface clock 
  MS32_PWR_EnableBkUpAccess();                             // enable RTC and bakeup register write
  
  MS32_RCC_ForceBackupDomainReset();
  MS32_RCC_ReleaseBackupDomainReset();  
  
  if (!pwr_clk_en_bk) {
    MS32_APB1_GRP1_DisableClock(MS32_APB1_GRP1_PERIPH_PWR);
  }  
}

/**
  * @brief  RTC clock config Function
  * @param  None
  * @retval None
  */
void rtc_clock_config(void) {
  MS32_RCC_OscInitTypeDef OscCfg;

  MS32_RCC_GetOscConfig(&OscCfg);  
#if(defined(RTC_USER_LSE) && RTC_USER_LSE)  
  OscCfg.LSEState = MS32_RCC_LSE_ON_DRV_H;
  MS32_RCC_OscConfig(&OscCfg);
  MS32_RTC_ClockInit(MS32_RTC_CLKSOURCE_LSE);              // LSE 32.768K 
#else
  OscCfg.LSEState = MS32_RCC_LSE_OFF;
  OscCfg.LSIState = MS32_RCC_LSI_ON;
  MS32_RCC_OscConfig(&OscCfg);
  MS32_RTC_ClockInit(MS32_RTC_CLKSOURCE_LSI);              // LSI 40K
#endif
}

/**
  * @brief  RTC config Function
  * @param  None
  * @retval None
  */
void rtc_config(void) {
  ErrorStatus status = ERROR;
  MS32_RTC_InitTypeDef RtcInitStruct;
  MS32_RTC_TimeTypeDef RtcTimeStruct = {0};
  MS32_RTC_DateTypeDef RtcDateStruct = {0};
  
  rtc_clock_config();                                      // LSE:first VBAT on,LSI: first VBAT on and core reset
  
#if(defined(RTC_USER_LSE) && RTC_USER_LSE)  
  printf("\r\n--Inf:RTC clock use LSE 32.768KHz.");  
#else
  printf("\r\n--Inf:RTC clock use LSI 40.000KHz.");  
#endif
  
  if(MS32_RTC_BAK_GetRegister(RTC, MS32_RTC_BKP_DR4) != RTC_INIT_IDF_VAL){     // RTC have not init   
    RCC_BKDomain_Reset();
    rtc_clock_config();

    MS32_RTC_StructInit( &RtcInitStruct);
    RtcInitStruct.HourFormat      = MS32_RTC_HOURFORMAT_24HOUR;
    RtcInitStruct.AsynchPrescaler = RTC_ASYNCH_PREDIV;
    RtcInitStruct.SynchPrescaler  = RTC_SYNCH_PREDIV;

    status= MS32_RTC_Init(RTC, &RtcInitStruct, DISABLE, MS32_RTC_CALIB_OUTPUT_NONE);

    if(status == ERROR){
      status = ERROR;                                                          // add user error function
      printf("\r\n**Error:MS32 RTC Init Error.");
    }
 
    RtcTimeStruct.TimeFormat =MS32_RTC_HOURFORMAT_24HOUR;                      // this must to be set
    RtcTimeStruct.Hours   = RTC_INIT_HOURS;
    RtcTimeStruct.Minutes = RTC_INIT_MINUTES;
    RtcTimeStruct.Seconds = RTC_INIT_SECONDS;   
    MS32_RTC_SetTime(RTC, MS32_RTC_FORMAT_BCD, &RtcTimeStruct, ENABLE);        // read calendar form RTC(not from Shadow reg)

    RtcDateStruct.WeekDay = RTC_INIT_WEEKDAY;
    RtcDateStruct.Day     = RTC_INIT_DAY;
    RtcDateStruct.Month   = RTC_INIT_MONTH;
    RtcDateStruct.Year    = RTC_INIT_YEAR;
    MS32_RTC_SetDate(RTC, MS32_RTC_FORMAT_BCD, &RtcDateStruct);
    
    MS32_RTC_BAK_SetRegister(RTC, MS32_RTC_BKP_DR4,RTC_INIT_IDF_VAL);          // write bakeup data reg4,avoid duplicate RTC initialization
    printf("\r\n--Inf:RTC Init Finish.");
  }
  else {
    printf("\r\n--Inf:RTC had init.");
  }
}

/**
  * @brief  RTC alarm config Function
  * @param  None
  * @retval None
  */
void rtc_alarm_config(void) {  
  MS32_RTC_AlarmTypeDef  RtcAlarmStruct;
   
  // set alarm time,mask none(do not care date and time)
  RtcAlarmStruct.AlarmTime.TimeFormat = MS32_RTC_HOURFORMAT_24HOUR;
  RtcAlarmStruct.AlarmTime.Hours      = RTC_ALARM_HOURS;
  RtcAlarmStruct.AlarmTime.Minutes    = RTC_ALARM_MINUTES;
  RtcAlarmStruct.AlarmTime.Seconds    = RTC_ALARM_SECONDS;
  RtcAlarmStruct.AlarmDateWeekDaySel  = MS32_RTC_ALARM_DATEWEEKDAYSEL_DATE;  
  RtcAlarmStruct.AlarmDateWeekDay     = 0x01;
  RtcAlarmStruct.AlarmMask            = MS32_RTC_ALARM_MASK_NONE;              // not match date and time ,ALRMASSR mask 0000,second inc alarm:1S alarm

  MS32_RTC_ALARM_Disable(RTC);                                                 // important CR->ALRAE:0 when change Alarm reg
  MS32_RTC_SetAlarm(RTC, MS32_RTC_FORMAT_BCD, &RtcAlarmStruct);
  
  // alarm not out to pin ,enable alarm
  MS32_RTC_AlarmConfig(RTC, MS32_RTC_ALARMOUT_DISABLE, MS32_RTC_OUTPUTPOLARITY_PIN_HIGH, ENABLE); 

  MS32_RTC_ClearFlag_ALRA(RTC);
  MS32_RTC_EnableIT_ALRA(RTC);

  // RTC Alarm Interrupt Configuration: EXTI line 17 configuration 
  MS32_EXTI_EnableIT_0_31(MS32_EXTI_LINE_17);
  MS32_EXTI_EnableRisingTrig_0_31(MS32_EXTI_LINE_17);
  
  // Configure the NVIC for RTC Alarm 
  NVIC_SetPriority(RTC_IRQn, 0x03);
  NVIC_EnableIRQ(RTC_IRQn);
}

/******************************** END OF FILE *********************************/
