#include "rtc.h"

uint8_t alarm1Flag = 0;
RTC_InitTypeDef RTC_InitStructure;

// RTC initialization
// return: SUCEE(0)
//         ERROR(1)
uint8_t My_RTC_Init(void)
{
  uint32_t timeoutCounter = 0xFFFFF;
  RCC_APBPeriphClockCmd(RCC_APBPeriph_RTC, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
  GPIO_Init(GPIOD, GPIO_Pin_2, GPIO_AF4);

  RCC_LSEConfig(RCC_LSE_ON);

  /* wait LSE clock ready */
  while ((RCC->LSECR & RCC_LSECR_LSERDY) == RESET)
  {
    timeoutCounter--;
    if (timeoutCounter == 0)
      return 1;
  }
  

  RCC_RTCPeriphResetCmd(ENABLE);
  RCC_RTCPeriphResetCmd(DISABLE);

  RTC_InitStructure.RTC_CLKSEL = RTC_CLK_SOURCE_LSE;    // Set RTC Clk Source
  RTC_InitStructure.RTC_HSEDIV = 0x0;                   // Set RTC HSE div
  RTC_InitStructure.RTC_HourFormat = RTC_HOURFORMAT_12; // Set RTC  hour format:12h
  RTC_Init(&RTC_InitStructure);

  RTC_Set_Time(11, 59, 50, RTC_H12_PM); // set time PM 12:00:00
  RTC_Set_Date(99, 12, 31, 5 - 1, 0);   // set date 99/01/01 week:5(-1)  20century

  RTC_Set_Alarm1();                     // 2000/01/01 week:6(-1)  00:00:00

  RTC_BypassShadowCmd(ENABLE);

  RTC_Set_Alarm2();       // set period alarm 1s

  RTC_1HZ_Config(ENABLE); // set 1hz output

  RTC_CalibConfig(RTC_CalibPeriod_6sec, 0x01);

  return 0;
}

// set rtc date
// hour(0~23 or 1~12),min(0~59),sec(0~59)
// ampm: @RTC_AM_PM_Definitions  :RTC_H12_AM/RTC_H12_PM
// return: SUCEE(1)
//         ERROR(0)
ErrorStatus RTC_Set_Time(uint8_t hour, uint8_t min, uint8_t sec, uint8_t ampm)
{
  RTC_TimeTypeDef RTC_TimeTypeInitStructure;

  RTC_TimeTypeInitStructure.RTC_Hours = hour;
  RTC_TimeTypeInitStructure.RTC_Minutes = min;
  RTC_TimeTypeInitStructure.RTC_Seconds = sec;
  RTC_TimeTypeInitStructure.RTC_H12 = ampm;

  return RTC_SetTime(RTC_Format_BIN, &RTC_TimeTypeInitStructure);
}

// set rtc date
// year(0~99),month(1~12),date(0~31)
// cen(0,1)
// return : SUCEE(1)
//          ERROR(0)
ErrorStatus RTC_Set_Date(uint8_t year, uint8_t month, uint8_t date, uint8_t week, uint8_t cen)
{
  RTC_DateTypeDef RTC_DateTypeInitStructure;
  RTC_DateTypeInitStructure.RTC_Date = date;
  RTC_DateTypeInitStructure.RTC_Month = month;
  RTC_DateTypeInitStructure.RTC_Year = year;
  RTC_DateTypeInitStructure.RTC_WeekDay = week;
  RTC_DateTypeInitStructure.RTC_Cen = cen;
  return RTC_SetDate(RTC_Format_BIN, &RTC_DateTypeInitStructure);
}

// set alarm
void RTC_Set_Alarm1(void)
{
  RTC_AlarmTypeDef RTC_AlarmTypeInitStructure;

  RTC_Alarm1Cmd(DISABLE); // close alarm1

  RTC_AlarmTypeInitStructure.RTC_AlarmTime.RTC_Hours = 12;
  RTC_AlarmTypeInitStructure.RTC_AlarmTime.RTC_Minutes = 0;
  RTC_AlarmTypeInitStructure.RTC_AlarmTime.RTC_Seconds = 0;
  RTC_AlarmTypeInitStructure.RTC_AlarmTime.RTC_H12 = 0;

  RTC_AlarmTypeInitStructure.RTC_AlarmDate.RTC_Year = 00;
  RTC_AlarmTypeInitStructure.RTC_AlarmDate.RTC_Month = 1;
  RTC_AlarmTypeInitStructure.RTC_AlarmDate.RTC_Date = 1;
  RTC_AlarmTypeInitStructure.RTC_AlarmDate.RTC_WeekDay = 6 - 1;
  RTC_AlarmTypeInitStructure.RTC_AlarmDate.RTC_Cen = 1;

  RTC_AlarmTypeInitStructure.Alarm_Enable.Year_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.Month_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.Date_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.WeekDay_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.Hours_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.Minutes_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.Seconds_Enable = ENABLE;
  RTC_AlarmTypeInitStructure.Alarm_Enable.Sen_Enable = ENABLE;

  RTC_SetAlarm1(RTC_Format_BIN, &RTC_AlarmTypeInitStructure);

  RTC_ClearITPendingBit(RTC_IT_ALR1);

  RTC_ITConfig(RTC_IT_ALR1, ENABLE);
  RTC_Alarm1Cmd(ENABLE);

  NVIC_SetPriority(RTC_IRQn, 2);
  NVIC_EnableIRQ(RTC_IRQn);
}

void RTC_Set_Alarm2(void)
{
  RTC_ITConfig(RTC_IT_ALR2, DISABLE);
  RTC_ClearITPendingBit(RTC_IT_ALR2);

  RTC_SetALARM2Period(RTC_ALARM2_1S);
  RTC_ITConfig(RTC_IT_ALR2, ENABLE);

  NVIC_SetPriority(RTC_IRQn, 2);
  NVIC_EnableIRQ(RTC_IRQn);
}

void RTC_IRQHandler(void)
{
  if ((RTC->ISR & (0x01 << 4)) == (0x01 << 4))
  {
    alarm1Flag = 1;
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
    RTC->INTCLR |= 0x01 << 4;
    RTC->WPR = 0xFF;
  }
  if ((RTC->ISR & (0x01 << 5)) == (0x01 << 5))
  {
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
    RTC->INTCLR |= 0x01 << 5;
    RTC->WPR = 0xFF;
  }
}
