OpenMoCo Menu Manager - completely automated menus for Arduino

Hi Oliver, thanks for the list - I hadn't seen m2tklib before, but it looks like we took a very similar approach in most regards. The online Doxygen documentation was linked in the first post, here it is again: Dynamic Perception

Thanks!

Chris

Hi

Ah, thanks for the link. I did not saw the initial link.

And yes, OpenMoCo Menu Manager and M2tklib do have a very similar approach.
I like the clean C++ approach and the description of the display handler.

Good work!

Oliver

Hi

I tried to use u8glib (Google Code Archive - Long-term storage for Google Code Project Hosting.) with OpenMoCo.

Problem 1: After download and archive extraction into the libraries folder, the Arduino IDE complains about the root directory name. I had to rename it to something without "-" and ".". I also noticed that there is exactly only one example for the complete lib. Luckily it covers the menu manager, but i would have expected some more examples within the Arduino IDE for other parts of the lib.

Problem 2: I do not know how to setup the u8glib picture loop. More specific: I need to draw the screen more than once. The draw callback handler for u8glib is easy. Assuming a font with char width 4 and height 8 it is this:

void uiDraw(char* p_text, int p_row, int p_col, int len) {
  u8g.setCursorPos(p_col*4, p_row*8);  
  for( int i = 0; i < len; i++ ) {
    if( c < '!' || c > '~' )
      u8g.write(' ');
    else  
      u8g.write(p_text[i]);
  }
}

However, the screen has to be updated several times. But i do not know how to do this. Controll is given to this lib with checkInput(), but i assume that this procedure also does the character output. Pseudocode for u8glib is this:

  1. check keys
  2. handle keys
  3. several times: redraw screen
    I looked into the code, but did not find how to do 3)

Any ideas?

Oliver

olikraus:
Problem 1: After download and archive extraction into the libraries folder, the Arduino IDE complains about the root directory name. I had to rename it to something without "-" and ".". I also noticed that there is exactly only one example for the complete lib. Luckily it covers the menu manager, but i would have expected some more examples within the Arduino IDE for other parts of the lib.

Hi Oliver,

What dashes and dots? There are no dashes or dots in any directory names for any OM libraries? The OM Menu Manager root directory name is 'OMMenuMgr'. The example exercises 100% of the OMMenuMgr functions.

If it's other libraries you're looking for information and examples on, read the doxygen docs which are in docs/html -- there are pages on the more complex libraries, which give many examples of their use, and all other libraries are fully documented with basic examples.

olikraus:
Problem 2: I do not know how to setup the u8glib picture loop. More specific: I need to draw the screen more than once. The draw callback handler for u8glib is easy. Assuming a font with char width 4 and height 8 it is this:

void uiDraw(char* p_text, int p_row, int p_col, int len) {

u8g.setCursorPos(p_col4, p_row8); 
  for( int i = 0; i < len; i++ ) {
    if( c < '!' || c > '~' )
      u8g.write(' ');
    else 
      u8g.write(p_text[i]);
  }
}




However, the screen has to be updated several times. But i do not know how to do this. Controll is given to this lib with checkInput(), but i assume that this procedure also does the character output. Pseudocode for u8glib is this:
1. check keys
2. handle keys
3. several times: redraw screen
I looked into the code, but did not find how to do 3)

Any ideas?

Oliver

I don't see from the u8g docs that it needs to be drawn constantly, but instead only to be drawn when it changes. However, if you want to re-draw constantly, then just store the draw data in global scope, and access that as it updates...

something like this:

struct {

  char text[OM_MENU_ROWS];
  int row;
  int col;
  int len;
} screenDat;

boolean screenSet = false;

...

void setup() {

  ...

  Menu.setDrawHandler(uiDraw);
  Menu.setExitHandler(uiExit);
}

void loop() {

  Menu.checkInput();

  if( screenSet )
     u8draw();

}

void uiDraw(char* p_text, int p_row, int p_col, int len) {

    // clear out buffer
  memset(screenDat.text, ' ', OM_MENU_ROWS);
  memcpy(&screenDat.text, p_text, len);

  screenDat.row = p_row;
  screenDat.col = p_col;
  screenDat.len = len;
 
  screenSet = true;

}

void uiExit() {

  screenSet = false;
}

Because of the lib name: Maybe i made a mistake here.

Regarding u8glib, i think i got your point: Implement an intermediate buffer and draw that buffer as often as required.
ok, this could be done.

Thanks,
Oliver

New update released, includes the following:

  • Ability to have Bit flag input types, showing "On" and "Off" (allow users to toggle a single bit out of a byte)
  • Automatic storage of values to EEPROM (Using OMEEPROM library included)
  • Accelerating input changes when button is held (scroll through values faster the longer buttons are held)
  • Query the library to determine if button is held, or simply pressed when using it to manage input outside of a menu
  • Navigation bug fixes
  • Greater flash size efficiency through coding optimizations

It can be downloaded here: Dynamic Perception
Updated documentation here: Dynamic Perception

!c

Hi drone

Is there a way to use my own function for the input? I have a function for my 4 analog buttons, the incremental encoder and the encoder push button. With your libary I can only use the 4 analog button and not a combination of the two... Is it possible to call the menu functions directly? I have debounced my analog buttons already.

greets mike

Hi Mike,

Sorry for the delay!

The issue is not really debouncing, but the checkInput() method does a lot more than that - you'll note that it handles escalating values the longer an input is held, dealing with returning back to menus from screens, etc. To handle a sixth input will be a bit more complex, because you probably want that input to behave like two of the other inputs. (e.g. emulate INCREASE or DECREASE based on direction of turn.) The best way to do this will be to modify the OMMenuMgr library file and make _checkAnalog() a protected virtual, and then sub-class the OMMenuMgr library, providing your new _checkAnalog() function to properly return the button type. This way, you can make your own _checkAnalog() method that returns one of BUTTON_NONE, BUTTON_FORWARD, BUTTON_BACK, BUTTON_INCREASE, BUTTON_DECREASE, BUTTON_SELECT based on how your inputs are read.

You may also want to make setAnalogButtonPins() virtual as well, so you can pass the correct information in without hard-coding it. If you're still interested in doing this, I can make these virtual changes to the core library so that you won't have to worry about upgrades later. BTW, the new home for this library is: GitHub - DynamicPerception/OMLibraries: OpenMoCo Libraries for AVR

!c

Hey there,

the lib looks promising. I stumbled upon this when i was wading through the code for chronos, not liking it a bit. But what i liked about the chronos approach was the input of data through potentiometers. it is fast and with a small piezo as audio feedback even tactile. but how to incorporate this into the openmoco menu manager?

Thinking aloud here it could even be possible to use just one analog pin for the hole setup, attaching the pot to vcc and gnd via two resistors, so two extra buttons can short the analog pin to vcc or gnd as button values.

But i'm just a moderate c programmer, still not able to handle the abstract thoughtsbehind c++, so don't expect any code from me. :frowning:

hi
i am getting error when try t compiling this example OMMenuMgr.ino.

'BUTTON_SELECT' was not declared in this scope.

any help?

shkdxb:
hi
i am getting error when try t compiling this example OMMenuMgr.ino.

'BUTTON_SELECT' was not declared in this scope.

any help?

Sounds like you did not properly install the library, or include it in your sketch? BUTTON_SELECT is an enum defined in OMMenuMgr.h

Thanks drone, i could able to solve the issue. For a strange reason, the libraries are not recognized under default library/ folder. While compiling, the error showed up for library location as my documents directory. i have copied your files to my document/ aruduino/library folder and problem solved.

But now i have one more issue. As per your documents, you have EEPROM support, but the example provided in your Github page doesn't have this line in line no 78.

MENU_VALUE foo_value = { TYPE_BYTE, 100, 0, MENU_TARGET(&foo), EEPROM_FOO };

Also i could not find the setup parameter OM_MENU_USE_EEPROM.

how can I implement EEPROM writing and reading?

I'm having a similar problem when compiling. I've installed directly into the program files\arduino\libraries folder so that each individual folder is its own library.

C:\Program Files\Arduino\libraries\OMMenuMgr/OMMenuMgr.h: In member function 'void OMMenuMgr::_eewrite(OMMenuValue*, T)':
C:\Program Files\Arduino\libraries\OMMenuMgr/OMMenuMgr.h:989: error: 'OMEEPROM' has not been declared

Hi all,
I have rum the sketch, but I am geeing lot of error as below. I thing problem with the Input Button definition, Please help me.
Regards,
Harikesh

example.ino:8:23: error: OMMenuMgr.h: No such file or directory
example:44: error: 'BUTTON_FORWARD' was not declared in this scope
example:45: error: 'BUTTON_INCREASE' was not declared in this scope
example:46: error: 'BUTTON_DECREASE' was not declared in this scope
example:47: error: 'BUTTON_BACK' was not declared in this scope
example:48: error: 'BUTTON_SELECT' was not declared in this scope
example:62: error: 'MENU_SELECT_ITEM' does not name a type
example:63: error: 'MENU_SELECT_ITEM' does not name a type
example:64: error: 'MENU_SELECT_ITEM' does not name a type
example:66: error: 'MENU_SELECT_LIST' does not name a type
example:71: error: 'MENU_SELECT' does not name a type
example:76: error: 'MENU_VALUE' does not name a type
example:77: error: 'MENU_VALUE' does not name a type
example:78: error: 'MENU_VALUE' does not name a type
example:79: error: 'MENU_VALUE' does not name a type
example:80: error: 'MENU_VALUE' does not name a type
example:83: error: 'MENU_ITEM' does not name a type
example:84: error: 'MENU_ITEM' does not name a type
example:85: error: 'MENU_ITEM' does not name a type
example:86: error: 'MENU_ITEM' does not name a type
example:87: error: 'MENU_ITEM' does not name a type
example:88: error: 'MENU_ITEM' does not name a type
example:91: error: 'MENU_LIST' does not name a type
example:94: error: 'MENU_ITEM' does not name a type
example:100: error: 'OMMenuMgr' does not name a type
example.ino: In function 'void setup()':
example:110: error: 'Menu' was not declared in this scope
example.ino: In function 'void loop()':
example:119: error: 'Menu' was not declared in this scope
example.ino: In function 'void uiQwkScreen()':
example:151: error: 'Menu' was not declared in this scope
example:157: error: 'BUTTON_SELECT' was not declared in this scope

Hi,
.h and .cpp files needs to move to upper folder. Same way om eprome also need to move in same folder where .h and .cpp are moved.
Regards,
Harikesh

Hallo,
I am trying to create Menu using this library from couple of weeks. I have tryed a lot to create Sub Menu. If any one know it, please repply me, it's not given in the example also. Please please help me out.
Harikesh Patil

Hi.

harikeshpatil:
I have tryed a lot to create Sub Menu...

You can generate the submenu by using MENU_LIST and MENU_ITEM similarly as the root menu is done. If you take the example included with the library and add these lines just above the line that begins with "MENU_LIST root_list..."

                   //  List of items in the submenu level
MENU_LIST submenu_list[] = { &item_bazme, &item_bakme };
                  // Submenu item
MENU_ITEM menu_submenu = { {"Submenu>>"},  ITEM_MENU,  MENU_SIZE(submenu_list),  MENU_TARGET(&submenu_list) };

Now add "&menu_submenu" to the root list below and remove "&item_bazme, &item_bakme " from the same list. You should now have a submenu with these two items.

Thank you for your support. It's working fine.
Harikesh Patil

Hello! First of all - thanks to developers for nice lib for menu! I found it very handy and simple to use. But I have one major trouble - with newer gcc (I think from 4.6 or 4.7) all PROGMEM identifers must also be const. I try to solve issues with const-ing by static_cast(const_cast(...) all works on OLDER compiler.. but I cannot find right cast for const MENU_LIST const root_list[] = {...}. without second const, that make pointer to arry elements const and PROGMEM-able it all can be compiled on older compiler, and it also WORKS! But as soon as I const root_list[] there is compiling errors about wrong cast from ‘const OMMenuItem* const ()[3]’ to type ‘void’. And without const-ing it cannot compile on ewer gcc :frowning:

HELP! PLEASE! :slight_smile:

I knew about __flash, but I prefere old-gcc compat solution and my knowelage isn't sufficient to port this lib to __flash.

Here is what I came so far
--therm_menu_const.SNIP---
float set_temp = 26.07;
float temp_delta = 0.5;

boolean missed = false;

// values to use

// TYPE MAX MIN TARGET
const MENU_VALUE set_temp_value = { TYPE_FLOAT_100, 125, -50 , MENU_TARGETO(&set_temp) };
const MENU_VALUE temp_delta_value = { TYPE_FLOAT_100, 2, 0.2 , MENU_TARGETO(&temp_delta) };

// LABEL TYPE LENGTH TARGET
const MENU_ITEM item_set_tempme = { {"Set Temperature"}, ITEM_VALUE, 0, MENU_TARGET(const_cast(&set_temp_value)) };
const MENU_ITEM item_temp_deltame = { {"Set Delta"}, ITEM_VALUE, 0, MENU_TARGET(const_cast(&temp_delta_value)) };
const MENU_ITEM item_testme = { {"Exit"}, ITEM_ACTION, 0, MENU_TARGETO(uiQwkScreen) };

// List of items in menu level
const MENU_LIST const root_list[] = { const_cast(&item_set_tempme), const_cast(&item_temp_deltame), const_cast(&item_testme) };

// Root item is always created last, so we can add all other items to it
const MENU_ITEM menu_root = { {"Root"}, ITEM_MENU, MENU_SIZE(root_list), MENU_TARGET(&root_list) };

OMMenuMgr Menu(const_cast(&menu_root));
--therm_menu_const.SNIP---

I add another macro

#define MENU_TARGETO(x) reinterpret_cast(x)
#define MENU_TARGET(x) static_cast(x)

Problem 2: I do not know how to setup the u8glib picture loop. More specific: I need to draw the screen more than once. The draw callback handler for u8glib is easy. Assuming a font with char width 4 and height 8 it is this:

void uiDraw(char* p_text, int p_row, int p_col, int len) {

u8g.setCursorPos(p_col4, p_row8); 
  for( int i = 0; i < len; i++ ) {
    if( c < '!' || c > '~' )
      u8g.write(' ');
    else 
      u8g.write(p_text[i]);
  }
}




However, the screen has to be updated several times. But i do not know how to do this. Controll is given to this lib with checkInput(), but i assume that this procedure also does the character output. Pseudocode for u8glib is this:
1. check keys
2. handle keys
3. several times: redraw screen
I looked into the code, but did not find how to do 3)

Any ideas?

Oliver

I don't see from the u8g docs that it needs to be drawn constantly, but instead only to be drawn when it changes. However, if you want to re-draw constantly, then just store the draw data in global scope, and access that as it updates... 

something like this:



struct {

char text[OM_MENU_ROWS];
  int row;
  int col;
  int len;
} screenDat;

boolean screenSet = false;

...

void setup() {

...

Menu.setDrawHandler(uiDraw);
  Menu.setExitHandler(uiExit);
}

void loop() {

Menu.checkInput();

if( screenSet )
     u8draw();

}

void uiDraw(char* p_text, int p_row, int p_col, int len) {

// clear out buffer
  memset(screenDat.text, ' ', OM_MENU_ROWS);
  memcpy(&screenDat.text, p_text, len);

screenDat.row = p_row;
  screenDat.col = p_col;
  screenDat.len = len;

screenSet = true;

}

void uiExit() {

screenSet = false;
}

I believe that OMMenuMgr is one of the simplest Menu Routines available right now but there is no ug8lib support or i cant realize how to do it.
Could u post your code?