/* Setup of the operating parameters with LCD menu */
/* $Id: setup.c,v 1.2 2001/08/31 16:13:48 leon Exp leon $ */

#pragma SYMBOLS

#include <reg515.h>
#include "setup.h"
#include "display.h"
#include "ds1307.h"
#include "serial.h"

#define TEST_MESSAGE_TIME 1000

/* Setup  parameters */
unsigned long burner_seconds;
unsigned int idata solar_pump_minutes;
int idata boiler_min_temp;
int idata boiler_max_temp;
int idata hot_water_min_temp;
int idata hot_water_max_temp;
int idata underfloor_temp[4];
int idata temperature_slope; /* underfloor temperature slope correction neg. */
int idata night_temp_offset; /* negative temperature offset at night times */
unsigned char idata night_begin; /* minutes/6 for the start of night regime */
unsigned char idata night_end;   /* minutes/6 for the end */


sbit SECONDS_SOURCE   = 0xB2; /* P3.2 DS1307 1Hz clock */


unsigned char bdata operating_flags;
sbit burner_enabled = operating_flags ^ 0;
sbit display_solar_temperatures = operating_flags ^ 1;
sbit display_blanking_enabled = operating_flags ^ 2;
sbit vacation = operating_flags ^ 3;

unsigned char bdata pump_enabled;
sbit hot_water_pump_enabled   = pump_enabled ^ 0;
sbit underfloor_pump0_enabled = pump_enabled ^ 1;
sbit underfloor_pump1_enabled = pump_enabled ^ 2; 
sbit underfloor_pump2_enabled = pump_enabled ^ 3;
sbit underfloor_pump3_enabled = pump_enabled ^ 4;
sbit circulator_pump_enabled  = pump_enabled ^ 5;
sbit solar_pump_enabled       = pump_enabled ^ 6;
sbit inter_tank_pump_enabled  = pump_enabled ^ 7;

unsigned char idata circulator_start_time[8]; /* (minutes from midnigth)/6 */
unsigned char idata circulator_duration;      /* in minutes */
int idata max_solar_temperature; /* in solar DHW */
int idata collector_temp_difference; /* between collector and heat exchanger */
int idata inter_tank_temp_difference;  /* min difference + 3K hysteresis */

void
set_defaults()
{
  boiler_min_temp = 4500;
  boiler_max_temp = 7500;
  hot_water_min_temp = 5000;
  hot_water_max_temp = 6000;
  underfloor_temp[0] = 2200;
  underfloor_temp[1] = 2400;
  underfloor_temp[2] = 2400;
  underfloor_temp[3] = 2300;
  temperature_slope = 25;
  pump_enabled = 0xff; /* all pumps enabled */
  circulator_start_time[0] =  60;  /*  6:00 get up */ 
  circulator_start_time[1] =  65;  /*  6:30 brush teeth me */
  circulator_start_time[2] =  71;  /*  7:06 brush teeth kids */
  circulator_start_time[3] = 110;  /* 11:00 start cooking */
  circulator_start_time[4] = 145;  /* 14:30 dish cleaner */   
  circulator_start_time[5] = 189;  /* 18:54 kids bath  */
  circulator_start_time[6] = 195;  /* 19:30 wash face */ 
  circulator_start_time[7] = 240;  /* off (spare) */
  circulator_duration = 3;
  night_temp_offset = 200;
  night_begin = 215; /* 21:30 */
  night_end = 50;     /* 5:00 */
  max_solar_temperature = 9800;
  collector_temp_difference = 700;
  inter_tank_temp_difference = 600;
  burner_enabled = 0;
  display_solar_temperatures = 1;
  display_blanking_enabled = 1;
  vacation = 0; /* Nightly cooling of solar tank */

}


static bit
parameters_range_check(void)
{
#define RANGE_CHECK(pmin, pmax, lo, hi) \
  (pmin >= pmax || pmin < lo || pmax > hi)

  if (   RANGE_CHECK(boiler_min_temp, boiler_max_temp, 4000, 9500)
                 || RANGE_CHECK(hot_water_min_temp, hot_water_max_temp, 3000, 7000) 
                 || underfloor_temp[0] < 0 || underfloor_temp[0] > 4500
                 || underfloor_temp[1] < 0 || underfloor_temp[1] > 4500
                 || underfloor_temp[2] < 0 || underfloor_temp[2] > 4500
                 || underfloor_temp[3] < 0 || underfloor_temp[3] > 4500
                 || temperature_slope < 0 || temperature_slope > 200
                 || circulator_duration == 0 || circulator_duration > 30
                 || night_temp_offset < 0 || night_temp_offset > 1000
                 || night_end > night_begin
                 || max_solar_temperature < 4000
                 || collector_temp_difference > 1500
                 || inter_tank_temp_difference < 100
                 || inter_tank_temp_difference > 3000)
    return 1;
  return 0;
}


/* CCIT 16-bit */
static unsigned int idata crc;

static void 
crc16(unsigned char ser_data)
{
  WDT = 1; /* reset the watch dog timer. CRC is overkill*/
  SWDT = 1;
  crc = (unsigned char) (crc >> 8) | (crc << 8);
  crc ^= ser_data;
  crc ^= (unsigned char) (crc & 0xff) >> 4;
  crc ^= (crc << 8) << 4;
  crc ^= ((crc & 0xff) << 4) << 1;
}




#define CRC16I(x) crc16(*((unsigned char *)&x)); \
                  crc16(*(((unsigned char *)&x)+1))

#define PARAMETERS_START_ADDRESS 0x0e
static void
save_parameters() /* into NVRAM */
{
  unsigned char address = PARAMETERS_START_ADDRESS;
  
  unsigned char i;

  crc = 0xdead;

#define SAVE_INT_PARAM(x) ds1307_set_int(address, x);  CRC16I(x); address += 2
#define SAVE_BYTE_PARAM(x)  ds1307_set_byte(address++, x); crc16(x)
  SAVE_INT_PARAM(boiler_min_temp);
  SAVE_INT_PARAM(boiler_max_temp);
  SAVE_INT_PARAM(hot_water_min_temp);
  SAVE_INT_PARAM(hot_water_max_temp);
  SAVE_INT_PARAM(underfloor_temp[0]);
  SAVE_INT_PARAM(underfloor_temp[1]);
  SAVE_INT_PARAM(underfloor_temp[2]);
  SAVE_INT_PARAM(underfloor_temp[3]);
  SAVE_INT_PARAM(temperature_slope);
  SAVE_INT_PARAM(night_temp_offset);
  SAVE_INT_PARAM(max_solar_temperature);
  SAVE_INT_PARAM(collector_temp_difference);
  SAVE_INT_PARAM(inter_tank_temp_difference);
  SAVE_BYTE_PARAM(night_begin);
  SAVE_BYTE_PARAM(night_end);
  for (i = 0; i < 8; i++)
        SAVE_BYTE_PARAM(circulator_start_time[i]);
  SAVE_BYTE_PARAM(circulator_duration);
  SAVE_BYTE_PARAM(operating_flags);
  SAVE_BYTE_PARAM(pump_enabled);
  ds1307_set_int(address, crc);
}

/*  Memory Map of the 56 bytes in the DS1307

        TODO

    0x08, 0x09, 0x0A, 0x0B : (ulong) burner_seconds burner working time counter
    0x0C, 0x0D             : (int) boiler minimal temp
    0x0E, 0x0F             : (int) boiler maximal temp
    0x10, 0x11             : (int) hot water container min temp
    0x12, 0x13             : (int) hot water container max temp
    0x14                   : (unsigned char) operating flags
    0x15, 0x16             : (int) circuit 0 temperature
    0x17, 0x18             : (int) circuit 1 temperature
    0x19, 0x1A             : (int) circuit 2 temperature
    0x1B, 0x1C             : (int) circuit 3 temperature
        0x1D, 0x1E             : (unsigned int) CRC 16 bit from 0x0C
    0x1F .. 0x3F           : spare

        circuit night temperature offset
        solar container max temperature
        solar pump delta temperature
        container circulator delta temperature
        DHW circulator times
 */


void 
load_parameters()
{
  unsigned int last_crc;
  unsigned char address = PARAMETERS_START_ADDRESS;
  unsigned char i;
  crc = 0xdead;
#define LOAD_BYTE_PARAM(x) x = ds1307_get_byte(address++); crc16(x);
#define LOAD_INT_PARAM(x) x = ds1307_get_int(address); CRC16I(x); address += 2
  LOAD_INT_PARAM(boiler_min_temp);
  LOAD_INT_PARAM(boiler_max_temp);
  LOAD_INT_PARAM(hot_water_min_temp);
  LOAD_INT_PARAM(hot_water_max_temp);
  LOAD_INT_PARAM(underfloor_temp[0]);
  LOAD_INT_PARAM(underfloor_temp[1]);
  LOAD_INT_PARAM(underfloor_temp[2]);
  LOAD_INT_PARAM(underfloor_temp[3]);
  LOAD_INT_PARAM(temperature_slope);
  LOAD_INT_PARAM(night_temp_offset);
  LOAD_INT_PARAM(max_solar_temperature);
  LOAD_INT_PARAM(collector_temp_difference);
  LOAD_INT_PARAM(inter_tank_temp_difference);
  LOAD_BYTE_PARAM(night_begin);
  LOAD_BYTE_PARAM(night_end);
  for (i = 0; i < 8; i++)
        LOAD_BYTE_PARAM(circulator_start_time[i]);
  LOAD_BYTE_PARAM(circulator_duration);
  LOAD_BYTE_PARAM(operating_flags);
  LOAD_BYTE_PARAM(pump_enabled);
  last_crc = ds1307_get_int(address);

  if (last_crc != crc || parameters_range_check()) /* CRC16 match test */
    {
      icm_error(29);
      if (confirm_dialog("Nalo\03im za\01etne \nnastavitve?     "))
                {
                  set_defaults();
                  save_parameters();
                }
    }
}


void 
delay(unsigned int n)
{
    while(n--) 
      {
                WDT = 1;
                SWDT = 1;
      }
}        


static void
debounce_keys(void)        
{
  int i = 0;

  while (i++ < 3000) /* release the key before answer with debounce*/
    {
      if (!KEY_UP || !KEY_DOWN || !KEY_YES || !KEY_NO)
                i = 0;
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;
    }
}

/* Dialog message shifts display left for 16 chars and prints
   the question. Previous display is then restored! */
bit 
confirm_dialog(const char code *question)
{
  unsigned char i;
  
  lcd_send(0, 0x90); /* move cursor to first line (shifted) */

  for (i = 0; i < 16; i++)
    lcd_send(0, 0x18); /* shift display left */


  i = 0;
  while(question[i])
    {
      if (question[i] == '\n')
        {
          lcd_send(0, 0x80+0x50); /* new line */
          i++;
          continue;
        }
      lcd_send(1, question[i++]);
    }

  debounce_keys();
  while (1)
    {
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;      

      if (!KEY_YES)
                {
                  lcd_send(0, 0x02); /* cursor home and shift restore */
                  debounce_keys();
                  return 1;
                }

      if (!KEY_NO)
                {
                  lcd_send(0, 0x02); /* cursor home and shift restore */
                  debounce_keys();
                  return 0;
                }
    }
  return 0;
}

static void
timed_message(char code *message, unsigned int time)
{
  unsigned char i;

  lcd_send(0, 0x90); /* move cursor to first line (shifted) */

  for (i = 0; i < 16; i++)
    lcd_send(0, 0x18); /* shift display left */

  i = 0;
  while(message[i])
    {
      if (message[i] == '\n')
        {
          lcd_send(0, 0x80+0x50); /* new line */
          i++;
          continue;
        }
      lcd_send(1, message[i++]);
    }
  while(time--)
    {
      for (i = 0; i < 200; i++)
                {
                  WDT = 1; /* reset the watch dog timer */
                  SWDT = 1;      
                }
    }      
  lcd_send(0, 0x02); /* cursor home and shift restore */
}

  


static void test_processor_clock(void)
{
  unsigned  int  i;
  

  i = 0;
  
  EAL = 0;
  do
        {
          WDT = 1; /* reset the watch dog timer */
          SWDT = 1;
        }
  while(!SECONDS_SOURCE); /* wait HI */ ;
  do
        {
          WDT = 1; /* reset the watch dog timer */
          SWDT = 1;
        }
  while(SECONDS_SOURCE); /* wait LO */ ;
  
  do
        {
          WDT = 1; /* 1T */
          SWDT = 1; /* 1T */
          i++; /* 1T+1T+ 2T + (1T) */
        }
  while(!SECONDS_SOURCE); /* 2 T */
  
  EAL = 1;
  
  lcd_print("Processor clock \n                ");
  lcd_print_ulong(0x4A, ((unsigned long)i*8UL + (unsigned long)i/256UL)
                                  * 24UL);
}

        
  


static void test_ram(void)
{
  unsigned char xdata *p = 0;
  lcd_print("Testing RAM ... \n                ");
  while (p < 0x8000)
        {
          *p = 0x00;
          p++;  /* Ouch this was optimized! */
          p--;
          if ((unsigned int)p % 16 == 0) /* printout is slow ! */
                lcd_print_ulong(0x4A, (unsigned long)p);          
          if (*p != 0x00)
                {
                  lcd_print_ulong(0x4A, (unsigned long)p);
                  halt(70, "RAM fault x00 at");
                }
          *p = 0xFF;
          p++;
          p--;
          if (*p != 0xFF)
                {
                  lcd_print_ulong(0x4A, (unsigned long)p);
                  halt(71, "RAM fault xFF at");
                }
          p++;
          WDT = 1; /* reset the watch dog timer */
          SWDT = 1;
        }
  timed_message("32 kilobytes of\nSTATIC RAM OK! ", TEST_MESSAGE_TIME); 
}


static void
clock_setup(void)
{
  char i;
  char day_of_week, hours, minutes, year, month, date, state;
  char code *day_names = " Error DayOfWeek"
                         " ponedeljek    >"
                         " torek         >"
                         " sreda         >"
                         " \01etrtek       >"
                         " petek         >"
                         " sobota        >"
                         " nedelja       >";

  hours = ds1307_get_bcd_hours(); BCD_TO_DECIMAL(hours); 
  minutes = ds1307_get_bcd_minutes(); BCD_TO_DECIMAL(minutes);
  day_of_week = ds1307_get_byte(3) & 0x07; 
  date = ds1307_get_byte(4) & 0x3f; BCD_TO_DECIMAL(date);
  month = ds1307_get_byte(5) & 0x3f; BCD_TO_DECIMAL(month); 
  year = ds1307_get_byte(6); BCD_TO_DECIMAL(year);

  lcd_send(0, 0x90); /* move cursor to first line (shifted) */
  
  for (i = 0; i < 16; i++)
    lcd_send(0, 0x18); /* shift display left */
  
  for(i = 0; i < 16; i++)
    lcd_send(1, day_names[day_of_week * 16 + i]);
# define LCD_SEND_2(x) lcd_send(1,((x)/10) + '0'); lcd_send(1,((x)%10) + '0')

  lcd_send(0, 0x80 + 0x50);
  LCD_SEND_2(year); lcd_send(1, '-');  LCD_SEND_2(month);
  lcd_send(1, '-'); LCD_SEND_2(date);  lcd_send(1, ' ');
  LCD_SEND_2(hours); lcd_send(1, ':'); LCD_SEND_2(minutes);
  lcd_send(1, ' ');  lcd_send(1, ' ');

  lcd_send(0, 0x90); /* move cursor to the first line (shifted) */
#if 0  
  lcd_send(0, 0x0f); /* blink the cursor */
#endif
  debounce_keys();

  state = 0;
#define CHANGE_VARIABLE(var, lo, hi)  if (!KEY_UP) var++; else var--;\
  if (var > hi) var = lo; if (var < lo) var = hi

  while (1)
    {
      if (!KEY_UP|| !KEY_DOWN)
                {
                  switch (state)
                        {
                        case 0:
                          CHANGE_VARIABLE(day_of_week, 1, 7);
                          for(i = 0; i < 16; i++)
                                lcd_send(1, day_names[day_of_week * 16 + i]);
                          lcd_send(0, 0x90); /* move cursor to the first line (shifted) */
                          break;
                        case 1:
                          CHANGE_VARIABLE(year, 0, 99);
                          LCD_SEND_2(year);
                          lcd_send(0, 0x80 + 0x50);              
                          break;
                        case 2:
                          CHANGE_VARIABLE(month, 1, 12);
                          LCD_SEND_2(month);
                          lcd_send(0, 0x80 + 0x53);              
                          break;
                        case 3:
                          CHANGE_VARIABLE(date, 1, 31);
                          LCD_SEND_2(date);
                          lcd_send(0, 0x80 + 0x56);              
                          break;
                        case 4:
                          CHANGE_VARIABLE(hours, 0, 23);
                          LCD_SEND_2(hours);
                          lcd_send(0, 0x80 + 0x59);              
                          break;
                        case 5:
                          CHANGE_VARIABLE(minutes, 0, 59);
                          LCD_SEND_2(minutes);
                          lcd_send(0, 0x80 + 0x5c);              
                          break;
                        }
                  debounce_keys();
                }
          
      if (!KEY_YES)
                break;
      
      if (!KEY_NO)
                {
                  state++;
                  if (state > 5)
                        state = 0;
                  debounce_keys();
                  if (state)
                        lcd_send(0, (0x80 | 0x50) + (state - 1)*3);
                  else
                        lcd_send(0, 0x90);
                }
          
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;      
    }
  
  ds1307_set_date_time(year, month, date, hours, minutes, day_of_week);
#if 0
  ds1307_set_date_time(year, month, date, hours, minutes, day_of_week);
  lcd_send(0, 0x0c); /* disable cursor */
#endif
  lcd_send(0, 0x02); /* cursor home and shift restore */

}



static void
show_main_menu_icons(void)
{
  lcd_cgram_symbols_init();
  lcd_print("\001 \005 \002 \003 \004 \006 i");
  lcd_send(0, 0x0d); /* blink on */
}

static void
show_main_menu(char menu_number)
{
  unsigned char i;
  char code *main_menu_text = {
    "1.Kotel         "
    "2.Hranilnik TV  "
    "3.Cirkulacija TV"
    "4.Talno gretje  "
    "5.Solarni sklop "
    "6.Nastavitve    "
    "7.Informacije   "
  };
  
  main_menu_text += 16 * menu_number;
  lcd_send(0,0x80|0x40); /* second row */
  for (i = 0; i < 16 ; i++)
        lcd_send(1, *(main_menu_text++));
  lcd_send(0, 0x80 + menu_number * 2);
  
}

#define KEY_DELAY_TIME 20000

/* With negative selected no radio buttons are shown */
static void
show_option(char code *text, char start_line, char selected,
                        bit cursor_at_home, bit show_options)
{
  char i;

  text += 16 * start_line;
  lcd_send(0, 0x80);
  for (i = 0; i < 16; i++)
        lcd_send(1, *(text++));
  lcd_send(0, 0xc0);
  if (*text)
        for (i = 0; i < 16; i++)
          lcd_send(1, *(text++));
  else
        for (i = 0; i < 16; i++)
          lcd_send(1, '-');

  if (show_options)
        {

          lcd_send(0, 0x8f); /* move to 15th char pos. */
          if (start_line == selected)
                lcd_send(1, '\x07');
          else
                lcd_send(1, '\x08');
          lcd_send(0, 0xcf);
          if (start_line + 1 == selected)
                lcd_send(1, '\x07');
          else
                lcd_send(1, '\x08');
        }

  if (cursor_at_home)
        lcd_send(0, 0x80);
  else
        lcd_send(0, 0xc0);
  
}

  
static bit
select_option(char code *text, char *start_line, char *selected,
                          bit cursor_at_home, bit show_options) 
{
  char options;
  char code *p = text;
  unsigned int key_delay;

  while(*p)
        p++;

  options = (p - text)/16;
  
  show_option(text, *start_line, *selected, cursor_at_home, show_options);
  debounce_keys();

  while(1)
        {
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;

      if (key_delay)
                {
                  key_delay --;
                  continue;
                }

          if (!KEY_DOWN)
                {
                  if (!cursor_at_home && *start_line < options - 2)
                        {
                          (*start_line) ++;
                          show_option(text, *start_line, *selected,
                                                  cursor_at_home, show_options);
                        }
                  else
                        cursor_at_home = 0;
                  lcd_send(0, 0xc0);
                  key_delay = KEY_DELAY_TIME;
                }

          if (!KEY_UP)
                {
                  if (cursor_at_home && *start_line > 0)
                        {
                          (*start_line) --;
                          show_option(text, *start_line, *selected,
                                                  cursor_at_home, show_options);
                        }
                  else
                        cursor_at_home = 1;
                  lcd_send(0, 0x80);
                  key_delay = KEY_DELAY_TIME;
                }

          if(!KEY_YES)
                {
                  *selected = cursor_at_home ? *start_line : *start_line + 1;
                  if (show_options)
                        {
                          show_option(text, *start_line, *selected,
                                                  cursor_at_home, show_options);
                          delay(0xffff);
                        }
                  break;
                }

          if(!KEY_NO)
                {
                  *selected = -1;
                  break;
                }
          
        }
  
  
  return cursor_at_home; 
}


static char
option_on_off(char selected)
{
  char start_line = 0;
  if (selected)
        selected = 0;
  else
        selected = 1;
  select_option("1. Vklju\x1i      2. Izklju\x1i    ",
                                &start_line, &selected, selected ? 0 : 1, 1);
  if (selected == 0)
        return 1;
  else if (selected == 1)
        return 0;
  return -1; /* nothing selected */
}

  

/* up/down and confirm/cancel dialog */
static void
set_temperature(char code *title, int idata *temperature,
                                char step, int minT, int maxT)
{
  unsigned int key_delay = 0;
  int value = *temperature;
  lcd_print(title);

  if (value > maxT)
        value = maxT;
  if (value < minT)
        value = minT;

  
  lcd_print_temp(0xca, value);

  debounce_keys();
  
  while(1)
        {
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;
      if (key_delay)
                {
                  key_delay --;
                  continue;
                }

          if(!KEY_DOWN && value - step >= minT)
                {
                  value -= step;
                  lcd_print_temp(0xca, value);
                  key_delay = KEY_DELAY_TIME;                  
                }
          
          if(!KEY_UP && value + step <= maxT)
                {
                  value += step;
                  lcd_print_temp(0xca, value);
                  key_delay = KEY_DELAY_TIME;
                }

          if(!KEY_YES)
                {
                  *temperature = value;
                  return;
                }

          if(!KEY_NO)
                return;
          
        }
  
  
  
}


static void
set_time_of_day(char code *title, unsigned char *time_of_day)
{
  unsigned int key_delay = 0;
  unsigned char value = *time_of_day;
  
  lcd_print(title);
  lcd_print_time_of_day(value);
  debounce_keys();

  
  while(1)
        {
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;
      if (key_delay)
                {
                  key_delay --;
                  continue;
                }

          if(!KEY_DOWN && value != 0)
                {
                  value --;
                  lcd_print_time_of_day(value);
                  key_delay = KEY_DELAY_TIME;                  
                }
          
          if(!KEY_UP && value < 240)
                {
                  value ++;
                  lcd_print_time_of_day(value);
                  key_delay = KEY_DELAY_TIME;
                }

          if(!KEY_YES)
                {
                  *time_of_day = value;
                  return;
                }

          if(!KEY_NO)
                return;
          
        }
  
}


static void
set_minutes(char code *title, unsigned char low, unsigned char high,
                        unsigned char *minutes)
{
  unsigned int key_delay = 0;
  unsigned char value = *minutes;
  
  lcd_print(title);
  lcd_print_uchar(0x47, value);
  lcd_princ(0x49, "minut");
  debounce_keys();
  while(1)
        {
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;
      if (key_delay)
                {
                  key_delay --;
                  continue;
                }

          if(!KEY_DOWN && value > low)
                {
                  value --;
                  lcd_print_uchar(0x47, value);                  
                  key_delay = KEY_DELAY_TIME;                  
                }
          
          if(!KEY_UP && value < high)
                {
                  value ++;
                  lcd_print_uchar(0x47, value);                  
                  key_delay = KEY_DELAY_TIME;
                }

          if(!KEY_YES)
                {
                  *minutes = value;
                  return;
                }

          if(!KEY_NO)
                return;
          
        }
}


#define ON_OFF(value) option = option_on_off(value); \
                          if (option >= 0) value = option

static void
display_hours(char code *title, unsigned int minutes)
{
  lcd_print(title);
  lcd_print_uchar(0x47, minutes/60);
  lcd_princ(0x49, "ur");
  debounce_keys();
  while(1)
        {
      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;
          
          if(!KEY_YES || !KEY_NO)
                break;
        }
  
  
}


static void
submenu(char main_menu_number)
{
  char selected = 0;
  char start_line = 0;
  bit cursor_at_home = 1;
  char option;
    
  lcd_cgram_caron_init();  
  
  while (1)
        {
          switch (main_menu_number)
                {
                case 0:  /* Boiler */ 
                  cursor_at_home = select_option("1. Gorilec      " 
                                                                                 "2. Min. temp.   "
                                                                                 "3. Maks. temp.  ",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  
                  switch(selected)
                        {
                        case 0:
                          ON_OFF(burner_enabled);
                          break;
                        case 1:
                          set_temperature("Min. temp kotla", &boiler_min_temp,
                                                          100, 1000, boiler_max_temp - 1000);
                          break;
                        case 2:
                          set_temperature("Maks.temp kotla", &boiler_max_temp,
                                                          100, boiler_min_temp + 1000, 9000);
                          break;
                          
                        }
                  
                  break;

                case 1: /* DHW tank connected to boiler */
                  cursor_at_home = select_option("0. Hranilnik    "     
                                                                                 "1. Min. temp.   "
                                                                                 "2. Maks. temp.  ",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  switch (selected)
                        {
                        case 0:
                          ON_OFF(hot_water_pump_enabled);
                          break;
                        case 1:
                          set_temperature("Min.T hranilnika", &hot_water_min_temp,
                                                          100, 500, hot_water_max_temp - 500);
                          break;
                        case 2:
                          set_temperature("Max.T hranilnika", &hot_water_max_temp,
                                                          100, hot_water_min_temp + 500,
                                                          boiler_max_temp - 500);
                          
                          break;
                        }
                  break;
                case 2: /* Hot water circulation setup */
                  cursor_at_home = select_option("1. Kro\003enje vode"
                                                                                 "2. Trajanje     "
                                                                                 "3. Za\001etek 1    "
                                                                                 "4. Za\001etek 2    "
                                                                                 "5. Za\001etek 3    "
                                                                                 "6. Za\001etek 4    "
                                                                                 "7. Za\001etek 5    "
                                                                                 "8. Za\001etek 6    "
                                                                                 "9. Za\001etek 7    "
                                                                                 "10.Za\001etek 8    ",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  switch (selected)
                        {
                        case 0:
                          ON_OFF(circulator_pump_enabled);
                          break;
                        case 1:
                          set_minutes("Trajanje kro\03en.", 1, 30, &circulator_duration);
                          break;
                        default:
                          if (selected > 0)
                                 set_time_of_day("Za\01etek",
                                                          &circulator_start_time[selected - 2]); 
                          break;
                        }
                  break;
                case 3: /* Underfloor heating */
                  cursor_at_home = select_option("0. Mansarda     "
                                                                                 "1. Spalnice     "
                                                                                 "2. Pritli\001je    "
                                                                                 "3. Gara\003a       "
                                                                                 "4. Temp.mansarde"
                                                                                 "5. Temp. spalnic"
                                                                                 "6. T. pritli\001ja "
                                                                                 "7. Temp. gara\003e "
                                                                                 "8.Nagib krivulje"
                                                                                 "9. No\001na korekc."
                                                                                 "10.Za\01etek no\01i "
                                                                                 "11.Konec no\01i   ",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  switch (selected)
                        {
                        case 0:
                          ON_OFF(underfloor_pump0_enabled);
                          break;
                        case 1:
                          ON_OFF(underfloor_pump1_enabled);
                          break;
                        case 2:
                          ON_OFF(underfloor_pump2_enabled);
                          break;
                        case 3:
                          ON_OFF(underfloor_pump3_enabled);
                          break;
                        case 4:
                        case 5:
                        case 6:
                        case 7:
                          set_temperature("Izhodi\02\01na temp.",
                                                          &underfloor_temp[selected - 4],
                                                          100, 1000, 4000);
                          break;
                        case 8:
                          set_temperature("Nagib -\xdf/K",
                                                          &temperature_slope,
                                                          1, 0, 100);
                          break;
                        case 9:
                          set_temperature("No\001na korekcija ",
                                                          &night_temp_offset,
                                                          10, 0, 1000);
                          break;
                        case 10:
                                 set_time_of_day("Za\01etek no\01i",        &night_begin);
                                break;
                        case 11:
                                 set_time_of_day("Konec no\01i",        &night_end);
                                break;
                        }
                  break;
                case 4: /* Solar */
                  cursor_at_home = select_option("0. Solarni sklop"
                                                                                 "1. Maks. temp.  "
                                                                                 "2. Razlika Tc-Th"
                                                                                 "3. Pretakanje   "
                                                                                 "4. Razlika Th-Tb"
                               "5. No\01no hlajen.",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  switch (selected)
                        {
                        case 0:
                          ON_OFF(solar_pump_enabled);
                          break;
                        case 1:
                          set_temperature("Maks. solar temp",
                                                          &max_solar_temperature,
                                                          100, 4000, 10000);
                          break;
                        case 2:
                          set_temperature("kolektor-izmenj.",
                                                          &collector_temp_difference,
                                                          100, 200, 2000);
                          break;
                        case 3:
                          ON_OFF(inter_tank_pump_enabled);
                          break;
                        case 4:
                          set_temperature("sol.hran.-bud.hr",
                                                          &inter_tank_temp_difference,
                                                          100, 100, 3000);
                          break;
         case 5:
            ON_OFF(vacation);
            break;
                        }
                  break;
                case 5: /* general system setup */
                  cursor_at_home = select_option("0. Nastavi uro  "
                                                                                 "1. Bri\02i \02tevce "
                                                                                 "2. Privzete nast",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  switch (selected)
                        {
                        case 0:
                          clock_setup();
                          break;
                        case 1:
                          if (confirm_dialog("Ali naj izbri\02em\n\02tevce ur?      "))
                                {
                                  burner_seconds = 0;
                                  solar_pump_minutes = 0;
                                  ds1307_set_ulong(BURNER_SECONDS_NVRAM_ADDR, burner_seconds);
                                  ds1307_set_int(BURNER_SECONDS_NVRAM_ADDR+4,
                                                                 solar_pump_minutes);
                                }
                          
                          break;
                        case 2:
                          if (confirm_dialog("Ali naj nastavim\nprivzete param.?"))
                                {
                                  timed_message("Za\01etni parametr\nso nastavljeni!", 400);
                                  set_defaults();
                                }
                          break;
                        }
                  break;
                  
                case 6: /* info */
                  cursor_at_home = select_option("0. Prikaz temp. "
                                                                                 "1. Temnjenje pr."
                                                                                 "2. Ure sol. \01rp."
                                                                                 "3. Zgodovina    "
                                                                                 "4. Test sistema ",
                                                                                 &start_line, &selected,
                                                                                 cursor_at_home, 0);
                  switch (selected)
                        {
                        case 0:
                          option = 0;
                          selected = display_solar_temperatures;
                          select_option("0.Talno gretje  "
                                                        "1.Solarne temp. ",
                                                        &option , &selected, selected ? 0 : 1, 1);
                          if (selected >= 0)
                                display_solar_temperatures = selected;
                          selected = 0;
                          break;
                        case 1:
                          ON_OFF(display_blanking_enabled);
                          break;
                        case 2:
                          display_hours("Obratovalne ure", solar_pump_minutes);
                          break;
                        case 3:
                          option = 0; /* start line */
                          selected = 0;
                          select_option("0. Informacije  "
                                                        "1. Izpi\02i zgod. "
                                                        "2. Izpi\02i 57600b"
                                                        "3. Bri\02i zgodov.",
                                                        &option, &selected, 1, 0);
                          switch (selected)
                                {
                                case 0:
                                  push_char('@');
                                  push_char('I');
                                  break;
                                case 1:
                                  push_char('@');
                                  push_char('P');
                                  break;
                                case 2:
                                  push_char('@');
                                  push_char('F');
                                  break;
                                case 3:
                                  if (confirm_dialog("Ali naj izbri\02em\nzgodov.dogodkov?"))
                                        {
                                          push_char('@');
                                          push_char('E');
                                        }
                                  break;
                                }
                          selected = 3;
                          break;
                        case 4: /* System test */
                          option = 0; /* start line */
                          selected = 0;
                          select_option("0. Static RAM   "
                                                        "1. Test ICM7218A"
                                                        "2. RS232 9600bps"
                                                        "3. \01rpalke      "
                                                        "4. Processor CLK",
                                                        &option, &selected, 1, 0);
                          switch (selected)
                                {
                                case 0:
                                  test_ram();
                                  break;
                                case 1:
                                  icm_test(0);
                                  timed_message("Blanking ICM7128\n...             ",
                                                                TEST_MESSAGE_TIME);
                                  icm_test(1);
                                  timed_message("Lighting all ICM\nsegments & LEDs ",
                                                                TEST_MESSAGE_TIME);
                                  icm_test(2);
                                  timed_message("Writting error  \nmessage #2      ",
                                                                TEST_MESSAGE_TIME);
                                  break;
                                case 2:
                                  syslog(LOG_INFO,
                                                 "A. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "B. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "C. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "D. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "E. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "F. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "G. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "H. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "I. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "J. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "K. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "L. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "M. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "N. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "O. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "P. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "Q. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "R. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "S. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "T. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "U. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "V. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "W. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "X. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "Y. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  syslog(LOG_INFO,
                                                 "Z. The quick brown fox jumped over lazy dog");
                                  SWDT=WDT=1;
                                  break;
                                case 3:
                                  break;
                                case 4:
                                  test_processor_clock();
                                  delay(60000);
                                  delay(60000);
                                  delay(60000);
                                  delay(60000);
                                  break;
                                  
                                }
                          selected = 4;
                          break;
                        }
                  break;
                } /* info */
          if (selected < 0)
                return;
        }
}


void 
setup()
{


#define TOTAL_MENUS 7
  
  char  main_menu_number = 0;
  unsigned int  key_delay = 0;

  WDT = 1; /* reset the watch dog timer */
  SWDT = 1;

  show_main_menu_icons();
  show_main_menu(main_menu_number);

  /*  set_defaults(); */
  
  debounce_keys();

  while (1)
    {

      WDT = 1; /* reset the watch dog timer */
      SWDT = 1;

      if (key_delay)
                {
                  key_delay --;
                  continue;
                }


      if (!KEY_UP)
                {
                  if (++main_menu_number >= TOTAL_MENUS)
                        main_menu_number = 0;
                  show_main_menu(main_menu_number);
                  key_delay = KEY_DELAY_TIME;
                  continue;
                }

      if (!KEY_DOWN)
                {
                  if (--main_menu_number < 0)
                        main_menu_number = TOTAL_MENUS - 1;
                  show_main_menu(main_menu_number);
                  key_delay = KEY_DELAY_TIME;
                  continue;
                }

      if (!KEY_YES)
                {
                  submenu(main_menu_number);
                  show_main_menu_icons();
                  show_main_menu(main_menu_number);
                  debounce_keys();
                  continue;
                }
          
      if (!KEY_NO)
                break;
          

    }
  save_parameters();
  lcd_send(0, 0x0c); /* disable cursor */
  lcd_send(0, 0x01); /* clear display at exit of the setup*/  
}