Register / Login  |  Desktop view  |  Jump to bottom of page

tcMenu Arduinio library » Is there a way to change menu through code?

Author: nvpsble
14/11/2021 16:07:36
Hi guys, first time here.
Didn't see similar posts about this, so I'm creating a new one.

I've come across to this great library which satisfies most of my project needs. tcMenu framework is very flexible and versatile.

I'm using ESP32. In my project there is a need for changing menus through code. Say I have some submenus under root menu, and now I want to switch between them through an encoder.
My idea is that the UI is always within one of the submenus. When I rotate the encoder I jump to another submenu, and the root menu is not visible to the user.

Then I looked up API docs. I'm developing using VSCode and I found several method names that look like what I'm searching for.
I tried `menuMgr.changeMenu()` and `menuMgr.activateMenuItem()`. They didn't work as I expected.
Then I tried `menuMgr.navigateToMenu(menuXXX.getChild())`. It worked but reseted the encoder value, so I wouldn't be able to scroll backward (the value is limited to 0). I provided a custom callback function and see that the value changes to 0 when `navigateToMenu` is called.
Then I tried setting the encoder's intention to `DIRECTION_ONLY`, but strangely, it didn't work like that either. (No `-1` is passed to the callback, only `0` and `1` because there's only 1 item in each submenu for testing)

My code to set up encoder:

void setupEncoder() {
  if (switches.getIoAbstraction() == nullptr)
    switches.initialise(internalDigitalIo(), true);

  switches.addSwitch(ENCODER_BUTTON, nullptr);
  switches.onRelease(ENCODER_BUTTON, encoderPressCallback);

  encoder = new HardwareRotaryEncoder(ENCODER_PIN_A, ENCODER_PIN_B,
                                      encoderRotateCallback, HWACCEL_REGULAR,
                                      FULL_CYCLE);
  encoder->setUserIntention(DIRECTION_ONLY);
  switches.setEncoder(encoder);
}


encoderPressCallback():

void encoderPressCallback(pinid_t id, bool held) {
  Serial.printf("PinID %u, Held %u\n", id, held);
  menuMgr.onMenuSelect(false);
}


encoderRotateCallback():

void encoderRotateCallback(int value) {
  // for debug purpose
  auto ptx = menuMgr.getCurrentMenu();
  auto ptr = menuMgr.getCurrentSubMenu();
  Serial.printf("[%lu] Val %d, CM %p, CSM %p\n", millis(), value, ptx, ptr);
  // messy code omitted. I store value and change menu in main loop, because directly calling `navigateToMenu` here causes stack overflow
}


I'm not sure if I have provided enough information. I'm not a native speaker so there may be some grammar issues. Any help is truly appreciated.

Many thanks!

Author: davetcc
14/11/2021 20:38:05
To be honest, what you're trying to do is slightly outside of the standard configurations. I assume there is only one rotary encoder, and you're using it for both menu operations and the custom movement between menus.

I'm not 100% how that would work because when the menu is in view, it will try to reset the encoder range to be able to navigate that series of menu items. Whereas as I understand it you want it to continue to select the various menus.

To be honest, as things stand now, and without writing some extensions yourself, I can't think of an easy robust way to do that. The only think I could think of is a menu select button or similar that allowed you to keep separate control and differentiate between "menu selection" and "menu control".

Depending on your C++ skill level, you could make an extension of the rotary encoder class that handled your case. See SwitchInput.h/cpp in IoAbstraction for that. https://www.thecoderscorner.com/ref-docs/ioabstraction/html/class_rotary_encoder.html

You would then switch the input plugin in code generator to the "no input" plugin and provide your custom class. https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menumanager-and-iteration/




Register / Login  |  Desktop view  |  Jump to top of page