Very easy menuing system library [REWRITEN WITHOUT String] see last page

Hi all,

I have looked for a menuing system where it would be easy to describe a menu to Arduino and found none that would suit me. So I decided to write one.

All that you need to do is to create a string with your menu items like this:

const String menuItems = 
"-READ:000"
"--SENSORS:000"
"---SENSOR A1:101"
"---SENSOR A2:102"
"--SWITCHES:000"
"---SWITCH PIN 4:103"
"---SWITCH PIN 5:104"
"-SET:000"
"--SERVO ARM:105"
"--SERVO BASE:106"
"-MOVE SERVOS:107";


Menu menu(menuItems);

On each line you have dashes that specify at what level the item is, i'ts label, and an integer that specifies what action is to be taken if this item is selected. Those integers can be used in a switch case construct.

The library can also take care of displaying the menu on a LCD and of reading the switches to navigate the menu.

You can find the library and a tutorial here.

p.s. Il y a aussi un tutoriel en francais.

re: github tutorial

I reloaded the tutorial.pdf page several times but it always comes up with torn text, making it unreadable. I've never seen that before.

arduino forum 8.PNG

arduino forum 8.PNG

Hi countryman.
I see you are busy again.

Lots of us stay away from Strings, actually I have never used them.
I like your Tutorial formatting.

Hope the bouncing is better.

Congrats on Full Membership, no more 5 minute timeouts :wink: .

.

Hi Doug,

I just downloaded the tutorial from github and it displays ok on my pc.

Can you read it in github?

Get back to me. The people at github are very helpfull. If you could tell me more about your setup, (OS, Reader version, etc) it will be easier for me to explain to them what is hapening.

Hi Larry,

I placed the Menu Library there 9 months ago. It is alive again because I added the French tutoriel.

I built this Library so that non-programmers could easily describe a menu and use it. With that in mind, I decided that using Strings was the way to go. I like to live on the edge.

The String is declared as const, the parser reads it character by character on instantiation, the menu is displayed item label by item label, there is no concanetation anywhere... I am not worried about fragmentation.

EDIT: Just realised that my code could be viewed as not stable. Not good.

Maybe you could rewrite it with char[]. My parser, your knowledge of C++, an easy menuing system that would be both easy and stable...

That would be great.

jbellavance:
Get back to me. The people at github are very helpfull. If you could tell me more about your setup, (OS, Reader version, etc) it will be easier for me to explain to them what is happening.

OS, Win7 Pro
Opens in IE11.0.9600.18738

There is no option available in IE to open with a .pdf reader

Tried the French version and it's the same.

Typing the letters 'IE' jogged my memory. There are problems occasionally with this. I went to this very thread in Chrome; to github link; to tutorial and everything's fine.

It's a Microsoft thing. Sigh.

Glad to hear that Chrome can read it.

Have a nice day.

Jacques

Hi,

I just read this:

Whilst is it possible to fragment and run out of memory with only 2 Kb to spare, code that allocates (and then frees) the same sizes strings all the time will not suffer from it.

In particular, if you avoid doing string concatentation which is probably the worst offender in causing fragmentation. (That is, building up a string by adding one character to it all the time). In any case, this sort of string-building is necessarily slow.

It was posted in 2012 by Nick Gammon.

I believe I can manage to modify the code so that it only uses 2 fixed sized strings.

Am I playing with fire, or would that spec save the day?

Will this line of code generate an intermediate String that I should worry about?

int action = MYstring.substring(pos+1, pos+4).toInt()

With String I still don't like the fact that the constant strings have to live in RAM. With regular c style strings you could PROGMEM them and save RAM for the application.

Hi Delta_G,

Yeah. After all I read about Strings, I decided to rewrite the whole thing with C style strings.

I am just about done. Just have to rewrite the tutorials (English and French). Probably tomorow. The library works just like before, but I removed some bells and whistles to make it leaner.

I'll stay away from the Strings class from now on. (At least in my Libraries :slight_smile: )

Jacques

Will you be using the F() macro to store text?

.

Hi Larry,

I only saw the F() macro with Serial.print().

Have you (or anyone) seen it used somewhere else?

Jacques

Lcd.print(F(“Hi Jacques”));

Obviously you cannot dynamically change the data, but for a menu that's not an issue.

Another option:
http://playground.arduino.cc/Main/PROGMEM

.

Yes,

I will look at the PROGMEM solution.

In order to make this menu so simple to describe, I place it all inside a (now) C style string (ending with NULL).

But I do change the data, transforming it into multiple C style strings, placing a NULL character after each of the item's label.

I do an other transform to it, to be able to place a carret in front of the active menu item. And that is changed every time a button is pressed.

EDIT: Went to Arduino's PROGMEM page. PROGMEM variables can only be read? Anyone can confirm or infirm?

Jacques

Yes, progmem data is read only. But that shouldn't be a problem. You don't have to append the caret onto the string. You print the caret and then print the string as two separate entities.

But I really need to split the menu into it's components (item labels) in order to display them. That means adding NULLs after each label, after the menu is set in the sketch.

I think that the menu will have to stay in RAM.

jbellavance:
But I really need to split the menu into it's components (item labels) in order to display them. That means adding NULLs after each label, after the menu is set in the sketch.

I think that the menu will have to stay in RAM.

You just need to reorganize how you store them. What, have you got them all in there as one long string or something? I don't understand where the issue is here. You should store each entry as its own string.

Here's an example of a menu system that I use. GitHub - delta-G/REBL_UI: Simple menu UI for Arduino with 16x2 LCD, rotary encoder, and a single button. It's a little dirty because it is implemented as a virtual class to handle the menu stuff and then a concrete implementation class that handles the actual input/output. But you can see in there how I handle the strings in progmem.

My goal is to create a menu system that is easy to describe and to use.

I looked at a lot of menus on the net, and the most frequent way to describe a multi-level menu looks like this:

-Fruit
--Apple
--Orange
-Vegetable
--Lettuce
--Cucumber
--Pepper
---Green
---Red

So the code to describe a menu in my Labrairy goes like this:

char menuItems[] =
"-READ:000"
"--SENSORS:000"
"---SENSOR A0:100"
"---SENSOR A1:101"
"--SWITCHES:000"
"---SWITCH PIN 4:200"
"---SWITCH PIN 5:201"
"-SET:000"
"--SERVO ARM:300"
"--SERVO BASE:301"
"-MOVE SERVOS:400";

So, yes, the whole menu is in one single string.

Each int after the item label corresponds to a "switch case" construct to implement the code to accomplish the task (action) specified by the menu item.

The user moves in the menu by supplying one of four values (UP, DOWN, LEFT or RIGHT) to the Library, which will return the required action tagged to the new menu item:

int action = menu.getAction(key);
if (action > 0) {
   make(action);  //Where make() is a "switch case" construct
}

The user handles its own display. It can display the menu with this simple code:

void displayMenu() {
  lcd.clear();
  for (int i = 0 ; i < lcdLines ; i++) {
    lcd.setCursor(0, i);
    lcd.print(menu.getLine(i));
  }
  menuNeedsUpdate = false;

I think that this Library succeds in both goals: easy to describe and easy to use.

You Library is very complete, handling both display, switches and encoders. Plus it uses PROGMEM.

The example sketch shows how easy it is to use single level menus. Since you can handle multiple menus, I suppose that it would be feasable to use it as a multilevel menuing system. If memory size becomes an issue, PROGMEM is the best solution.

However, I will stick to leave it in RAM. The above menu takes up 152 bytes. (7% of a Nano's RAM)

Jacques

Removed the Strings Class. Using c++ strings now. You can find it here

OK, I see what you're doing with the dashes to indicate the level. I would go for a more compact design and put that just as a number, why waste three or four bytes over a few bits worth of information.

But even there, you don't need to be able to modify the string to print it. These are char arrays after all, and arrays you can index.

char* longText = "DON'T print me : Print ME alone"

Serial.print(longText + 17);   // prints "Print ME alone"

As I said, I looked at a lot of menus on the net. The dashes (or spaces) indents the menu in a natural way and this scheme is found on many sites. Programmers are no the only earthlings to understand indents. The goal is not to be memory concious. It is to be "natural" to a non programmer to express a menu that pops in mind.

Printing the last part of a string is kind of easy, since the NULL character is already there.

"-Item1:101"
"-Item2:102"
"-Item3:103"
"-Item4:104"

is really, adding % as the NULL character:

"-Item1:101-Item2:102-Item3:103-Item4:104%"

After processing, Item1 being the current item,

">Item1%01 Item2%02 Item3%03 Item4%04%"
200      209      218      227

Now I only need the pointers {200,209,218,227} to the start of the items to display them.
The NULL characters tells where to stop for all items in the menu.