Problems following code.

I'm really new to this and am stuck.

Ok, here we go: (Edited to fit)

/*
// Menu texts
PROGMEM prog_char top_menu_item00[]="Display clock";
PROGMEM prog_char top_menu_item01[]="Adjust time";
PROGMEM prog_char top_menu_item02[]="Set alarms";
PROGMEM prog_char top_menu_item03[]="Display settings";
PROGMEM prog_char top_menu_item04[]="Show credit";
PROGMEM const char *top_menu_items[] = {top_menu_item00, top_menu_item01, top_menu_item02, top_menu_item03, top_menu_item04};

//This program is the main menu. It handles inputs from the keys, updates the menu or executes a certain menu function accordingly.
int clock_style=0; // This is the style of the menu
void top_menu()
{
  int 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=4; // 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-4; // 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_2();
      break;
  
      case 2:
      lcd.clear();
      top_menu_function_3();
      break;
      
      case 3:
      lcd.clear();
      top_menu_function_4();
      break;
      
      case 4:
      lcd.clear();
      top_menu_function_5();
      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.
// somewhere in here is the DISPLAY TIME function for which I am looking.
void top_menu_function_1() //This runs the clock
{
  lcd.clear();
  center_text("Anykey to return");
  wait_on_escape(1000);
  lcd.clear();
  int temp1;
  while (1)
  {
    clock1.run();
    if (!clock1.alarm_is_on)
    {
      temp1=wait_on_escape(1000);
      switch (temp1)
      {
        case 0:
        break;
        
        default:
        return;
        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[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;
  
  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;

Yeah, ok, excuse the whole lot of code there.

This is the part which has me stuck - I think:

// 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.
// somewhere in here is the DISPLAY TIME function for which I am looking.
void top_menu_function_1() //This runs the clock
{
  lcd.clear();
  center_text("Anykey to return");
  wait_on_escape(1000);
  lcd.clear();
  int temp1;
  while (1)
  {
    clock1.run();
    if (!clock1.alarm_is_on)
    {
      temp1=wait_on_escape(1000);
      switch (temp1)
      {
        case 0:
        break;
        
        default:
        return;
        break;
      }
    }
  }  
}

I don't know.

The clock works. The time is displayed, but I want to edit HOW it is displayed.

As now it is: MAY/19/2012/SAT

I would prefer something like: SAT MAY 19 2012

It isn't rocket science, but I am stuffed if I can resolve what part of the code does the displaying of the time.

The "complete" code is the "simple easy programmable multiday alarm clock" sketch. I won't put it all here (again) because I am sure that I am looking in the right part, but don't know how to resolve these functions when they call other files.

That last function may "run the clock" but it doesn't display the time on the LCD. Nor does anything in the first code block.

The "complete" code is the "simple easy programmable multiday alarm clock" sketch.

That comes with what library?

The code printing the clock is not posted:)

I suggest you look inside the file here: alarm_clock line 31-52 Play with those lines. I don't remember promising the clock was simple though.

Thanks.

On the clock's display I get: May/20/2012/Sun

This is where I am at:

  case 0:
    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=lcd_columns/2-8; // Display prompt at column 0
    myListInput.row=lcd_rows/2-1; // Display prompt at row 1
    myListInput.option=0; 
    myListInput.step.c_arr[0]=1; // rows to auto fit entire screen
    myListInput.step.c_arr[1]=1; // one col list
    render_list(&myListInput);
    sprintf(msg,"/%02d/%4d/",rtc[4],rtc[6]);
    lcd.print(msg);

Now I have resolved the data to be controlled by the line

sprintf(msg,"/%02d/%4d/",rtc[4],rtc[6]);

If I change it to: sprintf(msg," %02d %4d ",rtc[4],rtc[6]);

I get: May 20 2012 SUN

Which is a bit nicer to read.

But this is where I get stuck: sprintf( I'm guessing this is something like the PRINT command but then again, probably now because of the next line in the code.

msg,"/%02d/%4d/",rtc[4],rtc[6] This will take some work msg must be the month - but I am not sure how that works. /%02d It actually 2 things: the / then %02d. And d is not for date. (We'll skip the next /) %4d Is the year

Here's where it falls down.

rtc[4] and rtc[6] are left, but I only have the "day of week" left.

So the line: lcd.print(msg); prints the (msg) on the screen.

rtc(4) is the "day of week" and rtc(6) is the time? They are concatenated and something splits them and displays them on the two lines.

But why the weird/non-consistent names? msg %02d %04d rtc(4) rtc(6)

Ok, it is academic what they are called, so long as the code works, but for readability?

Anyway, I've made a big enough fool of my self already asking what I have just asked.

I'll stop before I make an even bigger fool of myself by continuing and trying to understand it all, because obviously my way of seeing it is not correct.

Looks like you need to spend some time reading how sprintf() works.

http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

Yup.

But what I have also learned - though bashing my head on the wall - is the %02 %4 things.

%02 means 2 digits with leading 0.

So the line is formatting rtc[4] and 6 (maybe) to a 2 digit leading 0 and 4 digit space.

But where does the MONTH and DAY come from?

(Reading link supplied now)

I can feel my IQ level falling to single digit figures quickly.

I can’t believe I am this stupid. Though I have been told.

Reading the link supplied:
int sprintf ( char * str, const char * format, … );
Write formatted data to string
Writes into the array pointed by str a C string consisting on a sequence of data formatted as the format argument specifies. After the format parameter, the function expects at least as many additional arguments as specified in format.

(this is really going to show how stupid I am)

int - huh? There is no int in the line of code.

    • again there aren’t any of these as separators of different parts
      “Write formatted data to string” – err, which string? I’m guessing from their template: char?
      The examples given in the table on the page are confusing to me.

(Yeah, RTFM, lean C, etc etc.)
Surely a simple template and then what is written in the code can be easily taken apart and resolved to what parts are what.

As this is the line from the code:
sprintf(msg," %02d %4d ",rtc[4],rtc[6]);

I honestly can’t transpose the template to what is written above.

You can't just call anything you don't understand academic or infer it's only useful in the classroom but is never useful outside. I'm sure relativity is difficult and academic considered by some but that is what runs your GPS. This sprintf is just a simple function that you should have come across if you had about 1/3 of a semester of c programming class or read through 1/3 of a c programming book yourself. James provided a good resource for the function, which I often use from time to time. If you can just admit you can't program, you probably feel better every time you are stuck, it's opportunity to learn not opportunity to blame.

Here is a tutorial, probably fitting your skill level better. The link James provided is better for reference not for first encounter.

http://liudr.wordpress.com/2012/01/16/sprintf/

sprintf(msg," %02d %4d ",rtc[4],rtc[6]);

Broken down:

msg: a string (char[]) that the new string gets dumped into ": Start of the string %02d: decimal (placeholder) with 2 digits %04d: decimal (placeholder) with 4 digits ": End of the String

The next two arguments are for each of the place holders. rtc[4] goes with the first %d and rtc[6] goes with the 2nd.

The Day is coming from somewhere else in the code.

The following prints out everything:

    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=lcd_columns/2-8; // Display prompt at column 0
    myListInput.row=lcd_rows/2-1; // Display prompt at row 1
    myListInput.option=0; 
    myListInput.step.c_arr[0]=1; // rows to auto fit entire screen
    myListInput.step.c_arr[1]=1; // one col list
    render_list(&myListInput);
    sprintf(msg,"/%02d/%4d/",rtc[4],rtc[6]);
    lcd.print(msg);
    
    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.col=lcd_columns/2-8+12; // Display prompt at column 0
    render_list(&myListInput);

It prints out month with the first 10 lines of code, using phi_prompt library. Since you are still learning programming in C, explaining another thing should be saved for later. Try this:

    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=lcd_columns/2-8; // Display prompt at column 0
    myListInput.row=lcd_rows/2-1; // Display prompt at row 1
    myListInput.option=0; 
    myListInput.step.c_arr[0]=1; // rows to auto fit entire screen
    myListInput.step.c_arr[1]=1; // one col list
    render_list(&myListInput);
    
    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.col=lcd_columns/2-8+4; // Display prompt at column 0
    render_list(&myListInput);

    sprintf(msg," %02d %4d/",rtc[4],rtc[6]);
    lcd.print(msg);

Well, I've learned something.

I was shown a few things/tricks with the code.

Sorry for all the mess below. I am trying to do things and not having luck.

All part of the learning curve.

This is the original code in "question":

  {
    case 0:
    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=lcd_columns/2-8; // Display prompt at column 0   // note this line.
    myListInput.row=lcd_rows/2-1; // Display prompt at row 1
    myListInput.option=0; 
    myListInput.step.c_arr[0]=1; // rows to auto fit entire screen
    myListInput.step.c_arr[1]=1; // one col list
    render_list(&myListInput);

//  there are 10 lines here. (above)
// now I have been shown the importance of reading the comments.  The block above does the MONTH.

    sprintf(msg," %02d %4d ",rtc[4],rtc[6]);
    lcd.print(msg);
    
    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.col=lcd_columns/2-8+12; // Display prompt at column 0    and note this line.
    render_list(&myListInput);

//  Here, there are 5 lines.  This does the DAY OF WEEK.
// Ofcourse it raises the question why the different number of lines?


    lcd.setCursor(lcd_columns/2-4,lcd_rows/2);
    sprintf(msg,"%2d:%02d:%02d",rtc[2],rtc[1],rtc[0]);
    lcd.print(msg);
    break;

The first "block" of code IMPLIES to me that it is all .... something related.

But reading the two blocks, as said above: I'm confused why the first block which does the month, where as the other block which does the day of week, only has 5 lines.

So I'm guessing that some of the 5 lines in the top are not really "needed" in the BLOCK.

So it would be nicer if the structure was better formatted/parragraphed so it makes sense to idiots like me.

Now you can see I have included two lines of comments: Note this line.

I thought that these paramaters set where on the screen the text is put.

Alas I am wrong. I guess the myListInput.col=lcd_columns/2-8 mathematically doesn't work. I've tried altering the numbers here and there, but to little avail.

I am sure I can work it out - eventually - but why can't the code be better structured?

BRILLIANT NEWS!

I worked out the code - kind of.

This is my effort at the modified “routine”, so anyone with the “multiple alarm clock” program who wants to give it a go, you are quite welcome to do so.

/*
Phi-2 shield for Arduino
Program title: Phi clock version 5 
----------------------------------------
Programmed by Dr. John Liu
Revision: 02/28/2012
Free software for educational and personal uses.
No warrantee!
Commercial use without authorization is prohibited.
Find details of the Phi-1 shield, Phi-2 shield, and Phi-prompt or contact Dr. Liu at
http://liudr.wordpress.com/phi-1-shield/
http://liudr.wordpress.com/phi-2-shield/
http://liudr.wordpress.com/phi_interfaces/
http://liudr.wordpress.com/phi_prompt/
All rights reserved.
*/
#include "alarm_clock.h"

void render_RTC(int temp)
{
  int rtc[7];
  char msg[17];
  int user_input;
  phi_prompt_struct myListInput; // This structure stores the main menu.

  RTC.get(rtc,true);

  switch(temp)
  {
    case 0:

//  NOTE!  This code has been modified and the comments may no longer be correct.
// display the time  HH:MM:SS
    lcd.setCursor(lcd_columns/2-4,1);
    sprintf(msg,"%2d:%02d:%02d",rtc[2],rtc[1],rtc[0]);
    lcd.print(msg);

// display the DOW
    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=lcd_columns/2-8; // Display prompt at column 0
    myListInput.row=lcd_rows/2; // Display prompt at row 2
    myListInput.option=0; 
    myListInput.step.c_arr[0]=1; // rows to auto fit entire screen
    myListInput.step.c_arr[1]=1; // one col list
    render_list(&myListInput);

// display the date
    sprintf(msg," %02d ",rtc[4]);
    lcd.print(msg);

// display the month
    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.col=lcd_columns/2-8+7; // Display prompt at column 0
    render_list(&myListInput);

// display the year
    sprintf(msg," %4d",rtc[6]);
    lcd.print(msg);

    break;
    
    case 1:
    sprintf(msg,"%02d%02d",rtc[2],rtc[1]);
    render_big_msg(msg,lcd_columns/2-8,0);
    if ((lcd_rows==4)&&(lcd_columns==20))
    {
      strcpy_P(msg,(char*)pgm_read_word(dow_items+rtc[3]-1));
      sprintf(msg+3,"%02d",rtc[4]);
      render_big_msg(msg,0,2);
    }
    if (rtc[0]%2)
    {
      lcd.setCursor(lcd_columns/2-1,0);
      lcd.write('.');
      lcd.setCursor(lcd_columns/2-1,1);
      lcd.write('.');
    }
    else
    {
      lcd.setCursor(lcd_columns/2-1,0);
      lcd.write(' ');
      lcd.setCursor(lcd_columns/2-1,1);
      lcd.write(' ');
    }
    break;
    default:
    break;
  }
}

alarm_clock::alarm_clock(boolean noo) // This parameter is need otherwise the compiler won't work with a constructor without parameters.
{
  alarm_is_on=false;
  snooze=10;
}

byte alarm_clock::run()
{
  int rtc[7];
  render_RTC(clock_style);
  RTC.get(rtc,true);
  for (int i=0;i<4;i++)
  {
    if ((alarms[i].hr==rtc[2])&&(alarms[i].mnt==rtc[1])&&(rtc[0]==0)&&within(i,rtc[3]))
    {
      alarm_is_on=true;
    }
  }
  if (alarm_is_on) alarm();
}

byte alarm_clock::set_alarm(byte alarm_num, byte hr, byte mnt, byte dow)
{
  if (alarm_num>=Max_alarms) return 255;
  if (hr>23) return 255;
  if (mnt>59) return 255;
  alarms[alarm_num].hr=hr;
  alarms[alarm_num].mnt=mnt;
  alarms[alarm_num].dow=dow;
  return 0;
}

void alarm_clock::alarm()
{
  int temp1;
  for (int i=0;i<4;i++)
  {
    tone(buzzer,770);
    temp1=wait_on_escape(75);
    if ((temp1==5)||(temp1==6))
    {
      noTone(buzzer);
      alarm_is_on=false; // Turn off alarm
      return;
    }
    noTone(buzzer);
    temp1=wait_on_escape(75);
    if ((temp1==5)||(temp1==6))
    {
      noTone(buzzer);
      alarm_is_on=false; // Turn off alarm
      return;
    }
  }
  temp1=wait_on_escape(150);
  if ((temp1==5)||(temp1==6))
  {
    noTone(buzzer);
    alarm_is_on=false; // Turn off alarm
    return;
  }
}

boolean alarm_clock::within(byte a, byte dow) // This function checks if the day of the week is within alarm clock's trigger setting.
{
  switch(alarms[a].dow)
  {
    case 0: // Alarm is off
    return false;
    break;
    
    case 1: // Alarm is on daily
    return true;
    break;
    
    case 2: // Alarm is on M-F
    if ((dow>1)&&(dow<7)) return true;
    else return false;
    break;
    
    case 3: // Alarm is on Weekend
    if ((dow==1)||(dow==7)) return true;
    else return false;
    
    case 4: // Alarm is on once so set it to off and return true
    alarms[a].dow=0;
    return true;
    break;
    
    default:
    return false;
    break;
  }
}

void alarm_clock::turn_on(byte alarm_num) // This function is not used.
{
  if (alarm_num<Max_alarms) alarms[alarm_num].on_off=true;
} 

void alarm_clock::turn_off(byte alarm_num) // This function is not used.
{
  if (alarm_num<Max_alarms) alarms[alarm_num].on_off=false;
}

It is only cosmetic changes, but gee I feel good in working out what is going on. Well, kind of.

I still haven’t worked out some of the stuff.

Some of the values are the same for Dow and month so the second block needs not to assign these values again. I admit this is making the code less readable.

Yes, I fully admit it is not perfect coding, but - to me - it is a lot clearer than the original.

Yes, it isn't broken down correctly and explained, but I admit: I don't know what half the values are. I simply bashed my head against the wall until the things appeared where I wanted them.

There MUST be reasons why there are funny calculations done like: myListInput.col=lcd_columns/2-8; // Display prompt at column 0 Because to me 2-8 does not = 0. But I don't touch what I don't understand.

I feel quite chuffed with myself for doing it. All this from 5 minutes of face to face with someone who explained a couple of things to me.

Now all I have to do is track down where the actual alarm routine is so I can apply the other part of code change you mentioned about the buzzer(high) so it can actually switch a relay rather than buz the buzzer.

And maaybe find the LED output as well.

The date to be displayed is 16 characters long. 8 is half that. lcd_columns/2 is half the LCD width. This simply sets the cursor to display the thing at the correct location, even when you switch from 16X2 to 20X4, it's still centered. I usually don't have phone service for these FREE codes. If it is free, it means something to both the writer and the user. I'm just trying to help but there's no promise how much.