REWORK: new menu structure and hierarchy

This commit is contained in:
Robin Dietzel 2023-01-26 12:25:09 +01:00
parent b3b2f9ba48
commit 5b3bc7591d
5 changed files with 323 additions and 94 deletions

View File

@ -7,6 +7,6 @@
// Auto generated header file containing the last git revision
#define GIT_HASH "408c69b"
#define GIT_HASH "527ebdc"
#endif //FLOATPUMP_GIT_REVISION_TEMPLATE_H

View File

@ -17,6 +17,7 @@
#include "RelayChannel.h"
#include "GPIChannel.h"
#include "Menu_Entry_Type_Execute.h"
#include "NewMenu.h"
#define SLAVE_ADDRESS_LCD 0x4e
@ -110,7 +111,8 @@ void CheckRefillConditions(Config_Store &cfg, io::PressureChannel &tankLevel, io
} else {
HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
refillPump.switchRelay(io::RelayChannel::state::OFF);
S_refillcooldown = (((c_RefillCooldown + (cfg.RefillCooldown.getValue() * 60*1000)) - HAL_GetTick()) / 1000);
S_refillcooldown = (((c_RefillCooldown + (cfg.RefillCooldown.getValue() * 60 * 1000)) - HAL_GetTick()) /
1000);
}
} else {
refillPump.switchRelay(io::RelayChannel::state::OFF);
@ -149,6 +151,15 @@ int main(void) {
initializer.runInitSequence();
//EXP
using namespace floatpump::newmenu;
//EXP
///
///
/// LOGICAL CODE BEGIN
@ -159,79 +170,38 @@ int main(void) {
using namespace floatpump;
menu::Menu tankmenu("Tank");
newmenu::Menu tankmenu("Tank");
bool a_caliblow, a_calibhigh = false;
menu::Menu_Entry_Type_Execute t_exCalibLow;
menu::Menu_Entry_Type_Execute t_exCalibHigh;
t_exCalibLow.linkConfig(&a_caliblow);
t_exCalibHigh.linkConfig(&a_calibhigh);
menu::Menu_Entry exCalibLow(t_exCalibLow, "Kal. Unt. Punkt");
menu::Menu_Entry exCalibHigh(t_exCalibHigh, "Kal. Ob. Punkt");
tankmenu.addEntry<MenuEntryExecute>(&a_caliblow, "Kal. Unt. Punkt");
tankmenu.addEntry<MenuEntryExecute>(&a_calibhigh, "Kal. Ob. Punkt");
menu::Menu_Entry_Type_Numeric t_CalibLow(0);
menu::Menu_Entry_Type_Numeric t_CalibHigh(65535);
t_CalibLow.linkConfig(globalConfig.TankCalibLow.getLink());
t_CalibHigh.linkConfig(globalConfig.TankCalibHigh.getLink());
menu::Menu_Entry CalibLow(t_CalibLow, "K Unten");
menu::Menu_Entry CalibHigh(t_CalibHigh, "K Oben");
tankmenu.addEntry<MenuEntryNumeric>(globalConfig.TankCalibLow.getLink(), "K Unten");
tankmenu.addEntry<MenuEntryNumeric>(globalConfig.TankCalibHigh.getLink(), "K Oben");
menu::Menu_Entry_Type_Percent t_tankLevel(25);
t_tankLevel.linkConfig(globalConfig.TankMinLevel.getLink());
menu::Menu_Entry TankLevel(t_tankLevel, "Min. Fuellst.");
tankmenu.addEntry<MenuEntryPercent>(globalConfig.TankMinLevel.getLink(), "Min. Fuellst.");
tankmenu.addEntry<MenuEntryPercent>(globalConfig.TankHysteresis.getLink(), "Hysterese");
menu::Menu_Entry_Type_Percent t_tankHysteresis(5);
t_tankHysteresis.linkConfig(globalConfig.TankHysteresis.getLink());
menu::Menu_Entry TankHysteresis(t_tankHysteresis, "Hysterese");
menu::Menu_Entry_Type_Checkable t_tankInvert(false);
t_tankInvert.linkConfig(globalConfig.TankPumpInvert.getLink());
menu::Menu_Entry TankInvert(t_tankInvert, "Inv. Relais");
tankmenu.addEntry(exCalibLow);
tankmenu.addEntry(exCalibHigh);
tankmenu.addEntry(CalibLow);
tankmenu.addEntry(CalibHigh);
tankmenu.addEntry(TankLevel);
tankmenu.addEntry(TankHysteresis);
tankmenu.addEntry(TankInvert);
tankmenu.addEntry<MenuEntryCheckable>(globalConfig.TankPumpInvert.getLink(), "Inv Relais");
menu::Menu refillmenu("Nachspeisung");
newmenu::Menu refillmenu("Nachspeisung");
menu::Menu_Entry_Type_Checkable t_refillEnable(false);
menu::Menu_Entry_Type_Checkable t_refillBlock(true);
menu::Menu_Entry_Type_Checkable t_refillBlockInvert(false);
t_refillEnable.linkConfig(globalConfig.RefillEnable.getLink());
t_refillBlock.linkConfig(globalConfig.RefillBlockEnable.getLink());
t_refillBlockInvert.linkConfig(globalConfig.RefillBlockInvert.getLink());
menu::Menu_Entry refillEnable(t_refillEnable, "Nachsp. akt.");
menu::Menu_Entry refillBlock(t_refillBlock, "Notabschalt.");
menu::Menu_Entry refillBlockInvert(t_refillBlockInvert, "NotAbs. Inv.");
refillmenu.addEntry<MenuEntryCheckable>(globalConfig.RefillEnable.getLink(), "Nachsp. akt.");
refillmenu.addEntry<MenuEntryCheckable>(globalConfig.RefillBlockEnable.getLink(), "Notabschalt.");
refillmenu.addEntry<MenuEntryCheckable>(globalConfig.RefillBlockInvert.getLink(), "NotAbs. Inv.");
menu::Menu_Entry_Type_Percent t_RefillBelow(20);
menu::Menu_Entry_Type_Percent t_RefillHysteresis(5);
t_RefillBelow.linkConfig(globalConfig.RefillBelow.getLink());
t_RefillHysteresis.linkConfig(globalConfig.RefillHysteresis.getLink());
menu::Menu_Entry refillBelow(t_RefillBelow, "Auff. bis");
menu::Menu_Entry refillHysteresis(t_RefillHysteresis, "Hysterese");
refillmenu.addEntry<MenuEntryPercent>(globalConfig.RefillBelow.getLink(), "Auff. bis");
refillmenu.addEntry<MenuEntryPercent>(globalConfig.RefillHysteresis.getLink(), "Hysterese");
menu::Menu_Entry_Type_Numeric t_RefillCooldown(10);
t_RefillCooldown.linkConfig(reinterpret_cast<uint16_t *>(globalConfig.RefillCooldown.getLink()));
menu::Menu_Entry refillCooldown(t_RefillCooldown, "Wartezeit");
refillmenu.addEntry<MenuEntryNumeric>(globalConfig.RefillCooldown.getLink(), "Wartezeit");
refillmenu.addEntry(refillEnable);
refillmenu.addEntry(refillBlock);
refillmenu.addEntry(refillBlockInvert);
refillmenu.addEntry(refillBelow);
refillmenu.addEntry(refillHysteresis);
refillmenu.addEntry(refillCooldown);
menu::Menu mainmenu("Hauptmenu");
newmenu::Menu mainmenu("Hauptmenu");
mainmenu.addSubmenu(&tankmenu);
mainmenu.addSubmenu(&refillmenu);
menu::Menu_Controller controller(&mainmenu, display);
newmenu::Menu_Controller controller(&mainmenu, display);
static int old_pos = 0;
//Instantiate Input and Output modules
@ -246,16 +216,16 @@ int main(void) {
uint32_t last_backlight_retrigger = 0;
bool f_store = false, f_restore = false;
menu::Menu_Entry_Type_Execute t_MStore;
menu::Menu_Entry_Type_Execute t_MRestore;
t_MStore.linkConfig(&f_store);
t_MRestore.linkConfig(&f_restore);
menu::Menu_Entry MStore(t_MStore, "Speichern");
menu::Menu_Entry MRestore(t_MRestore, "Laden");
mainmenu.addEntry(MStore);
mainmenu.addEntry(MRestore);
// menu::Menu_Entry_Type_Execute t_MStore;
// menu::Menu_Entry_Type_Execute t_MRestore;
// t_MStore.linkConfig(&f_store);
// t_MRestore.linkConfig(&f_restore);
// menu::Menu_Entry MStore(t_MStore, "Speichern");
// menu::Menu_Entry MRestore(t_MRestore, "Laden");
//
//
// mainmenu.addEntry(MStore);
// mainmenu.addEntry(MRestore);
while (1) {
@ -264,7 +234,8 @@ int main(void) {
display.LCDSetCursor(0, 0);
display.LCDSendCString(
const_cast<char *>(std::string("Fuellstand " + std::to_string(tankLevel0.getPercent()) + " %").c_str()));
const_cast<char *>(std::string(
"Fuellstand " + std::to_string(tankLevel0.getPercent()) + " %").c_str()));
display.LCDSetCursor(0, 1);
if (S_tankempty) {
display.LCDSendCString(const_cast<char *>(std::string("Tank Wassermangel ").c_str()));
@ -289,9 +260,11 @@ int main(void) {
if (S_refillcooldown > 0) {
int remaining_mins = S_refillcooldown / 60;
if (remaining_mins > 0)
display.LCDSendCString(const_cast<char *>(std::string("Nsp. wartet: min " + std::to_string( S_refillcooldown / 60)).c_str()));
display.LCDSendCString(const_cast<char *>(std::string(
"Nsp. wartet: min " + std::to_string(S_refillcooldown / 60)).c_str()));
else
display.LCDSendCString(const_cast<char *>(std::string("Nsp. wartet: s " + std::to_string(S_refillcooldown)).c_str()));
display.LCDSendCString(
const_cast<char *>(std::string("Nsp. wartet: s " + std::to_string(S_refillcooldown)).c_str()));
} else if (S_refillempty) {
display.LCDSendCString(const_cast<char *>(std::string("Nachspeisung mangel ").c_str()));
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET);
@ -303,11 +276,11 @@ int main(void) {
//Check for rotation to enable display backlight
if (old_pos < rot_counter) {
controller.pushEvent(menu::Menu_Controller::Event::Increase);
controller.pushEvent(newmenu::Menu_Controller::Event::Increase);
old_pos = rot_counter;
last_backlight_retrigger = HAL_GetTick();
} else if (old_pos > rot_counter) {
controller.pushEvent(menu::Menu_Controller::Event::Decrease);
controller.pushEvent(newmenu::Menu_Controller::Event::Decrease);
old_pos = rot_counter;
last_backlight_retrigger = HAL_GetTick();
}
@ -328,16 +301,16 @@ int main(void) {
controller.execute();
if (rot_button) {
rot_button = false;
controller.pushEvent(menu::Menu_Controller::Event::Push);
controller.pushEvent(newmenu::Menu_Controller::Event::Push);
last_menu_retrigger = HAL_GetTick();
}
if (old_pos < rot_counter) {
controller.pushEvent(menu::Menu_Controller::Event::Increase);
controller.pushEvent(newmenu::Menu_Controller::Event::Increase);
old_pos = rot_counter;
last_menu_retrigger = HAL_GetTick();
} else if (old_pos > rot_counter) {
controller.pushEvent(menu::Menu_Controller::Event::Decrease);
controller.pushEvent(newmenu::Menu_Controller::Event::Decrease);
old_pos = rot_counter;
last_menu_retrigger = HAL_GetTick();
}

View File

@ -5,9 +5,10 @@
#ifndef FLOATPUMP_MENU_CONTROLLER_H
#define FLOATPUMP_MENU_CONTROLLER_H
#include "Menu.h"
#include "NewMenu.h"
#include "LCD_I2C_Driver.h"
namespace floatpump::menu {
namespace floatpump::newmenu {
class Menu_Controller {
public:

View File

@ -0,0 +1,255 @@
//
// Created by robtor on 26.01.23.
//
#ifndef FLOATPUMP_NEWMENU_H
#define FLOATPUMP_NEWMENU_H
#include <cstdint>
#include <string>
#include <vector>
#include <memory>
#include <optional>
namespace floatpump {
namespace newmenu {
struct IMenuEntry {
virtual ~IMenuEntry() = default;
virtual auto u_press() -> void = 0;
virtual auto u_increase(uint16_t steps = 1) -> void = 0;
virtual auto u_decrease(uint16_t steps = 1) -> void = 0;
virtual auto is_entered() -> bool = 0;
virtual auto toString() -> std::string = 0;
};
template<typename T>
class MenuEntry : public IMenuEntry {
public:
MenuEntry(T *linked_config, std::string name) : m_name(name) {
m_storage = linked_config;
};
auto getValue() -> T & {
return (*m_storage);
}
auto setValue(T &value) -> void {
*m_storage = value;
}
auto relinkConfig(T *linked_config) -> void {
m_storage = linked_config;
}
protected:
T *m_storage;
std::string m_name;
bool m_entered = false;
auto buildString(std::string appendix) -> std::string {
int spaces = 19 - (m_name.length() + appendix.length());
std::string spacer;
if (spaces > 0)
spacer.append(spaces, ' ');
else if (spaces < 0)
return "ERROR";
return {m_name + spacer + appendix};
}
};
class MenuEntryCheckable : public MenuEntry<bool> {
public:
MenuEntryCheckable(bool *linked_config, const std::string &name) : MenuEntry(linked_config, name) {}
auto toString() -> std::string override {
return buildString({(*m_storage) ? "ON " : "OFF"});
}
auto u_press() -> void override {
*m_storage = !(*m_storage);
}
auto u_increase(uint16_t steps) -> void override {
}
auto u_decrease(uint16_t steps) -> void override {
}
auto is_entered() -> bool override {
return false;
}
};
class MenuEntryExecute : public MenuEntry<bool> {
public:
MenuEntryExecute(bool *linked_config, const std::string &name) : MenuEntry(linked_config, name) {}
auto u_press() -> void override {
*m_storage = true;
}
auto u_increase(uint16_t steps) -> void override {
}
auto u_decrease(uint16_t steps) -> void override {
}
auto is_entered() -> bool override {
return false;
}
auto toString() -> std::string override {
return buildString({(*m_storage) ? "[--]" : "[XX]"});
}
};
class MenuEntryNumeric : public MenuEntry<uint16_t> {
public:
MenuEntryNumeric(uint16_t *linked_config, const std::string &name) : MenuEntry(linked_config, name) {}
auto u_press() -> void override {
m_entered = !m_entered;
}
auto u_increase(uint16_t steps) -> void override {
(*m_storage)++;
}
auto u_decrease(uint16_t steps) -> void override {
(*m_storage)--;
}
auto is_entered() -> bool override {
return m_entered;
}
auto toString() -> std::string override {
if (m_entered) {
return buildString({"> " + std::to_string(*m_storage)});
} else {
return buildString({" " + std::to_string(*m_storage)});
}
}
};
class MenuEntryPercent : public MenuEntry<uint8_t> {
public:
MenuEntryPercent(uint8_t *linked_config, const std::string &name) : MenuEntry(linked_config, name) {}
auto u_press() -> void override {
m_entered = !m_entered;
}
auto u_increase(uint16_t steps) -> void override {
if (*m_storage < 100)
(*m_storage)++;
}
auto u_decrease(uint16_t steps) -> void override {
if (*m_storage > 0) {
(*m_storage)--;
}
}
auto is_entered() -> bool override {
return m_entered;
}
auto toString() -> std::string override {
if (m_entered) {
return buildString({"> %" + std::to_string(*m_storage)});
} else {
return buildString({" %" + std::to_string(*m_storage)});
}
}
};
class Menu {
public:
explicit Menu(const std::string &m_name) : m_name(m_name) {}
template<typename T, typename... As>
auto addEntry(As&& ...args) -> void{
m_entries.push_back(std::make_unique<T>(std::forward<As>(args)...));
}
auto addSubmenu(Menu *submenu) -> void {
submenu->m_parent = this;
m_submenus.push_back(submenu);
}
auto printLine() -> const std::string {
return m_name;
}
auto getDisplayList() -> std::vector<std::string> {
std::vector<std::string> list;
list.reserve(m_submenus.size() + m_entries.size());
//Append all Submenus
for (auto &m_submenu: m_submenus) {
list.push_back(m_submenu->printLine());
}
//Append all Entries
for (auto &m_entry: m_entries) {
list.push_back(m_entry->toString());
}
//Append Go-Back-Entry if we are within a submenu
if (m_parent != nullptr) {
list.emplace_back("<- Zurueck");
}
return list;
}
auto getAllEntriesNum() -> unsigned const int {
return (m_entries.size() + m_submenus.size()) + ((m_parent != nullptr) ? 1 : 0);
}
auto getSubmenu(int index) -> Menu* {
if (index >= 0 && index < m_submenus.size()) {
return m_submenus[index];
} else {
return nullptr;
}
}
auto getEntry(int index) -> std::optional<std::reference_wrapper<IMenuEntry>> {
if (index >= m_submenus.size() && index < m_entries.size() + m_submenus.size()) {
return *m_entries[index - m_submenus.size()];
} else {
return std::nullopt;
}
}
auto getParent() -> Menu* {
return m_parent;
}
private:
std::vector<std::unique_ptr<IMenuEntry>> m_entries;
std::vector<Menu *> m_submenus;
Menu *m_parent = nullptr;
std::string m_name;
};
}
}
#endif //FLOATPUMP_NEWMENU_H

View File

@ -4,7 +4,7 @@
#include "Menu_Controller.h"
namespace floatpump::menu {
namespace floatpump::newmenu {
void Menu_Controller::execute() {
displayMenu(m_menu);
@ -70,8 +70,8 @@ namespace floatpump::menu {
m_menu = m->getSubmenu(m_current_index);
m_current_index = 0;
//Forward press action if entry is entry
} else if (m->getEntry(m_current_index) != nullptr) {
m->getEntry(m_current_index)->action_press();
} else if (m->getEntry(m_current_index) != std::nullopt) {
m->getEntry(m_current_index)->get().u_press();
//If we are on the Go-Back-Entry and have a parent: replace menu with parent menu
} else if (m_menu->getParent() != nullptr) {
m_menu = m_menu->getParent();
@ -81,10 +81,10 @@ namespace floatpump::menu {
void Menu_Controller::increase(Menu *m) {
if (m_current_index < m->getAllEntriesNum()) {
if (m->getEntry(m_current_index) != nullptr) {
if (m->getEntry(m_current_index) != std::nullopt) {
//Forward increase action to entry if we have an entered entry
if (m->getEntry(m_current_index)->isEntered()) {
m->getEntry(m_current_index)->action_increase();
if (m->getEntry(m_current_index)->get().is_entered()) {
m->getEntry(m_current_index)->get().u_increase();
} else if (m_current_index < m->getAllEntriesNum() - 1) {
m_current_index++;
}
@ -98,10 +98,10 @@ namespace floatpump::menu {
void Menu_Controller::decrease(Menu *m) {
if (m_current_index > 0) {
if (m->getEntry(m_current_index) != nullptr) {
if (m->getEntry(m_current_index) != std::nullopt) {
//Forward decrease action to entry if we have an entered entry
if (m->getEntry(m_current_index)->isEntered()) {
m->getEntry(m_current_index)->action_decrease();
if (m->getEntry(m_current_index)->get().is_entered()) {
m->getEntry(m_current_index)->get().u_decrease();
} else {
m_current_index--;
}