starting status WLEDs behavior

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2025-08-23 16:02:21 +02:00
parent d8b1718069
commit 6e84d57b77
9 changed files with 252 additions and 24 deletions

2
firmware/.gitignore vendored
View File

@@ -1,5 +1,6 @@
# esp-idf # esp-idf
build/ build/
build-release/
managed_components/ managed_components/
sdkconfig sdkconfig
sdkconfig.old sdkconfig.old
@@ -16,7 +17,6 @@ cmake_install.cmake
install_manifest.txt install_manifest.txt
CMakeFiles/ CMakeFiles/
CTestTestfile.cmake CTestTestfile.cmake
Makefile
CMakeScripts CMakeScripts
compile_commands.json compile_commands.json

15
firmware/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdbtarget",
"request": "attach",
"name": "Eclipse CDT GDB Adapter"
},
{
"type": "espidf",
"name": "Launch",
"request": "launch"
}
]
}

2
firmware/Makefile Normal file
View File

@@ -0,0 +1,2 @@
release:
idf.py -B build-release -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release" fullclean build

View File

@@ -1,4 +1,4 @@
# Definiere die Quelldateien in einer Variable # Define the source files in a variable
set(SOURCE_FILES set(SOURCE_FILES
src/common/InactivityTracker.cpp src/common/InactivityTracker.cpp
src/common/Menu.cpp src/common/Menu.cpp

View File

@@ -6,6 +6,7 @@ if (DEFINED ENV{IDF_PATH})
PRIV_REQUIRES PRIV_REQUIRES
u8g2 u8g2
esp_event esp_event
esp_timer
persistence-manager persistence-manager
) )
return() return()

View File

@@ -1,3 +1,51 @@
#pragma once #pragma once
void led_status_init(); #include "driver/rmt_tx.h"
#include <stdint.h>
// Number of LEDs to be controlled
#define STATUS_LED_COUNT 3
// Possible lighting modes
typedef enum
{
LED_MODE_OFF,
LED_MODE_SOLID,
LED_MODE_BLINK
} led_mode_t;
// Structure for an RGB color
typedef struct
{
uint8_t r;
uint8_t g;
uint8_t b;
} rgb_t;
// This is the structure you pass from the outside to define a behavior
typedef struct
{
led_mode_t mode;
rgb_t color;
uint32_t on_time_ms = 0; // Only relevant for BLINK
uint32_t off_time_ms = 0; // Only relevant for BLINK
} led_behavior_t;
/**
* @brief Initializes the status manager and the LED strip.
*
* @param gpio_num GPIO where the data line of the LEDs is connected.
* @return esp_err_t ESP_OK on success.
*/
esp_err_t led_status_init(int gpio_num);
/**
* @brief Sets the lighting behavior for a single LED.
*
* This function is thread-safe.
*
* @param index Index of the LED (0 to STATUS_LED_COUNT - 1).
* @param behavior The structure with the desired behavior.
* @return esp_err_t ESP_OK on success, ESP_ERR_INVALID_ARG on invalid index.
*/
esp_err_t led_status_set_behavior(uint8_t index, led_behavior_t behavior);

View File

@@ -18,20 +18,26 @@ const char *TAG = "LED";
uint64_t wled_init(void) uint64_t wled_init(void)
{ {
led_strip_config_t strip_config = {.strip_gpio_num = CONFIG_WLED_DIN_PIN, led_strip_config_t strip_config = {
.strip_gpio_num = CONFIG_WLED_DIN_PIN,
.max_leds = 64, .max_leds = 64,
.led_model = LED_MODEL_WS2812, .led_model = LED_MODEL_WS2812,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
.flags = { .flags =
{
.invert_out = false, .invert_out = false,
}}; },
};
led_strip_rmt_config_t rmt_config = {.clk_src = RMT_CLK_SRC_DEFAULT, led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 0, .resolution_hz = 0,
.mem_block_symbols = 0, .mem_block_symbols = 0,
.flags = { .flags =
{
.with_dma = true, .with_dma = true,
}}; },
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
@@ -74,12 +80,12 @@ uint64_t send_event(uint32_t event, led_event_data_t *payload)
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
esp_err_t err = esp_event_post_to(loop_handle, // Event-Loop Handle esp_err_t err = esp_event_post_to(loop_handle, // Event loop handle
LED_EVENTS_BASE, // Event Base LED_EVENTS_BASE, // Event base
event, // Event ID (EVENT_LED_ON, EVENT_LED_OFF, etc.) event, // Event ID (EVENT_LED_ON, EVENT_LED_OFF, etc.)
payload, // Daten-Pointer payload, // Data pointer
sizeof(led_event_data_t), // Datengröße sizeof(led_event_data_t), // Data size
portMAX_DELAY // Wartezeit portMAX_DELAY // Wait time
); );
if (err != ESP_OK) if (err != ESP_OK)

View File

@@ -1,7 +1,145 @@
#include "led_status.h" #include "led_status.h"
void led_status_init() #include "esp_log.h"
#include "esp_timer.h" // For high-resolution timestamps
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "led_strip.h"
static const char *TAG = "LED_STATUS";
// Internal control structure for each LED
typedef struct
{ {
// This function is intentionally left empty for the native implementation. led_behavior_t behavior; // The desired behavior (target state)
// It serves as a placeholder to maintain compatibility with the HAL interface. uint64_t last_toggle_time_us; // Timestamp of the last toggle (in microseconds)
bool is_on_in_blink; // Current state in blink mode (actual state)
} led_control_t;
// --- Module variables ---
static led_strip_handle_t led_strip;
static led_control_t led_controls[STATUS_LED_COUNT];
static SemaphoreHandle_t mutex; // To protect the led_controls array
// The core: The task that controls the LEDs
static void led_status_task(void *pvParameters)
{
ESP_LOGI(TAG, "Led Status Task started.");
while (1)
{
uint64_t now_us = esp_timer_get_time();
// Take the mutex to safely access the control data
if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
{
for (int i = 0; i < STATUS_LED_COUNT; i++)
{
led_control_t *control = &led_controls[i];
switch (control->behavior.mode)
{
case LED_MODE_OFF:
led_strip_set_pixel(led_strip, i, 0, 0, 0);
break;
case LED_MODE_SOLID:
led_strip_set_pixel(led_strip, i, control->behavior.color.r, control->behavior.color.g,
control->behavior.color.b);
break;
case LED_MODE_BLINK: {
uint32_t duration_ms =
control->is_on_in_blink ? control->behavior.on_time_ms : control->behavior.off_time_ms;
if ((now_us - control->last_toggle_time_us) / 1000 >= duration_ms)
{
control->is_on_in_blink = !control->is_on_in_blink; // Toggle state
control->last_toggle_time_us = now_us; // Update timestamp
}
if (control->is_on_in_blink)
{
led_strip_set_pixel(led_strip, i, control->behavior.color.r, control->behavior.color.g,
control->behavior.color.b);
}
else
{
led_strip_set_pixel(led_strip, i, 0, 0, 0);
}
}
break;
}
}
// Release the mutex
xSemaphoreGive(mutex);
}
// Update the physical LED strip with the new values
led_strip_refresh(led_strip);
// Delay task for 20ms before the next iteration
vTaskDelay(pdMS_TO_TICKS(20));
}
}
// Initialization function
esp_err_t led_status_init(int gpio_num)
{
// LED strip configuration (e.g., for WS2812)
led_strip_config_t strip_config = {
.strip_gpio_num = gpio_num,
.max_leds = STATUS_LED_COUNT,
.led_model = LED_MODEL_WS2812,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRBW,
.flags =
{
.invert_out = false,
},
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10 * 1000 * 1000, // 10MHz
.mem_block_symbols = 0,
.flags =
{
.with_dma = false,
},
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
ESP_LOGI(TAG, "LED strip initialized.");
// Create mutex
mutex = xSemaphoreCreateMutex();
if (mutex == NULL)
{
ESP_LOGE(TAG, "Could not create mutex.");
return ESP_FAIL;
}
// Start task
xTaskCreate(led_status_task, "led_status_task", 2048, NULL, 5, NULL);
return ESP_OK;
}
// Function to set the behavior
esp_err_t led_status_set_behavior(uint8_t index, led_behavior_t behavior)
{
if (index >= STATUS_LED_COUNT)
{
return ESP_ERR_INVALID_ARG;
}
if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
{
led_controls[index].behavior = behavior;
// Reset internal state variables to start the new pattern cleanly
led_controls[index].is_on_in_blink = false;
led_controls[index].last_toggle_time_us = esp_timer_get_time();
xSemaphoreGive(mutex);
}
return ESP_OK;
} }

View File

@@ -1,7 +1,9 @@
#include "app_task.h" #include "app_task.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "led_manager.h" #include "led_manager.h"
#include "led_status.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -10,6 +12,22 @@ extern "C"
#endif #endif
void app_main(void) void app_main(void)
{ {
led_status_init(CONFIG_STATUS_WLED_PIN);
// LED 0: solid red
led_behavior_t led0_solid_red = {.mode = LED_MODE_SOLID, .color = {.r = 50, .g = 0, .b = 0}};
led_status_set_behavior(0, led0_solid_red);
// LED 1: fast blinking green (200ms an, 200ms aus)
led_behavior_t led1_blink_green = {
.mode = LED_MODE_BLINK, .color = {.r = 0, .g = 50, .b = 0}, .on_time_ms = 200, .off_time_ms = 200};
led_status_set_behavior(1, led1_blink_green);
// LED 2: slow blinking blue (1000ms an, 500ms aus)
led_behavior_t led2_blink_blue = {
.mode = LED_MODE_BLINK, .color = {.r = 0, .g = 0, .b = 50}, .on_time_ms = 1000, .off_time_ms = 500};
led_status_set_behavior(2, led2_blink_blue);
xTaskCreatePinnedToCore(app_task, "main_loop", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1); xTaskCreatePinnedToCore(app_task, "main_loop", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1);
wled_init(); wled_init();