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

@@ -22,23 +22,23 @@
* must implement or can override. The class follows the template method pattern,
* allowing derived classes to customize behavior while maintaining a consistent
* interface for the UI system.
*
*
* @note All widgets should inherit from this class to ensure compatibility with
* the UI management system.
*
*
* @see u8g2_t
* @see ButtonType
*/
class Widget
{
public:
public:
/**
* @brief Constructs a widget with the given u8g2 display context
* @param u8g2 Pointer to the u8g2 display context used for rendering operations
*
*
* @pre u8g2 must not be nullptr
* @post Widget is initialized with the provided display context
*
*
* @note The widget does not take ownership of the u8g2 context and assumes
* it remains valid for the lifetime of the widget.
*/
@@ -51,15 +51,20 @@ public:
*/
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
* @param dt Delta time in milliseconds since the last update call
*
*
* @details This method is called once per frame by the UI system to handle
* animations, timers, state transitions, or other time-dependent behavior.
* The base implementation is empty, allowing derived classes to override
* only if time-based updates are needed.
*
*
* @note Override this method in derived classes to implement time-based behavior
* such as animations, blinking effects, or timeout handling.
*/
@@ -71,10 +76,10 @@ public:
* their specific rendering logic using the u8g2 display context.
* The base implementation is empty, requiring derived classes to
* provide their own rendering code.
*
*
* @pre u8g2 context must be initialized and ready for drawing operations
* @post Widget's visual representation is drawn to the display buffer
*
*
* @note This method is called during the rendering phase of each frame.
* Derived classes should use the u8g2 member variable to perform
* drawing operations.
@@ -84,29 +89,29 @@ public:
/**
* @brief Handles button press events
* @param button The type of button that was pressed
*
*
* @details This method is called when a button press event occurs and allows
* the widget to respond to user input. The base implementation is empty,
* allowing derived classes to override only if input handling is needed.
*
*
* @note Override this method in derived classes to implement button-specific
* behavior such as navigation, selection, or state changes.
*
*
* @see ButtonType for available button types
*/
virtual void onButtonClicked(ButtonType button);
protected:
protected:
/**
* @brief Pointer to the u8g2 display context used for rendering operations
* @details This member provides access to the u8g2 graphics library functions
* for drawing text, shapes, bitmaps, and other UI elements. It is
* initialized during construction and remains valid for the widget's lifetime.
*
*
* @note This member is protected to allow derived classes direct access while
* preventing external modification. Derived classes should use this
* context for all rendering operations.
*
*
* @warning Do not modify or delete this pointer. The widget does not own
* the u8g2 context and assumes it is managed externally.
*/

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)
{
}

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)
{
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;
}
@@ -57,8 +57,8 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
{
if (m_options && m_options->persistence && m_options->persistence->save)
{
const auto value = std::to_string(getItem(item.getId()).getIndex());
m_options->persistence->save("light_mode", value.c_str());
const auto value = getItem(item.getId()).getIndex();
m_options->persistence->save(VALUE_TYPE_INT32, "light_mode", &value);
}
}
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 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})
idf_component_register(SRCS
persistence.c
espressif/persistence.c
INCLUDE_DIRS "include"
PRIV_REQUIRES
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
{
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;
#ifdef __cplusplus
extern "C"
{
#endif
void *persistence_init(const char *namespace_name);
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_deinit();
#ifdef __cplusplus
}
#endif

View File

@@ -1,13 +1,25 @@
#include "persistence.h"
#include "stddef.h"
#include <stdio.h>
void *persistence_init(const char *namespace_name)
{
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)
@@ -17,121 +29,4 @@ void *persistence_load(persistence_value_t value_type, const char *key, void *ou
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);
}
*/
}