Using PROGMEM in variable declarations [SOLVED]

I’m (still) experimenting with lcd menu code from:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1242443739

How would the char arrays “Root”, “Something”, “Stuff”, etc in the menu declarations be stored in PROGMEM?

code from the lcd menu example:

    Menu top("Root"); // <--- THIS (Root)
    Menu Item1("Something"); // <-- THIS (Something), etc
    Menu Item11("Stuff");
    Menu Item12("More");
    Menu Item121("Deeper");
    Menu Item2("Other");
    Menu Item3("Etc");
    Menu Item31("So On");

Right now I’ve stored the menu names as char array consts. Once they are set to prog_chars, how do I declare them to be read from PROGMEM?

edit: a few bugs

You can declare them to be stored in Progmem. However then the strings are different from normal strings. That is: unless you library supports reading these strings from Progmem this will not work no matter how you declare it.

Workarounds: - create a copy in SRAM prior to calling - patch the library - inherit from the librarie's class and overwrite the corresponding methods

Looks to me like you need to modify the menu class code by changing "char *" to "const __FlashStringHelper *" in a few places. Then you can use the F() macro to put the strings in progmem.

There is a thread over here regarding the same basic question: http://arduino.cc/forum/index.php/topic,87902.0.html

@gardner: I looked at that thread but it doesn’t seem to apply to variable declarations. In a routine I can easily copy a char array from PROGMEM using strcpy_P…

@dc42: I made these changes to Menu.h and Menu.cpp:

Menu.h

 __FlashStringHelper *name;//Name of this Menu

 Menu(__FlashStringHelper *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
 Menu(__FlashStringHelper *n,boolean (*c)(Menu&));//Constructs the Menu with a specified use function

Menu.cpp

  Menu::Menu(__FlashStringHelper *n)  
  {
    name=n;
    canEnter=NULL;
  }
  
  Menu::Menu(__FlashStringHelper *n,boolean (*c)(Menu&))
  {
    name=n;
    canEnter=c;
  }

When I define

  Menu top(F("Root"));

I get the error “statement-expressions are not allowed outside functions nor in template-argument lists”

Any further ideas?

You should use "const FlashStringHelper *" not "FlashStringHelper *" throughout, it's more type-correct. To avoid that error message, add this to the public member declarations of class Menu in Menu.h:

void setName(const __FlashStringHelper *n) { name = n; }

Then you can do this:

Menu top(NULL);

void setup()
{
  top.setName(F("Root"));
}

and it compiles. It appears that the F() macro cannot be used outside a function.

EDIT: or, since "name" is declared public in the version of the library I am looking at, even simpler is just to do this this:

Menu top(NULL);

void setup()
{
  top.name = F("Root");
}

Thanks dc42.

Another question for you.

As the char arrays get compared more than once I've set the menu strings as progmem constants, eg: prog_char Name[] PROGMEM = "...";

How would you assign the 'name' variable this way? I've been using strcpy_P but when the actual name gets compared it doesn't work. I hope this makes sense.

It’s only the F() macro that has to be inside a function, so try initializing it directly, like this:

prog_char Name[] PROGMEM = "...";
...
Menu top((const __FlashStringHelper*)Name);
prog_char Name[] PROGMEM = "...";
...
Menu top((const __FlashStringHelper*)Name);

I can't seem to get that to compile. Here's the source I'm working with:

example.ino (partial)

  Menu top(MENUCONST_ROOT);
  LCDMenu2 Root(top, LCD_rows, LCD_cols, 0, 1);   
  Menu Item1(MENUCONST_MENU1);
  Menu Item2(MENUCONST_MENU2);

defs.h

  prog_char MENUCONST_ROOT[] PROGMEM = "Root";
  prog_char MENUCONST_MENU1[] PROGMEM = "Menu1;
  prog_char MENUCONST_MENU2[] PROGMEM = "Menu2";

Menu.h (partial)

public:
 char *name;//Name of this Menu
 boolean (*canEnter)(Menu&);//Function to be called when this menu is 'used'

 Menu(prog_char *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
 Menu(prog_char *n, boolean (*c)(Menu&));//Constructs the Menu with a specified use function

Menu.cpp (partial)

  Menu::Menu(prog_char *n)
  {
    name=n;  // here i tried using strcpy_P to a preallocated char buffer[30]
    canEnter=NULL;
  }
  
  Menu::Menu(prog_char *n,boolean (*c)(Menu&))
  {
    name=n; // here i tried using strcpy_P to a preallocated char buffer[30]
    canEnter=c;
  }

You're not using "const __FlashStringHelper *" in the Menu code as I suggested, you're using "prog_char *" in some places and "char *" in others. So of course it won't compile. Use "const __FlashStringHelper" throughout as I suggested. Alternatively, if you will be naming all your menu strings and never passing F() string literals to the Menu constructor, try this:

  Menu top(MENUCONST_ROOT);
  LCDMenu2 Root(top, LCD_rows, LCD_cols, 0, 1);   
  Menu Item1(MENUCONST_MENU1);
  Menu Item2(MENUCONST_MENU2);

defs.h

  const prog_char MENUCONST_ROOT[] PROGMEM = "Root";
  const prog_char MENUCONST_MENU1[] PROGMEM = "Menu1;
  const prog_char MENUCONST_MENU2[] PROGMEM = "Menu2";

Menu.h (partial)

public:
 const __FlashStringHelper * name;//Name of this Menu
 boolean (*canEnter)(Menu&);//Function to be called when this menu is 'used'

 Menu(const prog_char *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
 Menu(const prog_char *n, boolean (*c)(Menu&));//Constructs the Menu with a specified use function

Menu.cpp (partial)

  Menu::Menu(const prog_char *n)
  {
    name = (const __FlashStringHelper*) n;  
    canEnter=NULL;
  }
  
  Menu::Menu([b]const [/b]prog_char *n,boolean (*c)(Menu&))
  {
    name = (const __FlashStringHelper*) n;  
    canEnter=c;
  }

The reason for declaring 'name' with type const __FlashStringHelper* is so that you can pass it directly to lcd.print().

Actually, I think you've got it right backwards.

He wants to do this:

  Menu top(F("Root"));

That means Menu() needs to take a __FlashStringHelper*. Then it should immediately cast it to a prog_char* like Print::print() does and save it internally.

  Menu::Menu(__FlashStringHelper *n)
  {
    name = (const prog_char*) n;
  }

Then, Menu::name is declared thusly

private:
 const prog_char * name;//Name of this Menu

Incidentally, prog_char is really extraneous anyway, const char* would do just as well.

He's said he doesn't want to use string literals surrounded by the F() macro in his declarations, he wants to use named PROGMEM char arrays instead. So he needs the constructors to take const prog_char . I already explained my reason for declaring 'name' as a flash string, so that he can print it easily - although of course he could instead declare it as a const prog_char and cast it to const __FlashStringHelper* at the time of printing.

Thanks for the replies, I’m getting closer.

Alternatively, if you will be naming all your menu strings and never passing F() string literals to the Menu constructor, try this:

Yes that’s what I’m doing now. I made the mods and it compiles right up to the goEnter() routine in LCDMENU.cpp where curfuncname trips an error. Code follows:

  void LCDMenu2::goEnter()
  {
      Menu *tmp;
      tmp=curMenu;
      if ((tmp=tmp->getChild(curloc)))
      {  //The child exists
          if (tmp->canEnter)
          {  //canEnter function is set
              if (tmp->canEnter(*tmp))
              {  //It wants us to enter
                  goMenu(*tmp);
              }
          }
          else {
                // canEnter function not set, assume entry allowed
                goMenu(*tmp);
                curfuncname = tmp->name; // < -- here the error is 'cannot convert const ___flashstringhelper to char * in assignment'
               }
      }
      else { // child did not exist  The only time this should happen is on the back Menu item, so go back
             goBack();
           }
  }

So what happens if you change the type in the declaration of curfuncname from char* to const __FlashStringHelper* in class LCDmenu2 as well?

So what happens if you change the type in the declaration of curfuncname from char* to const __FlashStringHelper* in class LCDmenu2 as well?

error: comparison between distinct pointer types 'const __FlashStringHelper*' and 'const prog_char*' lacks a cast

at a line outside the menu:

if (Root.curfuncname == MENUCONST_MENU1) // this const is in PROGMEM

definition of the const:

const prog_char MENUCONST_MENU1[] PROGMEM = "MENU1";

I also refer to curfuncname array elements so I can extract numbers, eg:

if (Root.curfuncname[0] == 'G') // process GMT offset

edit: improved description

I was able to get it going, although I wonder about its efficiency. Thanks to all who responded. Here’s the code:

Menu.h

/*
Menu.h - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want

*/
#ifndef Menu_h
#define Menu_h

//This is for arduino 0022,23 - 1.0 compatibility.
#if defined(ARDUINO) && ARDUINO >= 100
    #include <Arduino.h>
  #else
    #include <WProgram.h>
#endif

class Menu
{
private:
 Menu * parent;//Parent Menu, NULL if this is the top
 Menu * child;//First Child Menu, NULL if no children
 Menu * sibling;//Next Sibling Menu, NULL if this is the last sibling

 void setParent(Menu &p);//Sets the Menu's Parent to p
 void addSibling(Menu &s,Menu &p);//Adds a Sibling s with Parent p.  If the Menu already has a sibling, ask that sibling to add it
 
 public:
 char * name;//Name of this Menu
 Menu(const prog_char *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
 Menu(const prog_char *n, boolean (*c)(Menu&));//Constructs the Menu with a specified use function
 boolean (*canEnter)(Menu&);//Function to be called when this menu is 'used'
 void addChild(Menu &c);//Adds the child c to the Menu.  If the menu already has a child, ask the child to add it as a sibling
 boolean ChildExists();//Returns state of a child menu in current item
 Menu * getChild(int which);//Returns a pointer to the which'th child of this Menu
 Menu * getSibling(int howfar);//Returns a pointer to the sibling howfar siblings away from this Menu
 Menu * getParent();//Returns this Menu's parent Menu.  If no parent, returns itself
};

#endif //Menu_h

Menu.cpp

/*
Menu.cpp - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want

*/

#include "Menu.h"
#include <WString.h> // uses enhanced wstring that supports progmem 01.23.12

  void Menu::setParent(Menu &p)
  {
    parent=&p;
  }
  
  void Menu::addSibling(Menu &s,Menu &p)
  {
    if (sibling)
    {
     sibling->addSibling(s,p);
    } else {
             sibling=&s;
             sibling->setParent(p);
           }
  }

  Menu::Menu(const prog_char *n)
  {    
    name = (char *)realloc(name, strlen_P(n)+1);
    strcpy_P(name, n);
    canEnter=NULL;
  }
  
  Menu::Menu(const prog_char *n, boolean (*c)(Menu&))
  {
    name = (char *)realloc(name, strlen_P(n)+1);
    strcpy_P(name, n);    
    canEnter=c;
  }

  void Menu::addChild(Menu &c)
  {
    if (child)
    {
     child->addSibling(c,*this);
    } else {
             child=&c;
             child->setParent(*this);
           }
  }
  
  boolean Menu::ChildExists()
  {
    if (child)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
  
  Menu * Menu::getChild(int which)
  {
    if (child)
    {
     return child->getSibling(which);
    } else  {
              // this Menu item has no children
             return NULL;
            }
  }
  
  Menu * Menu::getSibling(int howfar)
  {
    if (howfar==0)
    {
     return this;
    } else if (sibling)
         {
           return sibling->getSibling(howfar-1);
         } else //Asking for a nonexistent sibling
             {
             return NULL;
             }
  }
  
  Menu * Menu::getParent()
  {
    if (parent)
    {
     return parent;
    } else // top Menu
     {
     return this;
     }
  }

LCDMenu2.h + LCDMenu2.cpp stay the same.

Here are helper functions for dealing with menu items:

boolean CompareStringToPROGMEMstring(char * str, const prog_char * pgm)
{
char * a;

  // allocate the buffer to the same size as the progmem string
  a = (char *)realloc(a, strlen_P(pgm)+1);
  // copy from progmem
  strcpy_P(a, pgm);
  // compare the string against the copied progmem string
  if (strcmp(str,a)==0)
    return true;
  else
    return false;  
}

uint8_t GetPROGMEMbyte(const prog_char * pgm, uint8_t pos)
{
char * a;

  // allocate the buffer to the same size as the progmem string
  a = (char *)realloc(a, strlen_P(pgm)+1);
  // copy from progmem
  strcpy_P(a, pgm);
  // return the byte at position  
  return a[pos];
}

j514: if (Root.curfuncname == MENUCONST_MENU1) // this const is in PROGMEM

Change to:

if (Root.curfuncname == (const __FlashStringHelper*)MENUCONST_MENU1) // this const is in PROGMEM

j514: I also refer to curfuncname array elements so I can extract numbers, eg:

if (Root.curfuncname[0] == 'G') // process GMT offset

Add the following to the public declarations in class LcdMenu2:

char getChar(size_t n) const { return pgm_read_byte(((const prog_char*)curfuncname) + n); }

the you can use:

if (Root.getChar(0) == 'G') // process GMT offset

j514:
I was able to get it going, although I wonder about its efficiency. Thanks to all who responded. Here’s the code:

Yes, that’s worse than not using progmem at all, because you’re copying all the strings into RAM and you also have the overheads of dynamic memory allocation.

if (Root.curfuncname == (const __FlashStringHelper*)MENUCONST_MENU1) // this const is in PROGMEM

const definition:

const prog_char MENUCONST_MENU1[] PROGMEM = "MENU1";

error: comparison between distinct pointer types 'char*' and 'const __FlashStringHelper*' lacks a cast

You've obviously changed the type of curfuncname back to char*. Why?