/******************** (C) COPYRIGHT 2006 STMicroelectronics ********************
* File Name          : calendar.c
* Author             : MCD Application Team
* Date First Issued  : 03/10/2006
* Description        : This file includes the calendar driver for the STR75x-EVAL
*                      demonstration.
********************************************************************************
* History:
* 07/17/2006 : V1.0
* 03/10/2006 : V0.1
********************************************************************************
* THE PRESENT SOFTWARE 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, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

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

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

  /* ST Logo to display on master LCD 61*32 dot matrix */
  u8 STLogo61[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0,
  0xFC, 0x7C, 0x7C, 0x7C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
  0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
  0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x1C, 0x0C,
  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xC0, 0xF0, 0xFC, 0xFF, 0xFF, 0xC1, 0x80, 0x00, 0x00, 0x18,
  0x3C, 0x3C, 0x7C, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
  0xFC, 0x7C, 0x1C, 0x04, 0x00, 0x00, 0x80, 0xE0, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC,
  0xFC, 0x7C, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x78, 0x7E, 0x7F, 0x7F,
  0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7C, 0x78, 0x70, 0x60, 0x40,
  0x01, 0x03, 0x07, 0x0F, 0xFF, 0xFF, 0x7F, 0x1F, 0x07, 0x01, 0x00, 0x80, 0xE0,
  0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x07, 0x01, 0x00, 0x80, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0C, 0x0C, 0x0E, 0x0F,
  0x07, 0x01, 0x00, 0x00, 0x00, 0x08, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
  0x07, 0x01, 0x00, 0x00, 0x00, 0x02, 0x07, 0x0F, 0x07, 0x02, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

  /* Peripheral InitStructure define */
  WDG_InitTypeDef   WDG_InitStructure;

  /* Time Structure definition */
  struct time_t  {
    u8 sec_l;
    u8 sec_h;
    u8 min_l;
    u8 min_h;
    u8 hour_l;
    u8 hour_h;
  };
  struct time_t time_struct;

  /* Alarm Structure definition */
  struct alarm_t  {
    u8 sec_l;
    u8 sec_h;
    u8 min_l;
    u8 min_h;
    u8 hour_l;
    u8 hour_h;
  };
  struct alarm_t alarm_struct;

  /* Date Structure definition */
  struct date_t{
    u8 month;
    u8 day;
    u16 year;
  };
  struct date_t date_s;

  /* Days names definition */
  string WeekDayNames[7] = {" SUN", " MON", " TUE", " WED", " THU", " FRI", " SAT"};
  /* Months names definition */
  u8 MonthNames[]= {'J', 'A', 'N', 'F', 'E', 'B', 'M', 'A', 'R', 'A', 'P', 'R',
                    'M', 'A', 'Y', 'J', 'U', 'N', 'J', 'U', 'L', 'A', 'U', 'G',
                    'S', 'E', 'P', 'O', 'C', 'T', 'N', 'O', 'V', 'D', 'E', 'C'};

  extern u8 ScreenSaveTime;     /* Counter of watchdog interrupt for screen saver */

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
* Function Name  : ReadDigit
* Description    : Reads digit entered by user, using menu navigation keys.
* Input          : None
* Output         : None
* Return         : Digit value
*******************************************************************************/
u8 ReadDigit(u8 ColBegin, u8 CountBegin, u8 ValueMax, u8 ValueMin)
{
  u8 MyKey = 0, tmpValue = 0;

  /* Wait to not detect "SEL" twice */
  Delay(0xFFFFF);
  /* Initialize tmpValue */
  tmpValue = CountBegin;
  /* Display  */
  LCD_DisplayChar(Line2, ColBegin, (tmpValue + 0x30), WhiteText);

  /* Endless loop */
  while(1)
  {	
    /* Check which key is pressed */
    MyKey = ReadKey();

    /* If "UP" pushbutton is pressed */
    if(MyKey == UP)
    {
      /* Increase the value of the digit */
      if(tmpValue == ValueMax)
      {
        tmpValue = (ValueMin - 1);
      }
      /* Display new value */
      LCD_DisplayChar(Line2, ColBegin,((++tmpValue) + 0x30) , WhiteText);
    }
    /* If "DOWN" pushbutton is pressed */
    if(MyKey == DOWN)
    {
      /* Decrease the value of the digit */
      if(tmpValue == ValueMin)
      {
        tmpValue = (ValueMax + 1);
      }
      /* Display new value */
      LCD_DisplayChar(Line2, ColBegin,((--tmpValue) + 0x30) , WhiteText);
    }
    /* If "SEL" pushbutton is pressed */
    if(MyKey == SEL)
    {
      /* Display new value */
      LCD_DisplayChar(Line2, ColBegin, (tmpValue + 0x30) , BlackText);
      /* Return the digit value and exit */
      return tmpValue;
    }
  }
}

/*******************************************************************************
* Function Name  : Calendar_Init
* Description    : Initializes calendar application.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Calendar_Init(void)
{
  /* Initialize Date structure */
  date_s.month = 01;
  date_s.day = 01;
  date_s.year = 2006;
  /* Initialize Alarm structure */
  alarm_struct.hour_h = 0;
  alarm_struct.hour_l = 0;
  alarm_struct.min_h = 0;
  alarm_struct.min_l = 0;
  alarm_struct.sec_h = 0;
  alarm_struct.sec_l = 0;
 
  /* If the system has resumed from STANDBY mode, there is no need to configure
     the RTC clock source */
  if((MRCC_GetFlagStatus(MRCC_FLAG_STDB) != RESET))
  {
    /* Clear STDB flag */
    MRCC_ClearFlag(MRCC_FLAG_STDB);
  }
  else /* Configure the RTC clock source */
  {
    /* RTC clock source configuration ----------------------------------------*/
    /* Enable OSC32K*/
    MRCC_OSC32KConfig(MRCC_OSC32K_Enable, MRCC_OSC32KBypass_Disable);
    while(MRCC_GetFlagStatus(MRCC_FLAG_OSC32KRDY) == RESET);

    /* Select OSC32K as CK_RTC clock source */
    MRCC_CKRTCConfig(MRCC_CKRTC_OSC32K);
    /* Wait for RTC clock to be ready */
    while(MRCC_GetFlagStatus(MRCC_FLAG_CKRTCOK) == RESET);
  }

  /* RTC configuration -------------------------------------------------------*/
  /* Enable RTC Clock */
  MRCC_PeripheralClockConfig(MRCC_Peripheral_RTC, ENABLE);

  /* Wait for RTC registers synchronization */
  RTC_WaitForSynchro();

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
  /* Set RTC prescaler: set RTC period to 1sec */
  RTC_SetPrescaler(32767); /* RTC period = CK_RTC/RTC_PR = (32.768 KHz)/(32767+1) */

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
  /* Enable the RTC Second and Alarm interrupt */
  RTC_ITConfig(RTC_IT_Second | RTC_IT_Alarm, ENABLE);
}

/*******************************************************************************
* Function Name  : Time_Regulate
* Description    : Returns the time entered by user, using menu vavigation keys.
* Input          : None
* Output         : None
* Return         : Current time RTC counter value
*******************************************************************************/
u32 Time_Regulate(void)
{
  u8 Tmp_HH = 0, Tmp_MM = 0, Tmp_SS = 0;

  /* Read time hours */
  Tmp_HH = ReadDigit(32, time_struct.hour_h, 0x2, 0x0);
  if(Tmp_HH == 2)
  {
    if(time_struct.hour_l > 3)
    {
      time_struct.hour_l = 0;
    }
    Tmp_HH = Tmp_HH*10 + ReadDigit(40, time_struct.hour_l, 0x3, 0x0);
  }
  else
  {
    Tmp_HH = Tmp_HH*10 + ReadDigit(40, time_struct.hour_l, 0x9, 0x0);
  }
  /* Read time  minutes */
  Tmp_MM = ReadDigit(56, time_struct.min_h,5, 0x0);
  Tmp_MM = Tmp_MM*10 + ReadDigit(64, time_struct.min_l, 0x9, 0x0);
  /* Read time seconds */
  Tmp_SS = ReadDigit(80, time_struct.sec_h,5, 0x0);
  Tmp_SS = Tmp_SS*10 + ReadDigit(88, time_struct.sec_l, 0x9, 0x0);

  /* Return the value to store in RTC counter register */
  return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));
}

/*******************************************************************************
* Function Name  : Time_Adjust
* Description    : Returns the time entered by user, using demoboard keys.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Time_Adjust(void)
{
  /* Clear Line2 */
  LCD_ClearLine(Line2);

  /* Display time separators ":" on Line2 */
  LCD_DisplayChar(Line2, 48, ':', BlackText);
  LCD_DisplayChar(Line2, 72, ':', BlackText);

  /* Display the current time */
  Time_Display(RTC_GetCounter());

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();  
  /* Change the current time */
  RTC_SetCounter(Time_Regulate());

  /* Execute UpDownFunc function to display upper menu */
  UpDownFunc();
}

/*******************************************************************************
* Function Name  : Time_Display
* Description    : Displays the current time.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Time_Display(u32 TimeVar)
{
  /* Display time hours */
  time_struct.hour_h=(u8)( TimeVar / 3600)/10;
  LCD_DisplayChar(Line2, 32,(time_struct.hour_h + 0x30) , BlackText);
  time_struct.hour_l=(u8)(((TimeVar)/3600)%10);
  LCD_DisplayChar(Line2, 40,(time_struct.hour_l + 0x30) , BlackText);

  /* Display time minutes */
  time_struct.min_h=(u8)(((TimeVar)%3600)/60)/10;
  LCD_DisplayChar(Line2, 56,(time_struct.min_h + 0x30) , BlackText);
  time_struct.min_l=(u8)(((TimeVar)%3600)/60)%10;
  LCD_DisplayChar(Line2, 64,(time_struct.min_l + 0x30) , BlackText);

  /* Display time seconds */
  time_struct.sec_h=(u8)(((TimeVar)%3600)%60)/10;
  LCD_DisplayChar(Line2, 80,(time_struct.sec_h + 0x30) , BlackText);
  time_struct.sec_l=(u8)(((TimeVar)%3600)%60)%10;
  LCD_DisplayChar(Line2, 88,(time_struct.sec_l + 0x30) , BlackText);
}

/*******************************************************************************
* Function Name  : Time_Show
* Description    : Shows the current time (HH/MM/SS) on LCD.
* Input          : None
* Output         : None
* Return         : None
******************************************************************************/
void Time_Show(void)
{
  /* Display time separators ":" on Line2 */
  LCD_DisplayChar(Line2, 48, ':', BlackText);
  LCD_DisplayChar(Line2, 72, ':', BlackText);
  /* Wait a press on "UP" or "DOWN" pushbuttons */
  while((ReadKey() & UP) != UP)
  {
    /* Display current time */
    Time_Display(RTC_GetCounter());
  }
  /* Execute UpDownFunc function to display upper menu */
  UpDownFunc();
}

/*******************************************************************************
* Function Name  : Date_Regulate
* Description    : Sets the date entered by user, using menu navigation keys.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Date_Regulate(void)
{
  u8 Tmp_Month = 0, Tmp_Day = 0, tmp = 0;
  u16 Tmp_Year = 0;

  /* Read date months */
  Tmp_Month = ReadDigit(24, date_s.month/10, 1, 0x0);
  tmp = date_s.month % 10;
  if(Tmp_Month == 1)
  {
    if(tmp > 2)
    {
      tmp = 0;
    }
    Tmp_Month = Tmp_Month*10 + ReadDigit(32, tmp, 2, 0x0);
  }
  else
  {
    Tmp_Month = Tmp_Month*10 + ReadDigit(32, tmp, 9, 0x1);
  }
  /* Read date days */
  if(Tmp_Month == 2)
  {
    Tmp_Day = ReadDigit(48, date_s.day/10, 2, 0x0);
  }
  else
  {
    Tmp_Day = ReadDigit(48, date_s.day/10, 3, 0x0);
  }
  if(Tmp_Day == 3)
  {
    tmp = date_s.day % 10;

    if(tmp >= 1)
    {
      tmp = 0;
    }

    if(Tmp_Month == 1 || Tmp_Month == 3 || Tmp_Month == 5 || Tmp_Month == 7 ||
       Tmp_Month == 8 || Tmp_Month == 10 || Tmp_Month == 12)
    {

      Tmp_Day = Tmp_Day*10 + ReadDigit(56, tmp, 1, 0x0);
    }
    else
    {
      Tmp_Day = Tmp_Day*10 + ReadDigit(56, tmp, 0, 0x0);
    }
  }
  else
  {
    if(Tmp_Day == 0)
    {
      Tmp_Day = Tmp_Day*10 + ReadDigit(56, date_s.day%10, 9, 0x1);
    }
    else
    {
      Tmp_Day = Tmp_Day*10 + ReadDigit(56, date_s.day%10, 9, 0x0);
    }
  }
  /* Read date years */
  Tmp_Year = 1000 * ReadDigit(72, date_s.year/1000, 9, 0x0);

  Tmp_Year = Tmp_Year + (ReadDigit(80, (date_s.year%1000)/100, 9, 0x0)*100);

  Tmp_Year = Tmp_Year + (ReadDigit(88,((date_s.year%1000)%100)/10, 9, 0x0)*10);

  Tmp_Year = Tmp_Year + ReadDigit(96,((date_s.year%1000)%100)%10, 9, 0x0);
  if(Tmp_Year  == 0)
  {
    /* Set year to 2006 */
    Tmp_Year = 2006;
  }
  if (Tmp_Month == 2 && Tmp_Day == 29 && (Tmp_Year % 4)!= 0)
  {
    Tmp_Day = 28;
  }
  /* Return the date value to store in date structure */
  date_s.year = Tmp_Year;
  date_s.month = Tmp_Month;
  date_s.day = Tmp_Day;
}

/*******************************************************************************
* Function Name  : Date_Adjust
* Description    : Adjusts the current date (MM/DD/YYYY).
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Date_Adjust(void)
{
  /* Clear Line2 */
  LCD_ClearLine(Line2);

  /* Display the current date */
  Date_Display(1);

  /* Change the current date */
  Date_Regulate();

  /* Execute UpDownFunc function to display upper menu */
  UpDownFunc();
}

/*******************************************************************************
* Function Name  : Date_Display
* Description    : Displays the current date.
* Input          : - Col: specifies the start column from where the date will
*                    be displayed.
*                : - Row: specifies the line where the date will be displayed.
*                : - Type: specifies the date format. If Type = 1 then show
*                    (MM/DD/YYYY) else (MM/DD/YY).
* Output         : None
* Return         : None
*******************************************************************************/
void Date_Display(u8 Type)
{
  /* Display date separators "/" on Line2 */
  LCD_DisplayChar(Line2, 40, '/', BlackText);
  LCD_DisplayChar(Line2, 64, '/', BlackText);
  /* Display date months */
  LCD_DisplayChar(Line2, 24, ((date_s.month/10) + 0x30), BlackText);
  LCD_DisplayChar(Line2, 32, ((date_s.month%10) + 0x30), BlackText);
  /* Display date days */
  LCD_DisplayChar(Line2, 48, ((date_s.day/10) + 0x30), BlackText);
  LCD_DisplayChar(Line2, 56, ((date_s.day%10) + 0x30), BlackText);

  /* If type=1: display YYYY year */
  if(Type == 1)
  {
    LCD_DisplayChar(Line2, 72, ((date_s.year/1000) + 0x30), BlackText);
    LCD_DisplayChar(Line2, 80, (((date_s.year%1000)/100) + 0x30), BlackText);
    LCD_DisplayChar(Line2, 88, (((date_s.year%1000)%100)/10 + 0x30), BlackText);
    LCD_DisplayChar(Line2, 96, (((date_s.year%1000)%10)%10 + 0x30), BlackText);

  }
  /* If type=0: display YY year */
  else
  {
    LCD_DisplayChar(Line2, 72, (((date_s.year%1000)%100)/10 + 0x30), BlackText);
    LCD_DisplayChar(Line2, 80, (((date_s.year%1000)%10)%10 + 0x30), BlackText);
  }
}

/*******************************************************************************
* Function Name  : Date_Show
* Description    : Shows date (MM/DD/YYYY) on LCD.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Date_Show (void)
{
  /* Clear Line2 */
  LCD_ClearLine(Line2);
  /* Wait a press on "UP" or "DOWN" pushbuttons */
  while((ReadKey() & UP) != UP)
  {
    LCD_DisplayString(Line2, WeekDayNames[DayOfWeek(date_s.year, date_s.month, date_s.day)], BlackText);
    LCD_DisplayChar(Line2, 35, MonthNames[(((date_s.month) -1) * 3)], BlackText);
    LCD_DisplayChar(Line2, 42, MonthNames[((((date_s.month) -1) * 3) + 1)], BlackText);
    LCD_DisplayChar(Line2, 49, MonthNames[((((date_s.month) -1) * 3) + 2)], BlackText);
    LCD_DisplayChar(Line2, 63, ((date_s.day/10) + 0x30), BlackText);
    LCD_DisplayChar(Line2, 70, ((date_s.day%10) + 0x30), BlackText);
    LCD_DisplayChar(Line2, 84, ((date_s.year/1000) + 0x30), BlackText);
    LCD_DisplayChar(Line2, 91, (((date_s.year%1000)/100) + 0x30), BlackText);
    LCD_DisplayChar(Line2, 98, (((date_s.year%1000)%100)/10 + 0x30), BlackText);
    LCD_DisplayChar(Line2, 105, (((date_s.year%1000)%10)%10 + 0x30), BlackText);
  }
  /* Execute UpDownFunc function to display upper menu */
  UpDownFunc();
}

/*******************************************************************************
* Function Name  : Date_Update
* Description    : Updates date when time is 23:59:59.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Date_Update(void)
{
  if(date_s.month == 1 || date_s.month == 3 || date_s.month == 5 || date_s.month == 7 ||
     date_s.month == 8 || date_s.month == 10 || date_s.month == 12)
  {
    if(date_s.day < 31)
    {
      date_s.day++;
    }
    /* Date structure member: date_s.day = 31 */
    else
    {
      if(date_s.month != 12)
      {
        date_s.month ++;
        date_s.day = 1;
      }
      /* Date structure member: date_s.day = 31 & date_s.month =12 */
      else
      {
        date_s.month = 1;
        date_s.day = 1;
        date_s.year++;
      }
    }
  }
  else if(date_s.month == 4 || date_s.month == 6 || date_s.month == 9 ||
          date_s.month == 11)
  {
    if(date_s.day < 30)
    {
      date_s.day++;
    }
    /* Date structure member: date_s.day = 30 */
    else
    {
      date_s.month++;
      date_s.day = 1;
    }
  }
  else if(date_s.month == 2)
  {
    if(date_s.day < 28)
    {
      date_s.day++;
    }
    else if(date_s.day == 28)
    {
      /* Leap year */
      if(date_s.year%4 == 0)
      {
        date_s.day++;
      }
      else
      {
        date_s.month++;
        date_s.day = 1;
      }
    }
    else if(date_s.day == 29)
    {
      date_s.month++;
      date_s.day = 1;
    }
  }
}

/*******************************************************************************
* Function Name  : Alarm_Regulate
* Description    : Returns the alarm time entered by user, using demoboard keys.
* Input          : None
* Output         : None
* Return         : Alarm time value to be loaded in RTC alarm register.
*******************************************************************************/
u32 Alarm_Regulate(void)
{
  u8 Alarm_HH = 0, Alarm_MM = 0, Alarm_SS = 0;

  /* Read alarm hours */
  Alarm_HH = ReadDigit(32, alarm_struct.hour_h, 0x2, 0x0);

  if(Alarm_HH == 0x2)
  {
    if(alarm_struct.hour_l > 0x3)
    {
      alarm_struct.hour_l = 0x0;
    }
    Alarm_HH = Alarm_HH*10 + ReadDigit(40, alarm_struct.hour_l, 0x3, 0x0);
  }
  else
  {
    Alarm_HH = Alarm_HH*10 + ReadDigit(40, alarm_struct.hour_l, 0x9, 0x0);
  }

  /* Read alarm minutes */
  Alarm_MM = ReadDigit(56, alarm_struct.min_h, 0x5, 0x0);
  Alarm_MM = Alarm_MM*10 + ReadDigit(64, alarm_struct.min_l, 0x9, 0x0);

  /* Read alarm seconds */
  Alarm_SS = ReadDigit(80, alarm_struct.sec_h, 0x5, 0x0);
  Alarm_SS = Alarm_SS*10 + ReadDigit(88, alarm_struct.sec_l, 0x9, 0x0);
  /* Return the alarm value to store in the RTC Alarm register */
  return((Alarm_HH*3600 + Alarm_MM*60 + Alarm_SS));
}

/*******************************************************************************
* Function Name  : Alarm_Adjust
* Description    : Configures an alarm event to occurs within the current day.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Alarm_Adjust(void)
{
  u32 Tmp = 0;

  /* Clear LCD Line2 */
  LCD_ClearLine(Line2);

  /* Read the alarm value stored in the Backup register */
  Tmp = MRCC_ReadBackupRegister(MRCC_BKP0);
  /* Display alarm separators ":" on Line2 */
  LCD_DisplayChar(Line2, 48, ':', BlackText);
  LCD_DisplayChar(Line2, 72, ':', BlackText);

  /* Display the alarm value */
  Alarm_Display(Tmp);
  /* Store new alarm value */
  Tmp = Alarm_Regulate();

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
  /* Set RTC Alarm register with the new value */
  RTC_SetAlarm(Tmp);

  /* Save the Alarm value in the Backup register */
  MRCC_WriteBackupRegister(MRCC_BKP0, Tmp);
  /* Execute UpDownFunc function to display upper menu */
  UpDownFunc();
}

/*******************************************************************************
* Function Name  : Alarm_Display
* Description    : Displays alarm time.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Alarm_Display(u32 AlarmVar)
{
  /* Display alarm hours */
  alarm_struct.hour_h=(u8)( AlarmVar / 3600)/10;
  LCD_DisplayChar(Line2, 32,(alarm_struct.hour_h + 0x30) , BlackText);

  alarm_struct.hour_l=(u8)(((AlarmVar)/3600)%10);
  LCD_DisplayChar(Line2, 40,(alarm_struct.hour_l + 0x30) , BlackText);

  /* Display alarm minutes */
  alarm_struct.min_h=(u8)(((AlarmVar)%3600)/60)/10;
  LCD_DisplayChar(Line2, 56,(alarm_struct.min_h + 0x30) , BlackText);

  alarm_struct.min_l=(u8)(((AlarmVar)%3600)/60)%10;
  LCD_DisplayChar(Line2, 64,(alarm_struct.min_l + 0x30) , BlackText);

  /* Display alarm seconds */
  alarm_struct.sec_h=(u8)(((AlarmVar)%3600)%60)/10;
  LCD_DisplayChar(Line2, 80,(alarm_struct.sec_h + 0x30) , BlackText);

  alarm_struct.sec_l=(u8)(((AlarmVar)%3600)%60)%10;
  LCD_DisplayChar(Line2, 88,(alarm_struct.sec_l + 0x30) , BlackText);
}

/*******************************************************************************
* Function Name  : Alarm_Show
* Description    : Shows alarm time (HH/MM/SS) on LCD.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Alarm_Show(void)
{
  u32 Tmp = 0;

  /* Display alarm separators ":" on Line2 */
  LCD_DisplayChar(Line2, 48, ':', BlackText);
  LCD_DisplayChar(Line2, 72, ':', BlackText);
  /* Get the actual alarm value */
  Tmp = MRCC_ReadBackupRegister(MRCC_BKP0);
  /* Wait a press on "UP" or "DOWN" pushbuttons */
  while((ReadKey() & UP) != UP)
  {
    /* Display actual alarm value */
    Alarm_Display(Tmp);
  }
  /* Execute UpDownFunc function to display upper menu */
  UpDownFunc();
}

/*******************************************************************************
* Function Name  : Alarm_Check
* Description    : Check if an alarm was occured or not during STOP or STANDBAY
*                  modes.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Alarm_Check(void)
{
  /* Compare the counter value saved just after STOP or STANDBY mode entrence (BKP1) */
  /* with the actual alarm value */
  if(MRCC_ReadBackupRegister(MRCC_BKP1) < MRCC_ReadBackupRegister(MRCC_BKP0))
  {
    /* Compare the actual time and alarm value */
    if(RTC_GetCounter() > MRCC_ReadBackupRegister(MRCC_BKP0))
    {
      /* Display the missed alarm message */
      LCD_DisplayString(Line1, "One missed Alarm ", BlackText);
      LCD_DisplayString(Line2, " Exit: Press SEL ", BlackText);
      /* Wait a press on "SEL" pushbutton */
      while(ReadKey() != SEL);
      /* Display the actual menu */
      DisplayMenu();
    }
  }
}

/*******************************************************************************
* Function Name  : DayOfWeek
* Description    : Return the number of the day in the week.
* Input          : None
* Output         : None
* Return         : The number of the day
*******************************************************************************/
u16 DayOfWeek(u16 nYear, u16 nMonth, u16 nDay)
{
  u16 nDayOfWeek = 0;
  u16 pnDaysBeforeMonth[14] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
	 	
  /* The day of Jan 1, nYear */
  nDayOfWeek = 6 + nYear % 7 + CountOfFeb29(nYear) % 7 + 14; /* + 14 : makes nDayOfWeek >= 0 */
	
  /* The day of nMonth 1, nYear */
  nDayOfWeek += pnDaysBeforeMonth[ nMonth ];
  if( nMonth > 2 && IsLeapYear(nYear))	
  {
    nDayOfWeek++;
  }

  /* The day of nMonth nDay, nYear */
  nDayOfWeek += nDay - 1;
  nDayOfWeek %= 7;
  /* return the number of the day in the week */	
  return nDayOfWeek;
}

/*******************************************************************************
* Function Name  : CountOfFeb29
* Description    : Return february days number.
* Input          : None
* Output         : None
* Return         : February days number.
*******************************************************************************/
u16 CountOfFeb29(u16 nYear)
{
  u16 nCount = 0;

  if(nYear > 0)
  {
    nCount = 1;	/* Year 0 is a leap year */
    nYear--;    /* Year nYear is not in the period */
  }
  nCount += nYear / 4 - nYear / 100 + nYear / 400;
  return nCount;
}

/*******************************************************************************
* Function Name  : IsLeapYear
* Description    : Check whether the passed year is Leap or not.
* Input          : None
* Output         : None
* Return         : TRUE: leap year
*                  FALSE: not leap year
*******************************************************************************/
bool IsLeapYear(u16 nYear)
{
  if(nYear % 4 != 0) return FALSE;
  if(nYear % 100 != 0) return TRUE;
  return (bool)(nYear % 400 == 0);
}

/*******************************************************************************
* Function Name  : ScreenSaver_Init
* Description    : Initializes the demonstration screen saver mode. The screen
*                  saver mode is entered if any of menu navigation keys are not
*                  pressed during 30 second and it is managed in the WDG interrupt
*                  handler routine.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ScreenSaver_Init(void)
{
  /* Configure the WDG to generate an interrupt each 0.86s */
  WDG_InitStructure.WDG_Mode = WDG_Mode_Timer;
  WDG_InitStructure.WDG_Prescaler = 0xFF;
  WDG_InitStructure.WDG_Preload =  0xFFFF;
  WDG_Init(&WDG_InitStructure);
  /* Enable WDG EOC interrupt */
  WDG_ITConfig(ENABLE);
  /* Enable WDG peripheral */
  WDG_Cmd(ENABLE);
}

/*******************************************************************************
* Function Name  : ScreenSaver_Show
* Description    : Displays screen saver: ST logo, time and date.
* Input          : None
* Output         : None
* Return         : None
******************************************************************************/
void ScreenSaver_Show(void)
{
  u32 TimeVar = 0;

  /* Disable screen saver mode */
  WDG_Cmd(DISABLE);

  /* Display ST Logo */
  LCD_DrawMasterGraphic(STLogo61);
  /* Display date separators */
  LCD_DisplayChar(Line1, 77, '/', BlackText);
  LCD_DisplayChar(Line1, 98, '/', BlackText);
  /* Display time separators */
  LCD_DisplayChar(Line2, 77, ':', BlackText);
  LCD_DisplayChar(Line2, 98, ':', BlackText);
  /* Endless loop */
  while(1)
  {
    /* If no key is pressed */
    if(ReadKey() != NOKEY)
    {
      /* Enable screen saver mode */
      ScreenSaver_Cmd(ENABLE);
      /* Exit from screen saver mode */
      return;
    }
    /* Get instantanously the RTC counter register value */
    TimeVar = RTC_GetCounter();

    /* Display the current date */
    LCD_DisplayChar(Line1, 63, ((date_s.month/10) + 0x30), BlackText);
    LCD_DisplayChar(Line1, 70, ((date_s.month%10) + 0x30), BlackText);
    LCD_DisplayChar(Line1, 84, ((date_s.day/10) + 0x30), BlackText);
    LCD_DisplayChar(Line1, 91, ((date_s.day%10) + 0x30), BlackText);
    LCD_DisplayChar(Line1, 105, (((date_s.year%1000)%100)/10 + 0x30), BlackText);
    LCD_DisplayChar(Line1, 112, (((date_s.year%1000)%10)%10 + 0x30), BlackText);

    /* Display the current time */
    /* Display hours */
    time_struct.hour_h=(u8)( TimeVar / 3600)/10;
    LCD_DisplayChar(Line2, 63,(time_struct.hour_h + 0x30) , BlackText);
    time_struct.hour_l=(u8)(((TimeVar)/3600)%10);
    LCD_DisplayChar(Line2, 70,(time_struct.hour_l + 0x30) , BlackText);
    /* Display minutes */
    time_struct.min_h=(u8)(((TimeVar)%3600)/60)/10;
    LCD_DisplayChar(Line2, 84,(time_struct.min_h + 0x30) , BlackText);
    time_struct.min_l=(u8)(((TimeVar)%3600)/60)%10;
    LCD_DisplayChar(Line2, 91,(time_struct.min_l + 0x30) , BlackText);
    /* Display seconds */
    time_struct.sec_h=(u8)(((TimeVar)%3600)%60)/10;
    LCD_DisplayChar(Line2, 105,(time_struct.sec_h + 0x30) , BlackText);
    time_struct.sec_l=(u8)(((TimeVar)%3600)%60)%10;
    LCD_DisplayChar(Line2, 112,(time_struct.sec_l + 0x30) , BlackText);	
  }
}

/*******************************************************************************
* Function Name  : ScreenSaver_Cmd
* Description    : Enables or disables screen saver mode
* Input          : None
* Output         : None
* Return         : None
******************************************************************************/
void ScreenSaver_Cmd(FunctionalState NewState)
{
  if(NewState == ENABLE)
  {
    /* Enable watchdog */
    WDG_Cmd(ENABLE);
  }
  else
  {
    /* Disable watchdog */
    WDG_Cmd(DISABLE);
    /* Reset ScreenSaveTime counter to count new 30sec */
    ScreenSaveTime = 0;

  }
}

/******************* (C) COPYRIGHT 2006 STMicroelectronics *****END OF FILE****/
