Menu structures in Flash memory

I'm using an Uno R3 with a 16 x 2 LCD and want to build a menu tree. The final tree will be quite large so the data needs to be in Flash memory as I will eventually need most of the RAM for other purposes. I have typedef'd a structure, declared a couple of strings and created two structures, but the compiler can't find them.

I have had this working in the past with a variety of commercial C compilers but the Arduino IDE seems a bit reluctant to co-operate. I think I need to use the "F()" construct somewhere, but I'm not sure where.

Some help would be gratefully accepted.

Here's the full test program and the compiler error messages:

/* 
 *
 * Menu display using structures
 *
 */

#include <LiquidCrystal.h>

typedef struct {
  byte xPos;
  byte yPos;
  char *dataString;
} menuLine;

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

PROGMEM char titleString[] = "TITLE LINE";
PROGMEM char versionString[] = "v1.0 2013-10-09";

PROGMEM menuLine titleLine = {2, 0, &titleString };
PROGMEM menuLine versionLine = { 0, 1, &versionString };

void showLine(menuLine *lineToShow) {
  setCursor(lineToShow->xPos, lineToShow->yPos);
  lcd.print(lineToShow->dataString);
}


void setup() {
  lcd.begin(16, 4);
}

void loop() {

  showLine(&titleLine);
  showLine(&versionLine);

  while(1); /* Do nothing */

}
BasicMenu:10: error: variable or field 'showLine' declared void
BasicMenu:10: error: 'menuLine' was not declared in this scope
BasicMenu:10: error: 'lineToShow' was not declared in this scope
BasicMenu:20: error: cannot convert 'char (*)[11]' to 'char*' in initialization
BasicMenu:21: error: cannot convert 'char (*)[16]' to 'char*' in initialization
BasicMenu.ino: In function 'void showLine(menuLine*)':
BasicMenu:24: error: 'setCursor' was not declared in this scope

Sorry, that should have been "lcd.setCursor()" in the function "showLine()". However, it's still not compiling.

Have you #included the avr/pgmspace header file? I don't see it.

Furthermore, program space stuff requires special functions to access. I don't know how well it would work with a structure.

No, I missed that. Thanks.

To try and debug it, I've avoided using Flash memory completely and kept it all in RAM, but it still doesn't work. It's down to two errors, which are appearing on line 10; the first "int" declaration in the typedef.

/* 
 *
 * Menu display using structures
 *
 */

#include <LiquidCrystal.h>

typedef struct {
  int xPos;
  int yPos;
  char *displayString;
} menuLine;

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

char *titleString = "TITLE LINE";
char *versionString = "v1.0 2013-10-09";

menuLine titleLine = {2, 0, titleString };
menuLine versionLine = { 0, 1, versionString };

void showMenuLine(menuLine lineToShow) {
  lcd.setCursor(lineToShow.xPos, lineToShow.yPos);
  lcd.print(lineToShow.displayString);
}

void setup() {
  lcd.begin(16, 4);
}

void loop() {

  showMenuLine(titleLine);
  showMenuLine(versionLine);

  while(1); /* Do nothing */

}

Compiler output:

BasicMenu:10: error: variable or field 'showMenuLine' declared void
BasicMenu:10: error: 'menuLine' was not declared in this scope

Well, I've got it working and there appears to be a bug in the Arduino IDE. I declare the structure thus:

typedef struct menuL {
  int xPos;
  int yPos;
  char *displayString;
} menuLine;

Now, I can use either the "struct menuL" or the typedef "menuLine" when creating structures as follows:

struct menuL titleLine = {2, 0, titleString };
menuLine versionLine = { 0, 1, versionString };

But only the "struct menuL" declaration works in a function definition as follows:

/* Using the normal structure definition in the function declaration works */
void showMenuLine(struct menuL lineToShow) {
  lcd.setCursor(lineToShow.xPos, lineToShow.yPos);
  lcd.print(lineToShow.displayString);
}
/* Using the "typedef" definition in the function declaration fails to compile */
void showMenuLine(menuLine lineToShow) {
  lcd.setCursor(lineToShow.xPos, lineToShow.yPos);
  lcd.print(lineToShow.displayString);
}

Welcome to the wonderful, ever-so-(not really)-helpful IDE.

If you look at the cpp file that is actually compiled, you'll see (I hope) exactly what the problem is.

You have two choices. Define the struct(s) in a separate file, with a .h extension. Or, add a variable as the first line of the sketch:

byte dumbShitIDEManglesStuffHere = 0;

The IDE will do it's stuff before that variable, leaving your structs alone.

Thanks Paul. I'll try the separate .h file.

I've been programming in C since the early 1980s and thought Arduino would be a great relaxed way to produce a few simple displays for our local Heritage Museum in my latter years. How wrong can one be!! I've been retired now for over 8 years and this is like being back in the office.

How wrong can one be!!

It's not that difficult. Of course, one needs to recognize that the Arduino is suited for and what is going to be a challenge. Menus are always going to be a challenge, since they imply waiting for a selection, and full-speed-ahead is the Arduino motto, not hurry-up-and-wait.

You can fix it by using a function prototype, which you would normally do anyway in C programming. eg.

void showMenuLine(menuLine lineToShow);   // <----- add this line
void showMenuLine(menuLine lineToShow) {
  lcd.setCursor(lineToShow.xPos, lineToShow.yPos);
  lcd.print(lineToShow.displayString);
}

that structure of yours has a pointer to ( presumably ) a string, but you still have to think
about where the actual string will be.

The idea is to keep all the strings and structures in Flash memory so as not to waste RAM. I'll post a working example once it's finally fixed.

FYI I couldn't get the F macro to work in all situations. Sometimes I ended up using

pgm_read_byte(&(PROGMEMname))

I also I ended up using

strcpy_P(TempRAMVariable, PROGMEMname)

for strings.