Old project from 2007 won't compile any more

Next problem:

char mapping[] = {1, 2, 3, 4, 5, 6};                       // This is a list of names for each button.
// sterretje, changed to uppercase last character
byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.

Bottom line is 140

Gives:

V100:140:16: error: 'btn_U' was not declared in this scope
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                ^~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:140:16: note: suggested alternative: 'btn_r'
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                ^~~~~
                btn_r
V100:140:23: error: 'btn_D' was not declared in this scope
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                       ^~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:140:23: note: suggested alternative: 'btn_r'
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                       ^~~~~
                       btn_r
V100:140:30: error: 'btn_L' was not declared in this scope
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                              ^~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:140:30: note: suggested alternative: 'btn_r'
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                              ^~~~~
                              btn_r
V100:140:37: error: 'btn_R' was not declared in this scope
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                                     ^~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:140:37: note: suggested alternative: 'btn_r'
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                                     ^~~~~
                                     btn_r
V100:140:44: error: 'btn_D' was not declared in this scope
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                                            ^~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:140:44: note: suggested alternative: 'btn_r'
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                                            ^~~~~
                                            btn_r
V100:140:51: error: 'btn_A' was not declared in this scope
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                                                   ^~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:140:51: note: suggested alternative: 'btn_r'
 byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
                                                   ^~~~~
                                                   btn_r

I'm guessing it is similar to the above, but it is also different in a way I don't yet get.

So where is btn_R (and the others) declared or #defined ??

I for one have lost track of which version of the code that you are getting the error with

3 Likes

I changed that long ago to the uppercase as the lowercase did not compile on my system; see if it stops complaining if you change it to lowercase btn_u etc.

And now, please post your code so people can (try to) compile it. Every time that you take a step and encounter a problem, post updated code. And remember, build it up slowly !!.

2 Likes

Thanks.

My bad on that.

Found the lines where they were defined with uppercase last characters and those lines were looking for lowercase last character.

I don't know why but I kept the uppercase last character because of possible confusion with the l letter.

That got it working.

Greatest apologies for missing that.

I've posted it several times now.

V_100.

That is the NEW code.

I am building on that.

I've (we've) established a working base line and building from that.

It complied good after the first mess up.
I added some more code and spent a long time chasing my tail on the structure of the ... what ever they are called. Arrays? with the month/day/button names in them.

Got that working. That was a long post with the FIXED IT at the bottom.

Then I imported another bit of code and ran into the problem with one part having uppercase last letters for button definition and the other having lowercase.

That is fixed.

I'm not sure it is going to help anyone if EVERY TIME I ADD CODE I POST THE ENTIRE FLOW.

I post the part NEW PART that is giving the error and what it is.

It's possible that you could inadvertently change something or other.
Just post your code - in code tags.

This is the code now.
Updated with imported old code being stuck on bit by bit.

/*
      For laptop:  Uno on com port 3.  Left side USB front.
*/


#define version_ "100"

#include <LiquidCrystal.h>
#include <Wire.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <phi_interfaces.h>
#include <phi_prompt.h>
#include <DS1307.h> 
#include <alarm_clock.h>
#include <Centipede.h>
#include <Arduino.h>



#define phi_2_shield

#define turn_light_on() CS.digitalWrite(1,HIGH)
#define turn_light_off() CS.digitalWrite(1,LOW)

#define turn_blanket_on() CS.digitalWrite(0,HIGH)
#define turn_blanket_off() CS.digitalWrite(0,LOW)

#define lcd_rows 4
#define lcd_columns 20

/////////////////   Un-remark this line to set values in EEPROM for new build.
//#define setRTC




#define LED 13


//Phi-2 shield definitions
#define total_buttons 6
#define btn_U 5
#define btn_D 10
#define btn_L 11
#define btn_R 4
#define btn_B 14
#define btn_A 15

//Phi-2 shield LCD pin setting
#define LCD_RS 8
#define LCD_EN 9
#define LCD_D4 7
#define LCD_D5 6
#define LCD_D6 2
#define LCD_D7 3

LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);  // Create the lcd object

int rtc[7];
DS1307 RTC=DS1307();             // Create RTC object
alarm_clock clock1(false);       // Create an alarm clock


#define alarm_EEPROM_storage 100 // Where the alarm is saved.  The first 100 bytes are for other things.
#define EEPROM_user 0           // Where I put my things/

#define Max_alarms 6


/*
  Map of things stored so far:
  0 - Alarm_run_time
  1 - Blanket off HR
  2 - Blanket off MN
  3 - Alarm defered flag
  4 - DLS start month      //  Needs work.  Could only be month?  October
  5 - DLS end month        //  Needs work   Could only be month?  April
  6 - RDO day              //  Work in progress
  7 - week counter         //  Work in progress
  8 - Audio alarm control
  9 -  Light run time
  10 - Blanket run time
  11 - DLS flag
*/
byte alarm_run_time;
int blanket_off_time_hr;
int blanket_off_time_mnt;
int defered_flag;
byte DLS_S_mth;
byte DLS_E_mth;
byte skip_day;
boolean week_num;
byte skip_day_flag;      //  Is this used?
boolean audio_flag;
byte light_run_time;
byte blanket_run_time;
boolean DLS_Flag;


Centipede CS; // create Centipede object

const PROGMEM char msg_00[]="LCD ALARM CLOCK\nDeveloped by:\nDr.Liu 02/28/12\nhttp://liudr.wordpress.com";
const PROGMEM char msg_01[]="Up - Defere alarm\nDown - Disable ALL alarms ON/OFF\nLeft - Blank' ON/OFFRight - Light ON/OFFEnter - SLEEP";

const PROGMEM char month_00[]="JAN";
const PROGMEM char month_01[]="FEB";
const PROGMEM char month_02[]="MAR";
const PROGMEM char month_03[]="APR";
const PROGMEM char month_04[]="MAY";
const PROGMEM char month_05[]="JUN";
const PROGMEM char month_06[]="JUL";
const PROGMEM char month_07[]="AUG";
const PROGMEM char month_08[]="SEP";
const PROGMEM char month_09[]="OCT";
const PROGMEM char month_10[]="NOV";
const PROGMEM char month_11[]="DEC";
//const PROGMEM signMessage[] *month_items[]= {month_00,month_01,month_02,month_03,month_04,month_05,month_06,month_07,month_08,month_09,month_10,month_11};
const char *const month_items[] PROGMEM = {month_00,month_01,month_02,month_03,month_04,month_05,month_06,month_07,month_08,month_09,month_10,month_11};

const PROGMEM char dow_00[]="SUN";
const PROGMEM char dow_01[]="MON";
const PROGMEM char dow_02[]="TUE";
const PROGMEM char dow_03[]="WED";
const PROGMEM char dow_04[]="THU";
const PROGMEM char dow_05[]="FRI";
const PROGMEM char dow_06[]="SAT";
//const PROGMEM char *dow_items[]= {dow_00,dow_01,dow_02,dow_03,dow_04,dow_05,dow_06};
const char *const dow_items[] PROGMEM = {dow_00,dow_01,dow_02,dow_03,dow_04,dow_05,dow_06};

const PROGMEM char alarm_00[]="Off";
const PROGMEM char alarm_01[]="Daily";
const PROGMEM char alarm_02[]="Weekday";
const PROGMEM char alarm_03[]="Weekend";
const PROGMEM char alarm_04[]="Once";
//PROGMEM const char *alarm_items[]= {alarm_00,alarm_01,alarm_02,alarm_03,alarm_04};
const char *const alarm_items[] PROGMEM = {alarm_00,alarm_01,alarm_02,alarm_03,alarm_04};




//  /*
char mapping[] = {1, 2, 3, 4, 5, 6};                       // This is a list of names for each button.
// sterretje, changed to uppercase last character
//byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
phi_button_groups my_btns(mapping, pins, total_buttons);
phi_serial_keypads debug_keypad(&Serial, 9600);
multiple_button_input* keypads[] = {&my_btns, &debug_keypad, 0};
char up_keys[] = {1, 0};                                                                       ///< All keys that act as the up key are listed here.
char down_keys[] = {2, 0};                                                                     ///< All keys that act as the down key are listed here.
char left_keys[] = {3, 0};                                                                     ///< All keys that act as the left key are listed here.
char right_keys[] = {4, 0};                                                                    ///< All keys that act as the right key are listed here.
char enter_keys[] = {5, 0};                                                                    ///< All keys that act as the enter key are listed here.
char escape_keys[] = {6, 0};                                                                   ///< All keys that act as the escape key are listed here.
char* function_keys[] = {up_keys, down_keys, left_keys, right_keys, enter_keys, escape_keys};  ///< All function key names are gathered here fhr phi_prompt.
//  */

// This is used to set if the blanket is also turned off when an alarm goes off.
//  If 0 nothing happens.
//  Set to 1 and when an alarm goes off, the blanket will be turned off also.
#define ABO 0


void setup()
{
  // put your setup code here, to run once:
  // My routines here.
  
  Serial.begin(9600);

  
  alarm_run_time = EEPROM.read(EEPROM_user+0);
  delay(100);
  blanket_off_time_hr = EEPROM.read(EEPROM_user+1);
  delay(100);
  blanket_off_time_mnt = EEPROM.read(EEPROM_user+2);
  delay(100);
  defered_flag = EEPROM.read(EEPROM_user+3);
  delay(100);
  DLS_S_mth = EEPROM.read(EEPROM_user+4);
  delay(100);
  DLS_E_mth = EEPROM.read(EEPROM_user+5);
  delay(100);
  skip_day = EEPROM.read(EEPROM_user+6);
  delay(100);
  week_num = EEPROM.read(EEPROM_user+7);
  delay(100);
  audio_flag = EEPROM.read(EEPROM_user+8);
  delay(100);
  light_run_time = EEPROM.read(EEPROM_user+9);
  delay(100);
  blanket_run_time = EEPROM.read(EEPROM_user+10);
  delay(100);
  DLS_Flag = EEPROM.read(EEPROM_user+11);
  delay(100);
  
  byte ch_buffer[10];         // This buffer is required for custom characters on the LCD.
  lcd.begin(lcd_columns, lcd_rows);
  Wire.begin();               // initialize wire
  init_phi_prompt(&lcd,keypads,function_keys, lcd_columns, lcd_rows, '~'); // Supply the liquid crystal object, input keypads, and function key names. Also supply the column and row of the lcd, and indicator as '>'. You can also use '\x7e', which is a right arrow.
  //  =========== 2023 08 31
  //init_big_font(&lcd);


////////////////////////////////////////////////
  CS.initialize(); // set all registers to default
  CS.portMode(0, 0b0000000000000000); // set all pins on chip 0 to output


// Set the two channels to output to drive the buzzer and LED.
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);


//============================================
#ifdef setRTC
// Set/init RTC
  RTC.stop();
  RTC.set(DS1307_SEC,0);
  RTC.set(DS1307_MIN,50);
  RTC.set(DS1307_HR,0);
  RTC.set(DS1307_DOW,3);           // value from 1 to 7. User define whether 1 is sun or mon.
  RTC.set(DS1307_DATE,10);
  RTC.set(DS1307_MTH,06);
  RTC.set(DS1307_YR,23);
  RTC.start();
//============================================

//Set alarms
  EEPROM.write(alarm_EEPROM_storage,6);       // Alarm 0 hour
  EEPROM.write(alarm_EEPROM_storage+1,50);    // Alarm 0 minute
  EEPROM.write(alarm_EEPROM_storage+2,0);     // Alarm 0 frequency off

  EEPROM.write(alarm_EEPROM_storage+3,7);     // Alarm 1 hour
  EEPROM.write(alarm_EEPROM_storage+4,00);    // Alarm 1 minute
  EEPROM.write(alarm_EEPROM_storage+5,0);     // Alarm 1 frequency off

  EEPROM.write(alarm_EEPROM_storage+6,7);     // Alarm 2 hour
  EEPROM.write(alarm_EEPROM_storage+7,00);    // Alarm 2 minute
  EEPROM.write(alarm_EEPROM_storage+8,3);     // Alarm 2 frequency Week end

  EEPROM.write(alarm_EEPROM_storage+9,4);     // Alarm 3 hour
  EEPROM.write(alarm_EEPROM_storage+10,48);   // Alarm 3 minute
  EEPROM.write(alarm_EEPROM_storage+11,0);    // Alarm 3 frequency off
  
  EEPROM.write(alarm_EEPROM_storage+12,5);     // Alarm 4 hour
  EEPROM.write(alarm_EEPROM_storage+13,48);   // Alarm 4 minute
  EEPROM.write(alarm_EEPROM_storage+14,2);    // Alarm 4 frequency M-F
  
  //  Set when DLS starts and ends - months.
  EEPROM.write(EEPROM_user+4,10);
  delay(100);
  EEPROM.write(EEPROM_user+5,4);
  delay(100);

#else
// Set alarm on the clock from EEPROM.
  clock1.set_alarm(0, EEPROM.read(alarm_EEPROM_storage), EEPROM.read(alarm_EEPROM_storage+1), EEPROM.read(alarm_EEPROM_storage+2));
  clock1.set_alarm(1, EEPROM.read(alarm_EEPROM_storage+3), EEPROM.read(alarm_EEPROM_storage+4), EEPROM.read(alarm_EEPROM_storage+5));
  clock1.set_alarm(2, EEPROM.read(alarm_EEPROM_storage+6), EEPROM.read(alarm_EEPROM_storage+7), EEPROM.read(alarm_EEPROM_storage+8));
  clock1.set_alarm(3, EEPROM.read(alarm_EEPROM_storage+9), EEPROM.read(alarm_EEPROM_storage+10), EEPROM.read(alarm_EEPROM_storage+11));
  clock1.set_alarm(4, EEPROM.read(alarm_EEPROM_storage+12), EEPROM.read(alarm_EEPROM_storage+13), EEPROM.read(alarm_EEPROM_storage+14));
  clock1.set_alarm(5, EEPROM.read(alarm_EEPROM_storage+15), EEPROM.read(alarm_EEPROM_storage+16), EEPROM.read(alarm_EEPROM_storage+17));
#endif

}

void loop()
{
  // put your main code here, to run repeatedly:

}

That compiles with no errors.

So I then import blocks of code and test as I go.

If I get an error I post the new block - and anything I think is associated - and the error.
Would it be better if I post the ENTIRE code each time?
I know it is not costing anyone anything but it seems a bit wasteful.
Just asking which is preferred.

Emphatically YES !

2 Likes

Ok.

Sorry, some other forums only want the new stuff.

I can't know what is what for all forums.

Anyway, thanks to all for the help.

I am starting to import routines. (As said.)
And - just so you know - Alas for me I now have to go and do other things.
As much as I would like to have the time to sit here and get all the kinks out of the code in one go.

Oh, ok, but on that about importing blocks of code:
When I did this originally I had other tabs with their sectionalised bits in/on the tabs.
Kind of like each routine in/on a new tab - but also not.... (sorry.)

Is that better or is it better having it all on ONE LOG tab?
I get it that it also may come down to horses for courses.

Again: Just asking.
(I'll wait a bit for the reply)

If your project is in more than one tab it complicates things when it comes to posting it to the forum because you have to zip up the contents of the sketch folder and attach that to a post. Then it has to be downloaded and extracted in order to examine it

Using separate tabs also introduces complications to the sketch if you are not careful about what is #included/#defined/declared and where

In general I find it easier to put all of the code in a single .ino file, using sensible function names, and that certainly makes it easier to copy it from the IDE using shift+Ctrl+C which conveniently adds the code tags for you. IDE 2.x also allows you to jump to or peek at a function definition without having to search for it, which is very helpful

SUMMARY
Neither a single tab or multiple tabs is better but they both have advantages and disadvantages depending on your requirements

2 Likes

Thanks.

For now I'll keep it as one tab to help everyone.

And I may even keep it that way too.
I did it then only because it was new and maybe novel having many tabs.

Ok.

Again: Thanks.
For me, I'll be back in about 6 hours.
Life kinda sucks and throws multiple things at you (me) and .... anyway.

I hope to make progress when I get back.
I'm off now.

To be able to follow your progress, I've installed GitHub - macetech/Centipede: Arduino library for the Centipede Shield MCP23017 I/O expander by macetech; I hope that that is the correct one.

I however don't seem to be able to find the correct alarm_clock library. Please provide a link or zip the directory in libraries that contains that library.

1 Like

Shall do.

I'm not sure from where it came so here it is in ZIP format

alarm_clock.zip (3.6 KB)

That's it for this post.

Oh the centipede.library. Yes that's the one.

BIg steps have been made.
Read all the post as it is a bit mish mash how I am writing it.
(Yeah, not a good sign of how I program)
Well, no. You will see that the routines are well documented above them.
This was because by the time I wrote them I had learnt my lesson on needing them
to be well written.
Maybe not THE BEST, but a lot better than when I started.

There are a couple now one of errors now that I think may need addressing.

While going through things some errors happened but then went away as I brought in more code.
I kind of worked that out looking at the names of what was missing.

So the code. (Zip format as it is getting quite big and I am not sure the limits of posting code are here.)

V100.zip (11.9 KB)

There are no other local files in the directory.
All/any other files are in the libraries folder.

Errors:


/home/me/Arduino/Alarm_Clock/V100/V100.ino: In function 'void top_menu_function_2()':
V100:1335:3: error: 'render_RTC' was not declared in this scope
   render_RTC(0);
   ^~~~~~~~~~
/home/me/Arduino/Alarm_Clock/V100/V100.ino:1335:3: note: suggested alternative: 'render_list'
   render_RTC(0);
   ^~~~~~~~~~
   render_list
Multiple libraries were found for "LiquidCrystal.h"
 Used: /home/me/Arduino/libraries/LiquidCrystal
 Not used: /snap/arduino/85/libraries/LiquidCrystal
exit status 1
'render_RTC' was not declared in this scope

Ok, only one.

The other one may have gone away with other stuff I had imported.

UPDATE!

That error is/may/probably is to do with alarm_clock.h
(Strange)
It is #include <alarm_clock> at the top and is correctly in the libraries directory.
Well, the one I made and is being used as there are libraries in there that aren't in the official one.
(I can't access it and am stuck on that point/part but that's off topic for now)
I searched the old version code and found the render(rtc) in there.
So that may now be the only stumbling block.

Thanks for the alarm_clock library. I'm battling to compile your code from post #69 (trying to work on that). It does not look like a library as it contains an ino file. So I suspect that it's part of your original sketch.

That is in the ino file in the alarm_clock "library".

I suggest that place the unzipped .ino and .h from the alarm_clock "library" in your sketch directory.

I would like to ask if you can zip your original 2007 project and attach it here so we can see what it looked like.

PS
The limit for a post is 120 kByte if not mistaken.

You seem to be determined not to post your code in the easiest way possible so here it is

/*
      For laptop:  Uno on com port 3.  Left side USB front.
*/

#define version_ "100"

#include <LiquidCrystal.h>
#include <Wire.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <phi_interfaces.h>
#include <phi_prompt.h>
#include <DS1307.h>
#include <alarm_clock.h>
#include <Centipede.h>
#include <Arduino.h>

#define phi_2_shield

#define turn_light_on() CS.digitalWrite(1, HIGH)
#define turn_light_off() CS.digitalWrite(1, LOW)

#define turn_blanket_on() CS.digitalWrite(0, HIGH)
#define turn_blanket_off() CS.digitalWrite(0, LOW)

#define lcd_rows 4
#define lcd_columns 20

/////////////////   Un-remark this line to set values in EEPROM for new build.
//#define setRTC

#define LED 13

//Phi-2 shield definitions
#define total_buttons 6
#define btn_U 5
#define btn_D 10
#define btn_L 11
#define btn_R 4
#define btn_B 14
#define btn_A 15

//Phi-2 shield LCD pin setting
#define LCD_RS 8
#define LCD_EN 9
#define LCD_D4 7
#define LCD_D5 6
#define LCD_D6 2
#define LCD_D7 3

LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);  // Create the lcd object

int rtc[7];
DS1307 RTC = DS1307();      // Create RTC object
alarm_clock clock1(false);  // Create an alarm clock

#define alarm_EEPROM_storage 100  // Where the alarm is saved.  The first 100 bytes are for other things.
#define EEPROM_user 0             // Where I put my things/

#define Max_alarms 6

/*
  Map of things stored so far:
  0 - Alarm_run_time
  1 - Blanket off HR
  2 - Blanket off MN
  3 - Alarm defered flag
  4 - DLS start month      //  Needs work.  Could only be month?  October
  5 - DLS end month        //  Needs work   Could only be month?  April
  6 - RDO day              //  Work in progress
  7 - week counter         //  Work in progress
  8 - Audio alarm control
  9 -  Light run time
  10 - Blanket run time
  11 - DLS flag
*/
byte alarm_run_time;
int blanket_off_time_hr;
int blanket_off_time_mnt;
int defered_flag;
byte DLS_S_mth;
byte DLS_E_mth;
byte skip_day;
boolean week_num;
byte skip_day_flag;  //  Is this used?
boolean audio_flag;
byte light_run_time;
byte blanket_run_time;
boolean DLS_Flag;

Centipede CS;  // create Centipede object

const PROGMEM char msg_00[] = "LCD ALARM CLOCK\nDeveloped by:\nDr.Liu 02/28/12\nhttp://liudr.wordpress.com";
const PROGMEM char msg_01[] = "Up - Defere alarm\nDown - Disable ALL alarms ON/OFF\nLeft - Blank' ON/OFFRight - Light ON/OFFEnter - SLEEP";

const PROGMEM char month_00[] = "JAN";
const PROGMEM char month_01[] = "FEB";
const PROGMEM char month_02[] = "MAR";
const PROGMEM char month_03[] = "APR";
const PROGMEM char month_04[] = "MAY";
const PROGMEM char month_05[] = "JUN";
const PROGMEM char month_06[] = "JUL";
const PROGMEM char month_07[] = "AUG";
const PROGMEM char month_08[] = "SEP";
const PROGMEM char month_09[] = "OCT";
const PROGMEM char month_10[] = "NOV";
const PROGMEM char month_11[] = "DEC";
//const PROGMEM signMessage[] *month_items[]= {month_00,month_01,month_02,month_03,month_04,month_05,month_06,month_07,month_08,month_09,month_10,month_11};
const char *const month_items[] PROGMEM = { month_00, month_01, month_02, month_03, month_04, month_05, month_06, month_07, month_08, month_09, month_10, month_11 };

const PROGMEM char dow_00[] = "SUN";
const PROGMEM char dow_01[] = "MON";
const PROGMEM char dow_02[] = "TUE";
const PROGMEM char dow_03[] = "WED";
const PROGMEM char dow_04[] = "THU";
const PROGMEM char dow_05[] = "FRI";
const PROGMEM char dow_06[] = "SAT";
//const PROGMEM char *dow_items[]= {dow_00,dow_01,dow_02,dow_03,dow_04,dow_05,dow_06};
const char *const dow_items[] PROGMEM = { dow_00, dow_01, dow_02, dow_03, dow_04, dow_05, dow_06 };

const PROGMEM char alarm_00[] = "Off";
const PROGMEM char alarm_01[] = "Daily";
const PROGMEM char alarm_02[] = "Weekday";
const PROGMEM char alarm_03[] = "Weekend";
const PROGMEM char alarm_04[] = "Once";
//PROGMEM const char *alarm_items[]= {alarm_00,alarm_01,alarm_02,alarm_03,alarm_04};
const char *const alarm_items[] PROGMEM = { alarm_00, alarm_01, alarm_02, alarm_03, alarm_04 };

//  /*
char mapping[] = { 1, 2, 3, 4, 5, 6 };  // This is a list of names for each button.
// sterretje, changed to uppercase last character
//byte pins[] = {btn_U, btn_D, btn_L, btn_R, btn_D, btn_A};  // The digital pins connected to the 6 buttons.
byte pins[] = { btn_U, btn_D, btn_L, btn_R, btn_D, btn_A };  // The digital pins connected to the 6 buttons.
phi_button_groups my_btns(mapping, pins, total_buttons);
phi_serial_keypads debug_keypad(&Serial, 9600);
multiple_button_input *keypads[] = { &my_btns, &debug_keypad, 0 };
char up_keys[] = { 1, 0 };                                                                       ///< All keys that act as the up key are listed here.
char down_keys[] = { 2, 0 };                                                                     ///< All keys that act as the down key are listed here.
char left_keys[] = { 3, 0 };                                                                     ///< All keys that act as the left key are listed here.
char right_keys[] = { 4, 0 };                                                                    ///< All keys that act as the right key are listed here.
char enter_keys[] = { 5, 0 };                                                                    ///< All keys that act as the enter key are listed here.
char escape_keys[] = { 6, 0 };                                                                   ///< All keys that act as the escape key are listed here.
char *function_keys[] = { up_keys, down_keys, left_keys, right_keys, enter_keys, escape_keys };  ///< All function key names are gathered here fhr phi_prompt.
//  */

// This is used to set if the blanket is also turned off when an alarm goes off.
//  If 0 nothing happens.
//  Set to 1 and when an alarm goes off, the blanket will be turned off also.
#define ABO 0

void setup()
{
    // put your setup code here, to run once:
    // My routines here.

    Serial.begin(9600);

    alarm_run_time = EEPROM.read(EEPROM_user + 0);
    delay(100);
    blanket_off_time_hr = EEPROM.read(EEPROM_user + 1);
    delay(100);
    blanket_off_time_mnt = EEPROM.read(EEPROM_user + 2);
    delay(100);
    defered_flag = EEPROM.read(EEPROM_user + 3);
    delay(100);
    DLS_S_mth = EEPROM.read(EEPROM_user + 4);
    delay(100);
    DLS_E_mth = EEPROM.read(EEPROM_user + 5);
    delay(100);
    skip_day = EEPROM.read(EEPROM_user + 6);
    delay(100);
    week_num = EEPROM.read(EEPROM_user + 7);
    delay(100);
    audio_flag = EEPROM.read(EEPROM_user + 8);
    delay(100);
    light_run_time = EEPROM.read(EEPROM_user + 9);
    delay(100);
    blanket_run_time = EEPROM.read(EEPROM_user + 10);
    delay(100);
    DLS_Flag = EEPROM.read(EEPROM_user + 11);
    delay(100);

    byte ch_buffer[10];  // This buffer is required for custom characters on the LCD.
    lcd.begin(lcd_columns, lcd_rows);
    Wire.begin();                                                               // initialize wire
    init_phi_prompt(&lcd, keypads, function_keys, lcd_columns, lcd_rows, '~');  // Supply the liquid crystal object, input keypads, and function key names. Also supply the column and row of the lcd, and indicator as '>'. You can also use '\x7e', which is a right arrow.
    //  =========== 2023 08 31
    //init_big_font(&lcd);

    ////////////////////////////////////////////////
    CS.initialize();                     // set all registers to default
    CS.portMode(0, 0b0000000000000000);  // set all pins on chip 0 to output

    // Set the two channels to output to drive the buzzer and LED.
    pinMode(LED, OUTPUT);
    digitalWrite(LED, LOW);

//============================================
//    I am not sure I need to keep this section of code.
//    Ending with similar line of =====
#ifdef setRTC
    // Set/init RTC
    RTC.stop();
    RTC.set(DS1307_SEC, 0);
    RTC.set(DS1307_MIN, 50);
    RTC.set(DS1307_HR, 0);
    RTC.set(DS1307_DOW, 3);  // value from 1 to 7. User define whether 1 is sun or mon.
    RTC.set(DS1307_DATE, 10);
    RTC.set(DS1307_MTH, 06);
    RTC.set(DS1307_YR, 23);
    RTC.start();

    //Set alarms
    EEPROM.write(alarm_EEPROM_storage, 6);       // Alarm 0 hour
    EEPROM.write(alarm_EEPROM_storage + 1, 50);  // Alarm 0 minute
    EEPROM.write(alarm_EEPROM_storage + 2, 0);   // Alarm 0 frequency off

    EEPROM.write(alarm_EEPROM_storage + 3, 7);   // Alarm 1 hour
    EEPROM.write(alarm_EEPROM_storage + 4, 00);  // Alarm 1 minute
    EEPROM.write(alarm_EEPROM_storage + 5, 0);   // Alarm 1 frequency off

    EEPROM.write(alarm_EEPROM_storage + 6, 7);   // Alarm 2 hour
    EEPROM.write(alarm_EEPROM_storage + 7, 00);  // Alarm 2 minute
    EEPROM.write(alarm_EEPROM_storage + 8, 3);   // Alarm 2 frequency Week end

    EEPROM.write(alarm_EEPROM_storage + 9, 4);    // Alarm 3 hour
    EEPROM.write(alarm_EEPROM_storage + 10, 48);  // Alarm 3 minute
    EEPROM.write(alarm_EEPROM_storage + 11, 0);   // Alarm 3 frequency off

    EEPROM.write(alarm_EEPROM_storage + 12, 5);   // Alarm 4 hour
    EEPROM.write(alarm_EEPROM_storage + 13, 48);  // Alarm 4 minute
    EEPROM.write(alarm_EEPROM_storage + 14, 2);   // Alarm 4 frequency M-F

    //  Set when DLS starts and ends - months.
    EEPROM.write(EEPROM_user + 4, 10);
    delay(100);
    EEPROM.write(EEPROM_user + 5, 4);
    delay(100);
    //============================================

#else
    // Set alarm on the clock from EEPROM.
    clock1.set_alarm(0, EEPROM.read(alarm_EEPROM_storage), EEPROM.read(alarm_EEPROM_storage + 1), EEPROM.read(alarm_EEPROM_storage + 2));
    clock1.set_alarm(1, EEPROM.read(alarm_EEPROM_storage + 3), EEPROM.read(alarm_EEPROM_storage + 4), EEPROM.read(alarm_EEPROM_storage + 5));
    clock1.set_alarm(2, EEPROM.read(alarm_EEPROM_storage + 6), EEPROM.read(alarm_EEPROM_storage + 7), EEPROM.read(alarm_EEPROM_storage + 8));
    clock1.set_alarm(3, EEPROM.read(alarm_EEPROM_storage + 9), EEPROM.read(alarm_EEPROM_storage + 10), EEPROM.read(alarm_EEPROM_storage + 11));
    clock1.set_alarm(4, EEPROM.read(alarm_EEPROM_storage + 12), EEPROM.read(alarm_EEPROM_storage + 13), EEPROM.read(alarm_EEPROM_storage + 14));
    clock1.set_alarm(5, EEPROM.read(alarm_EEPROM_storage + 15), EEPROM.read(alarm_EEPROM_storage + 16), EEPROM.read(alarm_EEPROM_storage + 17));
#endif
}

void loop()
{
    // put your main code here, to run repeatedly:
}

//  (My routines)

/*============================================================================================================================*/

/*
      Below are routines.
*/

/*============================================================================================================================*/
/*
        This is a list of the routines in this section:
        bootup
        alarm_defer
        light_toggle
        lecky_blanky
        sleep_time
        alarm_timer
        DLS
        show_keys
        week_counter
        voice_reminder
        audio_test
        display_stuff
*/

void bootup()
{
    //
    Serial.print("Version ");
    Serial.println(version_);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Boot up info.");
    lcd.setCursor(0, 1);
    lcd.print("Ver' ");
    lcd.print(version_);
    wait_on_escape(4000);
    lcd.setCursor(0, 0);
    lcd.print("HR MN ADF [DLS ] ART");
    lcd.setCursor(1, 1);
    lcd.print(blanket_off_time_hr);
    lcd.print(" ");
    lcd.print(blanket_off_time_mnt);
    lcd.print("  ");
    lcd.print(defered_flag);
    lcd.print("  [");
    lcd.print(DLS_S_mth);
    lcd.print(" ");
    lcd.print(DLS_E_mth);
    lcd.print("] ");
    lcd.print(alarm_run_time);
    lcd.setCursor(0, 2);
    lcd.print(" ");
    lcd.setCursor(0, 2);
    lcd.print("SD WN LT BT DF AF");
    lcd.setCursor(0, 3);
    lcd.print(" ");
    lcd.print(skip_day);
    lcd.print("  ");
    lcd.print(week_num);
    if (light_run_time > 9)
    {
        lcd.print(" ");
    }
    else
    {
        lcd.print("  ");
    }
    lcd.print(light_run_time);
    lcd.print(" ");
    lcd.print(blanket_run_time);
    lcd.print(" ");
    lcd.print(DLS_Flag);
    lcd.print("   ");
    lcd.print(audio_flag);
    wait_on_escape(8000);
}

/*============================================================================================================================*/

//  My routine to defere alarms for people who beat the alarm.

/*
    Call it with 0 return the status of the defered alarms  DISPLAY ONLY.
    Call it with 1 to set the flag to skip the next alarm.
    Call it with 2 to set the MASTER defere flag.
    Call it with 3 to return the status and clear if needed.  This is called when the alarm is active.
    
    When called with 0:
    Returns 0, 1 or 3.
    0 - allow alarm to happen.
    1 - do not allow this alarm to happen.
    3 - ALL alarms defered.
*/

boolean alarm_defere(byte fctn)
{
    Serial.print(F("alarm defer called with "));
    Serial.println(fctn);
    boolean rc;
    if (fctn == 0)
        return defered_flag;
    if (fctn == 1)
    {
        //
        if (defered_flag != 3)
        {
            defered_flag = defered_flag + 1;
            defered_flag = defered_flag % 2;
        }
        rc = 0;  //  This is a "dummy" as it is not needed/used.
    }
    if (fctn == 2)  //  This is for future use as a quick turn off for all alarm - toggle.
    {
        defered_flag = defered_flag + 1;
        defered_flag = defered_flag % 2;
        if (defered_flag == 1)
        {
            defered_flag = 3;
        }
        rc = 0;  //  This is a "dummy" as it is not needed/used.
    }
    else if (fctn == 3)
    {
        if (defered_flag == 0)
        {
            rc = 0;
        }
        if (defered_flag == 3)
        {
            rc = 1;
        }
        if (defered_flag == 1)
        {
            defered_flag = 0;
            rc = 1;
        }
    }
    EEPROM.write(EEPROM_user + 3, defered_flag);
    delay(100);
    Serial.print(F("Alarm defer returning value "));
    Serial.println(rc);
    return rc;
}

/*============================================================================================================================*/

//  My little routine to toggle light on/off
/*
    This is a simple toggle function for the light.
    So if you need it on, press the button.
    Call with 0 - returns status.
    Call with 1 - toggle light.
    Call with 2 - turn off.
    
    When called with 0:
    Returns:
    0 - light off
    1 - light on
    This is used for another routine to display the icon.
*/

boolean light_toggle(byte fctn)
{
    static boolean Light_status;
    if (fctn == 0)
    {
        return Light_status;
    }
    else if (fctn == 1)
    {
        sleep_time(light_run_time, 1);
        Light_status = Light_status + 1;
        Light_status = Light_status % 2;
        switch (Light_status)
        {
            case 0:
                turn_light_off();
                break;

            case 1:
                turn_light_on();
                break;
        }
    }
    else if (fctn == 2)  // used to force off.
    {
        Light_status = 0;
        turn_light_off();
    }
}

/*============================================================================================================================*/

//  Electric blanket routine.
/*
    This routine turns on the blanket relay.
    and other functions with the blanket.
    Call with 0 - return status
    Call with 1 - toggle.
    Call with 2 - turn off.

    When called with 0:
    Returns:
    0 - blanket off
    1 - blanket on
    This is used for another routine to display the icon.
*/

boolean leky_blanky(byte fctn)
{
    static int blanket_status;
    if (fctn == 0)
    {
        return blanket_status;
    }
    else if (fctn == 1)
    {
        sleep_time(blanket_run_time, 2);
        blanket_status = blanket_status + 1;
        blanket_status = blanket_status % 2;
        switch (blanket_status)
        {
            case 0:
                turn_blanket_off();
                break;

            case 1:
                turn_blanket_on();
                break;
        }
    }
    else if (fctn == 2)
    {
        blanket_status = 0;
        turn_blanket_off();
    }
}

/*============================================================================================================================*/

/*
      This is a countdown function.  There are TWO paramaters.  Function and Caller.
      Initial settings are set when it is called with a caller value of 0 or 1.
      The function value sets the time.
      To activate the timer, call with a caller value of 30.
      To the cancel the timer, call again with caller value of 30.
      
      Call twice with Caller of 0 or 1 then with 30 to turn on the
      device after the specified time, rather than turn off after
      the specified time.
      
      Returns the countdown time remaining when active.
*/

byte sleep_time(byte fctn, byte caller)
{
    static byte count_down_time_remaining;
    static byte fctn_memory;    //  This is a copy of the original call value so if it is seen again, it cancels the timer.
    static byte caller_memory;  //  This is the memory of who called and initiated the timer.
    static byte min_flag;       //  This ia the memory of the last minute from the RTC.
    static boolean condition;   //  This is a memory for the condition of this function.
    static byte old_caller;     //  This is another memory which is needed for who called.
    RTC.get(rtc, true);
    if (caller == 0)
    {
        // count down
        if (count_down_time_remaining > 0)
        {
            if (min_flag != rtc[1])
            {
                min_flag = rtc[1];
                count_down_time_remaining = count_down_time_remaining - 1;
            }
        }
        if (count_down_time_remaining == 0)
        {
            //condition = 0;
            if (old_caller > 0)
            {
                switch (old_caller)
                {
                    case 1:
                        old_caller = 0;
                        light_toggle(1);
                        break;

                    case 2:
                        old_caller = 0;
                        leky_blanky(1);
                        break;

                    default:
                        break;
                }
            }
        }
        return count_down_time_remaining;
    }

    if (caller == 1)
    {
        min_flag = rtc[1];
        caller_memory = caller;
        fctn_memory = fctn;
        if (old_caller == caller)
        {
            count_down_time_remaining = 0;
            return 0;
        }
    }

    if (caller == 2)
    {
        min_flag = rtc[1];
        caller_memory = caller;
        fctn_memory = fctn;
        if (old_caller == caller)
        {
            count_down_time_remaining = 0;
            return 0;
        }
    }

    if (caller == 30)
    {
        // toggle status of the "Sleep" function
        condition = condition + 1;
        condition = condition % 2;
        switch (condition)
        {
            case 0:
                count_down_time_remaining = 0;
                return 0;
                break;

            case 1:
                count_down_time_remaining = fctn_memory;
                old_caller = caller_memory;
                return count_down_time_remaining;
                break;
            default:
                return (0);
        }
    }
}

/*============================================================================================================================*/

/*
    This routine is a "countdown" timer for the alarms.
    It counts down the value ART - Alarm Run Time.
*/

byte alarm_timer(byte boo)
{
    static byte run_flag;
    static byte ART;
    static byte min_called;
    char msg[18];
    RTC.get(rtc, true);
    run_flag = boo;
    byte x = 2;
    byte y = 0;
    if (run_flag == 0)
    {
        ART = 0;
        return (ART);
    }
    if (run_flag == 1)
    {
        if (ART == 0)
        {
            ART = alarm_run_time;
            min_called = rtc[1];
        }
        if (ART > 0)
        {
            if (min_called != rtc[1])
            {
                min_called = rtc[1];
                ART = ART - 1;
            }
            lcd.setCursor(x, y);
            lcd.print(ART);
            if (ART == 1)
                lcd.print(F(" minute to go. "));
            else if (ART > 9)
                lcd.print(F(" minutes to go."));
            else
                lcd.print(F(" minutes to go. "));
        }
        return (ART);
    }
}

/*============================================================================================================================*/
/*
      Idea:
      Set:
      Check for DLS start month
      Check for DOW = 1.  Sunday
      Check hour = 02.
      Add 1 hour and set flag
      Reset:
      Check for DLS end month
      Check for DOW = 1.  Sunday
      Check hour = 02.
      Check flag is set
      Remove 1 hour and reset flag
    
      rtc[5] is the month.
      rtc[4] is the date.
      rtc[3] is DOW.
      rtc[2] is hour.
*/

void DLS()
{
    byte hour_now;
    RTC.get(rtc, true);
    if (DLS_S_mth == rtc[5])
    {
        //  Check DOW
        if (rtc[3] == 1)
        {
            //
            if (rtc[2] == 2)
            {
                if (DLS_Flag == 0)
                {
                    //  Wind clock fwd 1 hour and set flag.
                    // and set DLS_Flag = 1
                    hour_now = rtc[2];
                    hour_now = hour_now + 1;
                    rtc[2] = hour_now;
                    RTC.stop();
                    RTC.set(DS1307_HR, rtc[2]);
                    RTC.start();
                    DLS_Flag = 1;
                    EEPROM.write(EEPROM_user + 11, DLS_Flag);
                    delay(100);
                }
            }
        }
    }
    if (DLS_E_mth == rtc[5])
    {
        //  Check DOW
        if (rtc[3] == 1)
        {
            if (rtc[2] == 2)
            {
                if (DLS_Flag == 1)
                {
                    //  Wind clock back 1 hour and set flag.
                    // and set DLS_Flag = 0
                    hour_now = rtc[2];
                    hour_now = hour_now - 1;
                    rtc[2] = hour_now;
                    RTC.stop();
                    RTC.set(DS1307_HR, rtc[2]);
                    RTC.start();
                    DLS_Flag = 0;
                    EEPROM.write(EEPROM_user + 11, DLS_Flag);
                    delay(100);
                }
            }
        }
    }
}

/*============================================================================================================================*/

/*
    This shows what all the keys do.
*/

void show_keys()
{
    phi_prompt_struct myLongMsg;

    lcd.clear();
    lcd.noBlink();
    myLongMsg.ptr.msg_P = msg_01;           // Assign the address of the text string to the pointer.
    myLongMsg.low.i = 0;                    // Default text starting position. 0 is highly recommended.
    myLongMsg.high.i = strlen_P(msg_01);    // Position of the last character in the text string, which is size of the string - 1.
    myLongMsg.step.c_arr[0] = lcd_rows;     // rows to auto fit entire screen
    myLongMsg.step.c_arr[1] = lcd_columns;  // one col list
    myLongMsg.col = 0;                      // Display the text area starting at column 0
    myLongMsg.row = 0;                      // Display the text area starting at row 0
    myLongMsg.option = 0;                   // Option 0, display classic message, option 1, display message with scroll bar on right.

    text_area_P(&myLongMsg);
}

/*============================================================================================================================*/

/*
    This counts the week and alternates from 0 to 1.
    This is used to allow for "flexy days" to be included
    in the alarm sequence and actually stop the alarm going off
    on that specific day.
*/

void week_counter()
{
    static boolean flag;
    RTC.get(rtc, true);
    if (rtc[3] == 2)  //  Monday - or Sunday MIDNIGHT going into Monday.
    {
        if (flag == 0)
        {
            week_num = week_num + 1;
            week_num = week_num % 2;
            flag = 1;
            //************ WORK NEEDED HERE TO STORE TO EEPROM
        }
    }
    if (rtc[3] == 3)
    {
        flag = 0;
    }
}

/*============================================================================================================================*/
/*
    This creates a random number which is used to trigger a random
    sound.

    No sound optinon removed.    
    The initial value is:
    0 - play sound 1
    1 - play sound 2
    
    Then given the 1 or 2, they are reduced by 1 to be 0 or 1.
    This is to help identify which pin is used on the MCP.
    
    There is a lot of flags - GO and FLAG - which are used to
    stop multiple invocation of the routine.
    FLAG is used when the alarm starts and stops the voice repeating.
    GO is also needed to clear the FLAG once the alarm is stopped.
*/

void voice_reminder(boolean go)
{
    //  This bit of routine selects 1 of 2 values to select which sound is played.
    static boolean flag;
    if (go == 0)
    {
        //
        if (flag == 0)
        {
            //
            int random_num;
            lcd.setCursor(18, 0);
            random_num = random(0, audio_flag + 1);
            lcd.print(random_num);
            //            if (random_num >0)
            //            {
            //                random_num = random_num -1;
            CS.digitalWrite(4 + random_num, HIGH);
            delay(500);
            CS.digitalWrite(4 + random_num, LOW);
            //            }
            flag = 1;
        }
    }
    if (go == 1)
    {
        flag = 0;
        lcd.setCursor(18, 0);  //  2017 06 24   This was putting curor at 19,0 instead of 18,0.
        lcd.print(" ");
    }
}
/*============================================================================================================================*/
/*
    This routine is used only to cycle the pins to stimulate the audion card so I cam be sure it is working.
*/

void audio_test()
{
    //  for (int i=0;i<5;i++)
    for (int i = 0; i < (audio_flag + 1); i++)
    {
        //
        lcd.clear();
        lcd.print(i);
        CS.digitalWrite(4 + i, HIGH);
        delay(500);
        lcd.clear();
        lcd.print(i);
        CS.digitalWrite(4 + i, LOW);
        delay(500);
    }
    //  return;
}

/*============================================================================================================================*/

/*============================================================================================================================*/

/*============================================================================================================================*/

/*
      This piece of code is used for display stuff.
      There is no particular order but each "routine" is seperated
      by a line of -------
      
      General stuff to note:
      Variables x and y are used by each section to position the curosr
      on the screen as much as possible to help if the position where
      the information is displayed.
      
      boo is a general purpose thing for getting return values from other
      functions.
*/

void display_stuff()
{
    //  These two lines are for setting the position of things to print.
    byte x;    //  Sets X position on screen
    byte y;    //  Sets Y position on screen
    byte boo;  //  This is used to get return values from other routines.
    RTC.get(rtc, true);
    //  Now a list of other variables used.
    //  Comments tell which section they are used in.
    static byte al_flag;        //  Used in defere alarm section.
    static byte skip_day_flag;  //  RDO routine.
    byte i;                     //  Used for displaying alarm status symbol.
    int foo[Max_alarms - 1];    //  Used for displaying alarm status symbol.

    //-------------------------------------------------------------------------------------

    //display bell symbol for each "active" alarm

    x = 20 - (Max_alarms / 2);  //
                                //    x = 15;    //
    y = 1;
    lcd.setCursor(x, y);
    for (byte i = 0; i < (Max_alarms / 2); i++)
    //    for (int i=0;i<5;i++)
    {
        foo[i] = clock1.alarms[i].dow;  //2, 5, 8 and 11
        if (foo[i] > 0)
        {
            lcd.print(char(0));
        }
        else
        {
            lcd.print("-");
        }
    }
    if (Max_alarms > 5)
    {
        //  Work needed here so use the line below (now) the given one as well for extra alarms.
        x = 20 - (Max_alarms / 2);  //
                                    //        x = 15;    //
        y = 2;
        lcd.setCursor(x, y);
        for (byte i = (Max_alarms / 2); i < Max_alarms; i++)
        {
            foo[i] = clock1.alarms[i].dow;  //2, 5, 8 and 11
            if (foo[i] > 0)
            {
                lcd.print(char(0));
            }
            else
            {
                lcd.print("-");
            }
        }
    }

    //-------------------------------------------------------------------------------------

    //  Display the "defered alarm" symbol on the screen if the next alarm is defered.

    //    byte boo_x;
    x = 0;
    y = 0;
    boo = alarm_defere(0);
    lcd.setCursor(x, y);
    /*
    Serial.println("------------------");
    Serial.println(" alarm defer routine");
    Serial.print("Al flag ");
    Serial.print(al_flag);
*/
    if (boo == 0)
    {
        if (al_flag == 0)
        {
            lcd.print("                   ");
            al_flag = 1;
        }
    }
    if (boo == 1)
    {
        lcd.print("X");
        al_flag = 0;
    }
    if (boo == 3)
    {
        al_flag = 0;
        static int last_sec;
        if (last_sec != rtc[0])
        {
            last_sec = rtc[0];
            if (last_sec % 2 == 0)
            {
                //
                lcd.print("ALL alarms DISABLED");
            }
            else
            {
                lcd.print("      WARNING!     ");
            }
        }
    }

    //-------------------------------------------------------------------------------------

    //  Display the LIGHT icon indicating the light has been manually activated.
    x = 1;
    y = 2;
    lcd.setCursor(x, y);
    boo = light_toggle(0);
    if (boo == 0)
    {
        lcd.print(" ");
    }
    if (boo == 1)
    {
        lcd.print(char(3));
    }

    //-------------------------------------------------------------------------------------

    //  Display the BOLT icon indicating the blanket has been turned on.
    x = 0;
    y = 2;
    lcd.setCursor(x, y);
    boo = leky_blanky(0);
    if (boo == 0)
    {
        lcd.print(" ");
    }
    if (boo == 1)
    {
        lcd.print(char(2));
    }

    //-------------------------------------------------------------------------------------

    // sleep time remaining routine.
    x = 2;
    y = 2;
    lcd.setCursor(x, y);
    boo = sleep_time(0, 0);
    //  text format:  " @ nn"  Where @ is the timer char and nn are numbers.  Length = 5
    if (boo == 0)
    {
        lcd.print("     ");
    }
    if (boo > 0)
    {
        lcd.print(char(1));
        lcd.print(" ");
        lcd.print(boo);
        if (boo < 9)
        {
            lcd.print(" ");
        }
    }

    //-------------------------------------------------------------------------------------

    //  RDO routine.
    //  These lines are semi-debuging stuff.
    lcd.setCursor(18, 3);
    lcd.print(week_num);
    lcd.print(rtc[3]);
    lcd.setCursor(0, 3);
    lcd.print(skip_day);
    //  End debug lines.
    x = 6;
    y = 2;
    lcd.setCursor(x, y);
    if (week_num == 1)
    {
        //
        if (rtc[3] == (skip_day - 1))
        {
            lcd.print("Tomorrow");
            skip_day_flag = 0;  //  THis is only for testing reasons.  Can be deleted later
        }
        else if (rtc[3] == skip_day)
        {
            lcd.print("R.D.O.  ");
            if (skip_day_flag != 1)
            {
                alarm_defere(1);
                skip_day_flag = 1;
            }
        }
        else
        {
            lcd.print("        ");
            //            skip_day_flag = 0;
        }
    }

    //-------------------------------------------------------------------------------------

    //  Show when DLS is active.  This may be temporary.
    x = 0;
    y = 1;
    lcd.setCursor(x, y);
    if (DLS_Flag == 1)
    {
        lcd.print("DLS");
    }
    else
    {
        lcd.print("   ");
    }

    //-------------------------------------------------------------------------------------

    //-------------------------------------------------------------------------------------

    //  Other things happen below.
}
//  The line above needs to stay "outside" the other functions to close the bigger "display_stuff()" function.

/*============================================================================================================================*/

//  (Example menu)

// Menu texts
//  If more items are addeed, you also have to edit in the menu settings below!

const PROGMEM char top_menu_item00[] = "Display clock";
const PROGMEM char top_menu_item01[] = "List alarms";
const PROGMEM char top_menu_item02[] = "Set alarms";
const PROGMEM char top_menu_item03[] = "Adjust time";
const PROGMEM char top_menu_item04[] = "Adj' alarm run time";
const PROGMEM char top_menu_item05[] = "Blanket off time";
const PROGMEM char top_menu_item06[] = "Set skip day";
const PROGMEM char top_menu_item07[] = "Audio flag";
const PROGMEM char top_menu_item08[] = "Show key functions";
const PROGMEM char top_menu_item09[] = "Light run time";
const PROGMEM char top_menu_item10[] = "Blanket run time";
const PROGMEM char top_menu_item11[] = "Test audio outputs";
const PROGMEM char top_menu_item12[] = "Display boot information";
const char *const top_menu_items[] = { top_menu_item00, top_menu_item01, top_menu_item02, top_menu_item03, top_menu_item04, top_menu_item05, top_menu_item06, top_menu_item07, top_menu_item08, top_menu_item09, top_menu_item10, top_menu_item11, top_menu_item12 };

//This program is the main menu. It handles inputs from the keys, updates the menu or executes a certain menu function accordingly.
byte clock_style = 0;  // This is the style of the menu
void top_menu()
{
    //  Display the clock at boot up.
    lcd.clear();
    top_menu_function_1();

    byte menu_pointer_1 = 0;   // This stores the menu choice the user made.
    phi_prompt_struct myMenu;  // This structure stores the main menu.

    // Initialize the top menu
    myMenu.ptr.list = (char **)&top_menu_items;  // Assign the list to the pointer
    myMenu.low.i = 0;                            // Default item highlighted on the list
    myMenu.high.i = 12;                          // Last item of the list is size of the list - 1.
    myMenu.width = lcd_columns - 1;              // Length in characters of the longest list item.
    myMenu.step.c_arr[0] = lcd_rows - 1;         // rows to auto fit entire screen
    myMenu.step.c_arr[1] = 1;                    // one col list
    myMenu.step.c_arr[2] = 0;                    // y for additional feature such as an index
    myMenu.step.c_arr[3] = lcd_columns - 6;      // x for additional feature such as an index
    myMenu.col = 0;                              // Display prompt at column 0
    myMenu.row = 1;                              // Display prompt at row 1
    myMenu.option = 45;

    while (1)  // This loops every time a menu item is selected.
    {
        lcd.clear();  // Refresh menu if a button has been pushed
        lcd.print("Main Menu");

        select_list(&myMenu);           // Use the select_list to ask the user to select an item of the list, that is a menu item from your menu.
        menu_pointer_1 = myMenu.low.i;  // Get the selected item number and store it in the menu pointer.
        switch (menu_pointer_1)         // See which menu item is selected and execute that correspond function
        {
            case 0:
                lcd.clear();
                top_menu_function_1();
                break;

            case 1:
                lcd.clear();
                top_menu_function_4();
                break;

            case 2:
                lcd.clear();
                top_menu_function_3();
                break;

            case 3:
                lcd.clear();
                top_menu_function_2();
                break;

            case 4:
                lcd.clear();
                top_menu_function_5();
                break;

            case 5:
                lcd.clear();
                top_menu_function_6();
                break;

            case 6:
                lcd.clear();
                top_menu_function_7();
                break;

            case 7:
                lcd.clear();
                top_menu_function_8();
                break;

            case 8:
                lcd.clear();
                top_menu_function_9();
                break;

            case 9:
                lcd.clear();
                top_menu_function_10();
                break;

            case 10:
                lcd.clear();
                top_menu_function_11();
                break;

            case 11:
                lcd.clear();
                top_menu_function_12();
                break;

            case 12:
                lcd.clear();
                bootup();
                break;

                /*
      //  This is a dummy if more menu options are added.
      case :
      lcd.clear();
      top_menu_function_();
      break;
*/
            default:
                break;
        }
    }
}

/*============================================================================================================================*/

// Menu functions go here. The functions are called when their menu items are selected. They are called only once so if you want to do something repeatedly, make sure you have a while loop.

void top_menu_function_1()  //This runs the clock
{
    lcd.clear();
    lcd.print("Escape key for menu");
    wait_on_escape(600);
    lcd.clear();
    byte temp1;
    while (1)
    {
        clock1.run();
        //  Can I put the "If (ABO==0)" routine here?
        //  Taken from alarm_clock
        if (!clock1.alarm_is_on)
        {
            temp1 = wait_on_escape(800);
            switch (temp1)
            {
                case 0:
                    break;

                case 1:  // UP key
                    alarm_defere(1);
                    break;

                // ALL Alarms ON/OFF quick toggle.
                case 2:  // DOWN key
                    alarm_defere(2);
                    break;

                //  Electric blanket ON/OFF function.   Needs work for time specific on period.
                case 3:  // LEFT key
                    leky_blanky(1);
                    break;

                // call my routine (in alarm_clock) to toggle light.
                case 4:  // RIGHT key
                    light_toggle(1);
                    break;

                //  call my routine for sleep time (in alarm_clock).
                case 5:  // ENTER key
                    sleep_time(30, 30);

                    //digitalWrite(LED,HIGH);
                    break;

                //  This is the ESCAPE key and exits back to the menu
                case 6:  // ESCAPE key
                    return;

                default:
                    break;
            }
        }
    }
}

/*============================================================================================================================*/

void top_menu_function_2()  //Set the clock
{
    int user_input;
    phi_prompt_struct myIntegerInput, myListInput;  // This structure stores the main menu.

    render_RTC(0);
    RTC.get(rtc, true);

    user_input = rtc[6];                        // Current value
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 2000;                // Lower limit
    myIntegerInput.high.i = 2099;               // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 6;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 4;                   // The number occupies 2 characters space
    myIntegerInput.option = 0;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Year");                                            // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) rtc[6] = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    myListInput.ptr.list = (char **)&month_items;  // Assign the list to the pointer
    myListInput.low.i = rtc[5] - 1;                // Default item highlighted on the list
    myListInput.high.i = 11;                       // Last item of the list is size of the list - 1.
    myListInput.width = 3;                         // Length in characters of the longest list item.
    myListInput.col = 0;                           // Display prompt at column 0
    myListInput.row = 1;                           // Display prompt at row 1
    myListInput.option = 1;
    myListInput.step.c_arr[0] = lcd_rows - 1;     // rows to auto fit entire screen
    myListInput.step.c_arr[1] = lcd_columns / 4;  // multi col list
    lcd.clear();
    center_text("Month");                                                 // Prompt user for input
    if (select_list(&myListInput) != -1) rtc[5] = myListInput.low.i + 1;  // select_list stores user choice in myListInput.low. If the user didn't press escape (return -1) then update the user choice with the value in myListInput.low.
    else
        return;

    user_input = rtc[4];         // Current value
    myIntegerInput.low.i = 1;    // Lower limit
    myIntegerInput.high.i = 31;  // Upper limit
    lcd.clear();
    center_text("Date");                                            // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) rtc[4] = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    myListInput.ptr.list = (char **)&dow_items;  // Assign the list to the pointer
    myListInput.low.i = rtc[3] - 1;              // Default item highlighted on the list
    myListInput.high.i = 6;                      // Last item of the list is size of the list - 1.
    myListInput.width = 3;                       // Length in characters of the longest list item.
    myListInput.col = 0;                         // Display prompt at column 0
    myListInput.row = 1;                         // Display prompt at row 1
    myListInput.option = 1;
    myListInput.step.c_arr[0] = lcd_rows - 1;     // rows to auto fit entire screen
    myListInput.step.c_arr[1] = lcd_columns / 4;  // multi col list
    lcd.clear();
    center_text("Day of the week");                                       // Prompt user for input
    if (select_list(&myListInput) != -1) rtc[3] = myListInput.low.i + 1;  // select_list stores user choice in myListInput.low. If the user didn't press escape (return -1) then update the user choice with the value in myListInput.low.
    else
        return;

    user_input = rtc[2];                        // Current value
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 0;                   // Lower limit
    myIntegerInput.high.i = 23;                 // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 7;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Hour");                                            // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) rtc[2] = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    user_input = rtc[1];         // Current value
    myIntegerInput.low.i = 0;    // Lower limit
    myIntegerInput.high.i = 59;  // Upper limit
    lcd.clear();
    center_text("Minute");                                          // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) rtc[1] = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    user_input = rtc[0];  // Current value
    lcd.clear();
    center_text("Second");                                          // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) rtc[0] = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    RTC.stop();
    RTC.set(DS1307_SEC, rtc[0]);        //rtc[0]
    RTC.set(DS1307_MIN, rtc[1]);        //rtc[1]
    RTC.set(DS1307_HR, rtc[2]);         //rtc[2]
    RTC.set(DS1307_DOW, rtc[3]);        //rtc[3] value from 1 to 7. User define whether 1 is sun or mon.
    RTC.set(DS1307_DATE, rtc[4]);       //rtc[4] dat
    RTC.set(DS1307_MTH, rtc[5]);        //rtc[5] Month
    RTC.set(DS1307_YR, rtc[6] - 2000);  //rtc[6] Year only has years since 2000 so 10 represents 20100.
    RTC.start();
}

/*============================================================================================================================*/

void top_menu_function_3()  //Set alarms
{
    byte temp1;
    byte ala = 0;
    char msg[17];
    int user_input;
    phi_prompt_struct myIntegerInput, myListInput;  // This structure stores the main menu.
    lcd.clear();
    sprintf(msg, "Alarm %02d:", 0);
    lcd.print(msg);

    user_input = 0;                             // Current value
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 0;                   // Lower limit
    myIntegerInput.high.i = Max_alarms - 1;     // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 7;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Which alarm?");                                 // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) ala = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    user_input = clock1.alarms[ala].hr;  // Current value
    myIntegerInput.high.i = 23;          // Upper limit
    lcd.clear();
    center_text("Hour");                                                           // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) clock1.alarms[ala].hr = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    user_input = clock1.alarms[ala].mnt;  // Current value
    myIntegerInput.high.i = 59;           // Upper limit
    lcd.clear();
    center_text("Minute");                                                          // Prompt user for input
    if (input_integer(&myIntegerInput) != -1) clock1.alarms[ala].mnt = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    else
        return;

    myListInput.ptr.list = (char **)&alarm_items;  // Assign the list to the pointer
    myListInput.low.i = clock1.alarms[ala].dow;    // Default item highlighted on the list
    myListInput.high.i = 4;                        // Last item of the list is size of the list - 1.
    myListInput.width = 7;                         // Length in characters of the longest list item.
    myListInput.col = 0;                           // Display prompt at column 0
    myListInput.row = 1;                           // Display prompt at row 1
    myListInput.option = 1;                        // Option 0, display classic list, option 1, display 2X2 list, option 2, display list with index, option 3, display list with index2.
    myListInput.step.c_arr[0] = lcd_rows - 1;      // rows to auto fit entire screen
    myListInput.step.c_arr[1] = lcd_columns / 8;   // multi col list
    lcd.clear();
    center_text("Type");                                                              // Prompt user for input
    if (select_list(&myListInput) != -1) clock1.alarms[ala].dow = myListInput.low.i;  // select_list stores user choice in myListInput.low. If the user didn't press escape (return -1) then update the user choice with the value in myListInput.low.
    else
        return;

    //  If the alarm is set for ONCE, don't store it in EEPROM memory.
    if (myListInput.low.i != 4)
    {
        EEPROM.write(alarm_EEPROM_storage + 3 * ala, clock1.alarms[ala].hr);  // Alarm hour
        delay(100);

        EEPROM.write(alarm_EEPROM_storage + 3 * ala + 1, clock1.alarms[ala].mnt);  // Alarm minute
        delay(100);

        EEPROM.write(alarm_EEPROM_storage + 3 * ala + 2, clock1.alarms[ala].dow);  // Alarm frequency M-F
        delay(100);
    }
}

/*============================================================================================================================*/

void top_menu_function_4()  //Display a list of the alarms and times.

/*
    What I have learnt:
    alarm_EEPROM_storage+n (where n is the alarm number) yields 0,1,2,3
    0 = off
    1 = Daily
    2 = M-F
    3 = Weekend
    4 = Once

bit of information about the RTC alarms.
clock1.alarms[ala].hr;
clock1.alarms[ala].mnt;
clock1.alarms[ala].dow;

*/
{
    byte boo;
    char msg[14];
    byte button_pressed;
    byte j = 0;
    byte i;
    lcd.clear();
    lcd.print(" Alarm list (u/d/e)");
    while (1)
    {
        button_pressed = wait_on_escape(500);
        switch (button_pressed)
        {
            case 0:
                break;

            case 1:  // up key
                if (j > 1)
                {
                    j = (j - 3) % (Max_alarms - 1);
                }
                break;

            case 2:  //  down key
                if (j < Max_alarms - 2)
                {
                    j = (j + 3) % (Max_alarms - 1);
                }
                break;

            case 6:  //  escape key
                return;

            default:
                break;
        }

        for (i = j; i < (j + 3); i++)
        {
            lcd.setCursor(0, (i % 3) + 1);
            if (i > Max_alarms - 1)
            {
                //    Clear text on line for alarms which don't exist.
                lcd.print("                    ");
            }
            else
            {
                sprintf(msg, "Alm %1d %2d:%02d ", i, clock1.alarms[i].hr, clock1.alarms[i].mnt);
                boo = clock1.alarms[i].dow;
                lcd.print(msg);
                if (boo == 0)
                {
                    lcd.print("OFF     ");
                }
                if (boo == 1)
                {
                    lcd.print("Daily   ");
                }
                if (boo == 2)
                {
                    lcd.print("Week Day");
                }
                if (boo == 3)
                {
                    lcd.print("Week End");
                }
                if (boo == 4)
                {
                    lcd.print("Once    ");
                }
            }
        }
    }
}

/*============================================================================================================================*/

int top_menu_function_5()  //Adjust alarm run time
{
    int user_input;
    phi_prompt_struct myIntegerInput;

    user_input = EEPROM.read(EEPROM_user + 0);
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 0;                   // Lower limit
    myIntegerInput.high.i = 240;                // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 7;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Alarm run time");  // Prompt user for input
    if (input_integer(&myIntegerInput) != -1)
    {
        alarm_run_time = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
        EEPROM.write(EEPROM_user + 0, alarm_run_time);
        delay(100);
    }
    else
        return (0);
}

/*============================================================================================================================*/

/*
      This is my attempt to add the menu at what time to turn off the blanket - EVERY DAY!
*/

void top_menu_function_6()  //Blanket off time
{
    int user_input;
    phi_prompt_struct myIntegerInput;

    user_input = blanket_off_time_hr;
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 0;                   // Lower limit
    myIntegerInput.high.i = 23;                 // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 8;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    lcd.print("Blanket off time:");  // Prompt user for input
    lcd.setCursor(0, 1);
    lcd.print("Hour:");
    lcd.setCursor(0, 2);
    lcd.print("Minute:");  // Prompt user for input
    lcd.setCursor(8, 2);
    lcd.print(blanket_off_time_mnt);
    if (input_integer(&myIntegerInput) != -1)
    {
        blanket_off_time_hr = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
    }
    user_input = blanket_off_time_mnt;
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 0;                   // Lower limit
    myIntegerInput.high.i = 59;                 // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 8;                     // Display prompt at column 7
    myIntegerInput.row = 2;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    if (input_integer(&myIntegerInput) != -1)
    {
        blanket_off_time_mnt = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
        //
        EEPROM.write(EEPROM_user + 1, blanket_off_time_hr);
        delay(100);
        EEPROM.write(EEPROM_user + 2, blanket_off_time_mnt);
        delay(100);
    }
    else
        return;
}

/*============================================================================================================================*/

void top_menu_function_7()  //Skip day settings
{
    //
    boolean week;
    lcd.clear();
    lcd.print(F("Which day to skip? "));  // Don't know if I need this line.  See next line.
    skip_day = simple_select_list("Which day to skip\nOff\nMonday\nTuesday\nWednesday\nThursday\nFriday\n");
    skip_day = skip_day + 1;

    Serial.print("Skip day ");
    Serial.println(skip_day);

    //    Need to now set which week to skip.
    //
    week = simple_select_list("Which week?\nThis\nNext\n");

    Serial.print("Week ");
    Serial.println(week);
    Serial.print("Week num ");
    Serial.println(week_num);

    week_num = week ^ (week_num & 1);  //    2017 06 24 added ( ) around the week_num & 1 part

    Serial.print("Week XOR week_num ");
    Serial.println(week_num);
    Serial.println("-------------");

    lcd.clear();
    lcd.print("day / week_num");
    lcd.setCursor(0, 1);
    lcd.print(skip_day);
    lcd.print("    ");
    lcd.print(week_num);

    EEPROM.write(EEPROM_user + 6, skip_day);
    delay(100);
    EEPROM.write(EEPROM_user + 7, week_num);
    delay(1500);
    return;
}

/*============================================================================================================================*/

boolean top_menu_function_8()  //Audio flag alterer.
{
    int user_input;
    int audio_flag;
    phi_prompt_struct myIntegerInput;

    user_input = EEPROM.read(EEPROM_user + 8);
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 0;                   // Lower limit
    myIntegerInput.high.i = 2;                  // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 7;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 1;                   // The number occupies 2 characters space
    myIntegerInput.option = 0;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Audio control");  // Prompt user for input
    if (input_integer(&myIntegerInput) != -1)
    {
        audio_flag = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.

        if (input_integer(&myIntegerInput) != -1)
        {
            EEPROM.write(EEPROM_user + 8, audio_flag);
            delay(100);
        }
    }
    else
        return (0);
}

/*============================================================================================================================*/

void top_menu_function_9()
{
    show_keys();
}

/*============================================================================================================================*/

int top_menu_function_10()  //Adjust Light on time
{
    int user_input;
    phi_prompt_struct myIntegerInput;

    user_input = EEPROM.read(EEPROM_user + 9);
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 1;                   // Lower limit
    myIntegerInput.high.i = 99;                 // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 7;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Light on time");  // Prompt user for input
    if (input_integer(&myIntegerInput) != -1)
    {
        light_run_time = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
        EEPROM.write(EEPROM_user + 9, light_run_time);
        delay(100);
    }
    else
        return (0);
}

/*============================================================================================================================*/

int top_menu_function_11()  //Adjust blanket time
{
    int user_input;
    phi_prompt_struct myIntegerInput;

    user_input = EEPROM.read(EEPROM_user + 10);
    myIntegerInput.ptr.i_buffer = &user_input;  // Pass the address of the buffer
    myIntegerInput.low.i = 1;                   // Lower limit
    myIntegerInput.high.i = 99;                 // Upper limit
    myIntegerInput.step.i = 1;                  // Step size
    myIntegerInput.col = 7;                     // Display prompt at column 7
    myIntegerInput.row = 1;                     // Display prompt at row 1
    myIntegerInput.width = 2;                   // The number occupies 2 characters space
    myIntegerInput.option = 1;                  // Option 0, space pad right, option 1, zero pad left, option 2, space pad left.
    lcd.clear();
    center_text("Blanket run time");  // Prompt user for input
    if (input_integer(&myIntegerInput) != -1)
    {
        blanket_run_time = user_input;  // If the user didn't press escape (return -1) then update the ultimate storage with the value in the buffer.
        EEPROM.write(EEPROM_user + 10, blanket_run_time);
        delay(100);
    }
    else
        return (0);
}

/*============================================================================================================================*/
int top_menu_function_12()  //Test audio outputs of audio card
{
    audio_test();
}
/*============================================================================================================================*/

The error seems quite obvious. You are calling the render_RTC() function and it is not in the sketch. Where did you get the code that tries to call it ?

Well, I am not sure about that.

Well, ok.

But the .h file.... Is that a library?

I seem to remember DrLui wrote the original alarmclock sketch and the alarmclock.h file was in there.

Anyway, it is kind of good that we are at this point.

Should I maybe included the .ino file in the main part?

As I mentioned: Some places don't allow big files to be posted.

Yeah, ok I maybe should have tried before posting the zip.

I know now this forum does support such long files.

As I just mentioned in the other post - just now - DrLui wrote an alarm clock sketch upon which I built this. (On Wordpress)

But I'm not sure if it still exists in it's original form.
DId a quick search and didn't find anything.

I am not clear which .h file you are referring to. Such files can be part of a library or just contain definitions of variables. They can contain code too but that is generally regarded as bad practice and code goes in the associated .cpp file

So where did you get the code that calls the missing function ?

Though on a different site now, this looks like where I got the original code:

The .h file is the one which I included in the alarm_clock.zip I attached in post 75

Bit more digging and this looks very much like the kit I bought way back when.

Though I use a 20x4 display.