arduino-menusystem icon indicating copy to clipboard operation
arduino-menusystem copied to clipboard

Serialize menu system state

Open jonblack opened this issue 9 years ago • 6 comments

Support serializing the menu system state to binary so that users can write it to persistent storage such as an SD card. It should also be possible to reload the menu system state from the serialized data.

Note that this library will not be responsible for writing and reading the state from storage.

This issue was created in response to comments in #21.

jonblack avatar Apr 13 '16 07:04 jonblack

Interesting, but this introduces some intriguing challenges. At least if you want to be able to serialize the entire menu into a byte array and being able restore the entire menu solely from that array.

  • how to tell the menu item classes apart. I don't know how well arduino c++ supports reflection. Maybe each class can have a getType() method.
  • How to deal with custom callbacks.

Or maybe I'm making this overly complicated. It could be enough to store the state (just name and value if applicable) of each menuitem into a hashmap. That hashmap could easily be stored in a byte array. When constructing the menu at bootup the constructor could query the hashmap for values and use the default values if nothing was found.

eadf avatar Apr 18 '16 09:04 eadf

This is about storing just the state. It won't create the MenuComponent's. First the menu system is built by adding MenuComponent's (like we currently do), then the state can be loaded. This just sets which Menu's are selected and, in the case of NumericMenuItem, the value it has. Here's some pseudo-code:

MenuSystem ms;
Menu mm("");
MenuItem mm_mi1("Level 1 - Item 1 (Item)");
MenuItem mm_mi2("Level 1 - Item 2 (Item)");
Menu mu1("Level 1 - Item 3 (Menu)");
MenuItem mu1_mi1("Level 2 - Item 1 (Item)");
MenuItem mu1_mi2("Level 2 - Item 2 (Item)");

void setup()
{
  Serial.begin(9600);

  // Menu setup
  mm.add_item(&mm_mi1, NULL);
  mm.add_item(&mm_mi2, NULL);
  mm.add_menu(&mu1);
  mu1.add_item(&mu1_mi1, NULL);
  mu1.add_item(&mu1_mi2, NULL);
  ms.set_root_menu(&mm);

  // Load the menu state
  state = sd_card.load();

  // Set the menu system state
  ms.load_state(state);
}

jonblack avatar Apr 18 '16 09:04 jonblack

I want to store the setpoints only so that any changes made by the operator are not lost when powered down. I imagined an array for each numeric menu, same name and order as menu items. 'Settings' menu item 0 > select >> operates on Settings[0].

Load arrays on startup and save on exit of numeric menu to capture changes. General access to setpoints from the code references the array.

recyclix avatar Apr 18 '16 10:04 recyclix

@jonblack are you sure that you don't want to store the name of the MenuItem in the state as well?

Before I made NumericMenuItem I used the name of a basic MenuItem to contain a boolean state. E.g. when the name of a specific MenuItem was set to "turn off led" the led was on. And when the select callback was called, it changed the item name to "turn on led" and turned off the led (and vice versa). Is this use case not valid? The select callback gets a pointer to a non-const MenuItem after all (that has aset_name()method).

For a MenuItem that represents boolean states, or any other 'one-way-cyclic' state, the set_name() trick is even easier to use than the NumericMenuItem

eadf avatar Apr 18 '16 11:04 eadf

We can also store the name although I don't think it's necessary since the menu has to be specified manually anyway, which includes the name.

Perhaps a better idea is to introduce a BooleanMenuItem for that specific use case?

jonblack avatar Apr 18 '16 11:04 jonblack

since the menu has to be specified manually anyway, which includes the name.

Which refers to an array; menuname[menuitem_position] when selected or displayed. And the user code can refer to array; menuname[some_position] for the setpoint value.

recyclix avatar Apr 18 '16 14:04 recyclix