code optimization

- lifecycle functions for widgets
- persistence functions

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2025-06-20 20:53:13 +02:00
parent 1a912d31c4
commit a0fe4ba538
11 changed files with 218 additions and 153 deletions

View File

@@ -31,7 +31,7 @@
*/ */
class Widget class Widget
{ {
public: public:
/** /**
* @brief Constructs a widget with the given u8g2 display context * @brief Constructs a widget with the given u8g2 display context
* @param u8g2 Pointer to the u8g2 display context used for rendering operations * @param u8g2 Pointer to the u8g2 display context used for rendering operations
@@ -51,6 +51,11 @@ public:
*/ */
virtual ~Widget() = default; virtual ~Widget() = default;
virtual void enter();
virtual void pause();
virtual void resume();
virtual void exit();
/** /**
* @brief Updates the widget's internal state based on elapsed time * @brief Updates the widget's internal state based on elapsed time
* @param dt Delta time in milliseconds since the last update call * @param dt Delta time in milliseconds since the last update call
@@ -96,7 +101,7 @@ public:
*/ */
virtual void onButtonClicked(ButtonType button); virtual void onButtonClicked(ButtonType button);
protected: protected:
/** /**
* @brief Pointer to the u8g2 display context used for rendering operations * @brief Pointer to the u8g2 display context used for rendering operations
* @details This member provides access to the u8g2 graphics library functions * @details This member provides access to the u8g2 graphics library functions

View File

@@ -4,6 +4,22 @@ Widget::Widget(u8g2_t *u8g2) : u8g2(u8g2)
{ {
} }
void Widget::enter()
{
}
void Widget::pause()
{
}
void Widget::resume()
{
}
void Widget::exit()
{
}
void Widget::update(uint64_t dt) void Widget::update(uint64_t dt)
{ {
} }

View File

@@ -45,7 +45,7 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
if (m_options && m_options->persistence && m_options->persistence->save) if (m_options && m_options->persistence && m_options->persistence->save)
{ {
const auto value = getItem(item.getId()).getValue(); const auto value = getItem(item.getId()).getValue();
m_options->persistence->save("light_activated", value.c_str()); m_options->persistence->save(VALUE_TYPE_STRING, "light_activated", value.c_str());
} }
break; break;
} }
@@ -57,8 +57,8 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
{ {
if (m_options && m_options->persistence && m_options->persistence->save) if (m_options && m_options->persistence && m_options->persistence->save)
{ {
const auto value = std::to_string(getItem(item.getId()).getIndex()); const auto value = getItem(item.getId()).getIndex();
m_options->persistence->save("light_mode", value.c_str()); m_options->persistence->save(VALUE_TYPE_INT32, "light_mode", &value);
} }
} }
break; break;

View File

@@ -37,6 +37,6 @@ void LightSettingsMenu::onButtonPressed(const MenuItem &menuItem, const ButtonTy
{ {
const auto key = "section_" + std::to_string(menuItem.getId()); const auto key = "section_" + std::to_string(menuItem.getId());
const auto value = getItem(menuItem.getId()).getValue(); const auto value = getItem(menuItem.getId()).getValue();
m_options->persistence->save(key.c_str(), value.c_str()); m_options->persistence->save(VALUE_TYPE_STRING, key.c_str(), value.c_str());
} }
} }

View File

@@ -1,6 +1,6 @@
if (DEFINED ENV{IDF_PATH}) if (DEFINED ENV{IDF_PATH})
idf_component_register(SRCS idf_component_register(SRCS
persistence.c espressif/persistence.c
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
PRIV_REQUIRES PRIV_REQUIRES
nvs_flash nvs_flash

View File

@@ -0,0 +1,116 @@
#include "persistence.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "nvs_flash.h"
static const char *TAG = "persistence";
static nvs_handle_t persistence_handle;
static SemaphoreHandle_t persistence_mutex;
void *persistence_init(const char *namespace_name)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(nvs_open(namespace_name, NVS_READWRITE, &persistence_handle));
persistence_mutex = xSemaphoreCreateMutex();
if (persistence_mutex == NULL)
{
ESP_LOGE(TAG, "Failed to create mutex");
}
return &persistence_handle;
}
void persistence_save(persistence_value_t value_type, const char *key, const void *value)
{
if (persistence_mutex != NULL)
{
if (xSemaphoreTake(persistence_mutex, portMAX_DELAY) == pdTRUE)
{
esp_err_t err = ESP_ERR_INVALID_ARG;
switch (value_type)
{
case VALUE_TYPE_STRING:
err = nvs_set_str(persistence_handle, key, (char *)value);
break;
case VALUE_TYPE_INT32:
err = nvs_set_i32(persistence_handle, key, *(int32_t *)value);
break;
default:
ESP_LOGE(TAG, "Unsupported value type");
break;
}
if (err == ESP_OK)
{
ESP_ERROR_CHECK(nvs_commit(persistence_handle));
}
else
{
ESP_LOGE(TAG, "Error saving key %s: %s", key, esp_err_to_name(err));
}
xSemaphoreGive(persistence_mutex);
}
}
}
void *persistence_load(persistence_value_t value_type, const char *key, void *out)
{
if (persistence_mutex != NULL)
{
if (xSemaphoreTake(persistence_mutex, portMAX_DELAY) == pdTRUE)
{
esp_err_t err = ESP_ERR_INVALID_ARG;
switch (value_type)
{
case VALUE_TYPE_STRING:
err = nvs_get_str(persistence_handle, key, (char *)out, NULL);
break;
case VALUE_TYPE_INT32:
err = nvs_get_i32(persistence_handle, key, (int32_t *)out);
break;
default:
ESP_LOGE(TAG, "Unsupported value type");
break;
}
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Error loading key %s: %s", key, esp_err_to_name(err));
}
xSemaphoreGive(persistence_mutex);
}
}
return out;
}
void persistence_deinit()
{
if (persistence_mutex != NULL)
{
vSemaphoreDelete(persistence_mutex);
persistence_mutex = NULL;
}
nvs_close(persistence_handle);
}

View File

@@ -9,10 +9,17 @@ typedef enum
typedef struct typedef struct
{ {
void *handle; void *handle;
void (*save)(const char *key, const char *value); void (*save)(persistence_value_t value_type, const char *key, const void *value);
} persistence_t; } persistence_t;
#ifdef __cplusplus
extern "C"
{
#endif
void *persistence_init(const char *namespace_name); void *persistence_init(const char *namespace_name);
void persistence_save(persistence_value_t value_type, const char *key, const void *value); void persistence_save(persistence_value_t value_type, const char *key, const void *value);
void *persistence_load(persistence_value_t value_type, const char *key, void *out); void *persistence_load(persistence_value_t value_type, const char *key, void *out);
void persistence_deinit(); void persistence_deinit();
#ifdef __cplusplus
}
#endif

View File

@@ -1,13 +1,25 @@
#include "persistence.h" #include "persistence.h"
#include "stddef.h" #include "stddef.h"
#include <stdio.h>
void *persistence_init(const char *namespace_name) void *persistence_init(const char *namespace_name)
{ {
return NULL; return NULL;
} }
void persistence_save(persistence_value_t value_type, const char *key, const void *value) void persistence_save(const persistence_value_t value_type, const char *key, const void *value)
{ {
printf("Key: %s - ", key);
switch (value_type)
{
case VALUE_TYPE_STRING:
printf("Value (s): %s\n", (char *)value);
break;
case VALUE_TYPE_INT32:
printf("Value (i): %d\n", *(int32_t *)value);
break;
}
} }
void *persistence_load(persistence_value_t value_type, const char *key, void *out) void *persistence_load(persistence_value_t value_type, const char *key, void *out)
@@ -18,120 +30,3 @@ void *persistence_load(persistence_value_t value_type, const char *key, void *ou
void persistence_deinit() void persistence_deinit()
{ {
} }
/*
#include "esp_err.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "nvs_flash.h"
static const char *TAG = "persistence";
static nvs_handle_t persistence_handle;
static SemaphoreHandle_t persistence_mutex;
void *persistence_init(const char *namespace_name)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(nvs_open(namespace_name, NVS_READWRITE, &persistence_handle));
persistence_mutex = xSemaphoreCreateMutex();
if (persistence_mutex == NULL)
{
ESP_LOGE(TAG, "Failed to create mutex");
}
return &persistence_handle;
}
void persistence_save(persistence_value_t value_type, const char *key, const void *value)
{
if (persistence_mutex != NULL)
{
if (xSemaphoreTake(persistence_mutex, portMAX_DELAY) == pdTRUE)
{
esp_err_t err = ESP_ERR_INVALID_ARG;
switch (value_type)
{
case VALUE_TYPE_STRING:
err = nvs_set_str(persistence_handle, key, (char *)value);
break;
case VALUE_TYPE_INT32:
err = nvs_set_i32(persistence_handle, key, *(int32_t *)value);
break;
default:
ESP_LOGE(TAG, "Unsupported value type");
break;
}
if (err == ESP_OK)
{
ESP_ERROR_CHECK(nvs_commit(persistence_handle));
}
else
{
ESP_LOGE(TAG, "Error saving key %s: %s", key, esp_err_to_name(err));
}
xSemaphoreGive(persistence_mutex);
}
}
}
void *persistence_load(persistence_value_t value_type, const char *key, void *out)
{
if (persistence_mutex != NULL)
{
if (xSemaphoreTake(persistence_mutex, portMAX_DELAY) == pdTRUE)
{
esp_err_t err = ESP_ERR_INVALID_ARG;
switch (value_type)
{
case VALUE_TYPE_STRING:
err = nvs_get_str(persistence_handle, key, (char *)out, NULL);
break;
case VALUE_TYPE_INT32:
err = nvs_get_i32(persistence_handle, key, (int32_t *)out);
break;
default:
ESP_LOGE(TAG, "Unsupported value type");
break;
}
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Error loading key %s: %s", key, esp_err_to_name(err));
}
xSemaphoreGive(persistence_mutex);
}
}
return out;
}
void persistence_deinit()
{
if (persistence_mutex != NULL)
{
vSemaphoreDelete(persistence_mutex);
persistence_mutex = NULL;
}
nvs_close(persistence_handle);
}
*/

View File

@@ -59,6 +59,7 @@ void setScreen(const std::shared_ptr<Widget> &screen)
m_widget = screen; m_widget = screen;
m_history.clear(); m_history.clear();
m_history.emplace_back(m_widget); m_history.emplace_back(m_widget);
m_widget->enter();
} }
} }
@@ -66,7 +67,12 @@ void pushScreen(const std::shared_ptr<Widget> &screen)
{ {
if (screen != nullptr) if (screen != nullptr)
{ {
if (m_widget)
{
m_widget->pause();
}
m_widget = screen; m_widget = screen;
m_widget->enter();
m_history.emplace_back(m_widget); m_history.emplace_back(m_widget);
} }
} }
@@ -76,7 +82,12 @@ void popScreen()
if (m_history.size() >= 2) if (m_history.size() >= 2)
{ {
m_history.pop_back(); m_history.pop_back();
if (m_widget)
{
m_widget->exit();
}
m_widget = m_history.back(); m_widget = m_history.back();
m_widget->resume();
} }
} }

View File

@@ -3,6 +3,7 @@
#include <hal/u8g2_hal_sdl.h> #include <hal/u8g2_hal_sdl.h>
#include <u8g2.h> #include <u8g2.h>
#include "persistence.h"
#include "MenuOptions.h" #include "MenuOptions.h"
#include "common/InactivityTracker.h" #include "common/InactivityTracker.h"
#include "ui/ScreenSaver.h" #include "ui/ScreenSaver.h"
@@ -55,11 +56,15 @@ Device::Device(void *appstate) : UIWidget(appstate)
m_children.push_back(std::make_shared<Button>( m_children.push_back(std::make_shared<Button>(
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + DPAD_WIDTH, GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + DPAD_WIDTH,
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - BUTTON_WIDTH, BUTTON_WIDTH, U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - BUTTON_WIDTH, BUTTON_WIDTH,
[]() { PushKey(SDLK_RETURN); })); []() {
PushKey(SDLK_RETURN);
}));
m_children.push_back(std::make_shared<Button>( m_children.push_back(std::make_shared<Button>(
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 4 * U8G2_SCREEN_PADDING + DPAD_WIDTH + BUTTON_WIDTH, GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 4 * U8G2_SCREEN_PADDING + DPAD_WIDTH + BUTTON_WIDTH,
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - 2 * BUTTON_WIDTH, BUTTON_WIDTH, U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - 2 * BUTTON_WIDTH, BUTTON_WIDTH,
[]() { PushKey(SDLK_BACKSPACE); })); []() {
PushKey(SDLK_BACKSPACE);
}));
m_children.push_back(std::make_shared<D_Pad>( m_children.push_back(std::make_shared<D_Pad>(
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 2 * U8G2_SCREEN_PADDING, GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 2 * U8G2_SCREEN_PADDING,
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - DPAD_WIDTH, DPAD_WIDTH, dpad_callback)); U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - DPAD_WIDTH, DPAD_WIDTH, dpad_callback));
@@ -67,13 +72,19 @@ Device::Device(void *appstate) : UIWidget(appstate)
u8g2_Setup_sh1106_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sdl_hw_spi, u8x8_gpio_and_delay_sdl); u8g2_Setup_sh1106_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sdl_hw_spi, u8x8_gpio_and_delay_sdl);
u8x8_InitDisplay(u8g2_GetU8x8(&u8g2)); u8x8_InitDisplay(u8g2_GetU8x8(&u8g2));
m_persistence = {.save = savePersistence}; m_persistence.save = persistence_save;
options = { options = {
.u8g2 = &u8g2, .u8g2 = &u8g2,
.setScreen = [this](const std::shared_ptr<Widget> &screen) { this->SetScreen(screen); }, .setScreen = [this](const std::shared_ptr<Widget> &screen) {
.pushScreen = [this](const std::shared_ptr<Widget> &screen) { this->PushScreen(screen); }, this->SetScreen(screen);
.popScreen = [this]() { this->PopScreen(); }, },
.pushScreen = [this](const std::shared_ptr<Widget> &screen) {
this->PushScreen(screen);
},
.popScreen = [this]() {
this->PopScreen();
},
.persistence = &m_persistence, .persistence = &m_persistence,
}; };
m_widget = std::make_shared<SplashScreen>(&options); m_widget = std::make_shared<SplashScreen>(&options);
@@ -90,6 +101,7 @@ void Device::SetScreen(const std::shared_ptr<Widget> &screen)
m_widget = screen; m_widget = screen;
m_history.clear(); m_history.clear();
m_history.emplace_back(m_widget); m_history.emplace_back(m_widget);
m_widget->enter();
} }
} }
@@ -97,8 +109,13 @@ void Device::PushScreen(const std::shared_ptr<Widget> &screen)
{ {
if (screen != nullptr) if (screen != nullptr)
{ {
if (m_widget)
{
m_widget->pause();
}
m_widget = screen; m_widget = screen;
m_history.emplace_back(m_widget); m_history.emplace_back(m_widget);
m_widget->enter();
} }
} }
@@ -106,8 +123,13 @@ void Device::PopScreen()
{ {
if (m_history.size() >= 2) if (m_history.size() >= 2)
{ {
if (m_widget)
{
m_widget->exit();
}
m_history.pop_back(); m_history.pop_back();
m_widget = m_history.back(); m_widget = m_history.back();
m_widget->resume();
} }
} }
@@ -119,11 +141,6 @@ void Device::PushKey(const SDL_Keycode key)
SDL_PushEvent(&ev); SDL_PushEvent(&ev);
} }
void Device::savePersistence(const char *key, const char *value)
{
SDL_Log("Saving: %s = %s", key, value);
}
void Device::RenderU8G2() const void Device::RenderU8G2() const
{ {
SDL_Surface *u8g2_surface = nullptr; SDL_Surface *u8g2_surface = nullptr;

View File

@@ -44,8 +44,6 @@ private:
static void PushKey(SDL_Keycode key); static void PushKey(SDL_Keycode key);
static void savePersistence(const char *key, const char *value);
std::vector<std::shared_ptr<UIWidget>> m_children{}; std::vector<std::shared_ptr<UIWidget>> m_children{};
std::shared_ptr<Widget> m_widget; std::shared_ptr<Widget> m_widget;
std::vector<std::shared_ptr<Widget>> m_history; std::vector<std::shared_ptr<Widget>> m_history;