Files
led_manager/led_manager.c
Andrey Aleksandrov 9491deaeba Add brightness setting
2026-02-06 17:35:50 +02:00

494 lines
12 KiB
C

#include "led_manager.h"
#include <string.h>
static const char *TAG = "LED_MANAGER";
static led_strip_handle_t led_strip = NULL;
static bool is_initialized = false;
// Blinking functionality
static TaskHandle_t blink_task_handle = NULL;
static bool is_blinking = false;
static uint16_t current_hue = 0;
static uint8_t current_sat = 0;
static uint8_t current_val = 0;
static bool has_color = false;
static uint32_t blink_rate_ms = 500;
static bool blink_state = false;
static uint8_t global_brightness = 255;
// Forward declaration for blink task
static void led_blink_task(void *pvParameter);
static void rgb_to_hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t *hue, uint8_t *sat, uint8_t *val);
static uint8_t apply_brightness(uint8_t value);
// RGB color definitions
static const struct
{
uint8_t red;
uint8_t green;
uint8_t blue;
const char *name;
led_color_t enum_val;
} rgb_colors[] = {
{255, 0, 0, "Red", LED_COLOR_RED},
{255, 100, 0, "Orange", LED_COLOR_ORANGE},
{255, 200, 0, "Yellow", LED_COLOR_YELLOW},
{0, 255, 0, "Green", LED_COLOR_GREEN},
{0, 0, 255, "Blue", LED_COLOR_BLUE},
};
// LED blink task
static void led_blink_task(void *pvParameter)
{
while (is_blinking)
{
if (blink_state)
{
// Turn on with current color
led_strip_set_pixel_hsv(led_strip, 0, current_hue, current_sat, apply_brightness(current_val));
led_strip_refresh(led_strip);
}
else
{
// Turn off
led_strip_set_pixel_hsv(led_strip, 0, current_hue, current_sat, 0);
led_strip_refresh(led_strip);
}
blink_state = !blink_state;
vTaskDelay(pdMS_TO_TICKS(blink_rate_ms));
}
// Clean exit - restore solid color
led_strip_set_pixel_hsv(led_strip, 0, current_hue, current_sat, apply_brightness(current_val));
led_strip_refresh(led_strip);
blink_task_handle = NULL;
vTaskDelete(NULL);
}
esp_err_t led_manager_init(int gpio_pin)
{
if (is_initialized)
{
ESP_LOGW(TAG, "LED manager already initialized");
return ESP_OK;
}
ESP_LOGI(TAG, "Initializing LED manager on GPIO %d", gpio_pin);
// Configure GPIO
gpio_reset_pin(gpio_pin);
gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
gpio_set_level(gpio_pin, 0);
// LED strip general configuration
led_strip_config_t strip_config = {
.strip_gpio_num = gpio_pin,
.max_leds = 1,
.led_model = LED_MODEL_WS2812,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
.flags = {
.invert_out = false,
}};
// LED strip RMT configuration
led_strip_rmt_config_t rmt_config = {
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
.rmt_channel = 0,
#else
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10 * 1000 * 1000, // 10MHz resolution
.mem_block_symbols = 64,
#endif
.flags = {
.with_dma = false,
}};
// Create the LED strip
esp_err_t ret = led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to create LED strip: %s", esp_err_to_name(ret));
return ret;
}
// Clear the LED strip
ret = led_strip_clear(led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to clear LED strip: %s", esp_err_to_name(ret));
led_strip_del(led_strip);
led_strip = NULL;
return ret;
}
is_initialized = true;
global_brightness = 255;
current_hue = 0;
current_sat = 0;
current_val = 0;
has_color = false;
ESP_LOGI(TAG, "LED manager initialized successfully");
return ESP_OK;
}
esp_err_t led_manager_set_color_by_name(const char *color_name, bool blink)
{
if (!is_initialized || led_strip == NULL)
{
ESP_LOGE(TAG, "LED manager not initialized");
return ESP_ERR_INVALID_STATE;
}
if (color_name == NULL)
{
ESP_LOGE(TAG, "Color name is NULL");
return ESP_ERR_INVALID_ARG;
}
int color_index = -1;
// Find the color index by name
for (int i = 0; i < sizeof(rgb_colors) / sizeof(rgb_colors[0]); i++)
{
if (strcmp(rgb_colors[i].name, color_name) == 0)
{
color_index = i;
break;
}
}
// If color not found, default to first color (Red)
if (color_index == -1)
{
ESP_LOGW(TAG, "Color '%s' not found, defaulting to Red", color_name);
color_index = 0;
}
// Stop any existing blinking
if (is_blinking)
{
led_manager_stop_blinking();
}
// Set the color
esp_err_t ret = led_manager_set_rgb(rgb_colors[color_index].red,
rgb_colors[color_index].green,
rgb_colors[color_index].blue);
if (ret != ESP_OK)
{
return ret;
}
if (blink)
{
// Start blinking
is_blinking = true;
blink_state = true;
if (blink_task_handle == NULL)
{
xTaskCreate(led_blink_task, "led_blink", 2048, NULL, 5, &blink_task_handle);
}
}
return ESP_OK;
}
esp_err_t led_manager_set_color(led_color_t color, bool blink)
{
if (!is_initialized || led_strip == NULL)
{
ESP_LOGE(TAG, "LED manager not initialized");
return ESP_ERR_INVALID_STATE;
}
// Find the color by enum value
for (int i = 0; i < sizeof(rgb_colors) / sizeof(rgb_colors[0]); i++)
{
if (rgb_colors[i].enum_val == color)
{
// Stop any existing blinking
if (is_blinking)
{
led_manager_stop_blinking();
}
esp_err_t ret = led_manager_set_rgb(rgb_colors[i].red,
rgb_colors[i].green,
rgb_colors[i].blue);
if (ret != ESP_OK)
{
return ret;
}
if (blink)
{
// Start blinking
is_blinking = true;
blink_state = true;
if (blink_task_handle == NULL)
{
xTaskCreate(led_blink_task, "led_blink", 2048, NULL, 5, &blink_task_handle);
}
}
return ESP_OK;
}
}
ESP_LOGW(TAG, "Invalid color enum %d, defaulting to Red", color);
return led_manager_set_color(LED_COLOR_RED, blink);
}
esp_err_t led_manager_set_rgb(uint8_t red, uint8_t green, uint8_t blue)
{
if (!is_initialized || led_strip == NULL)
{
ESP_LOGE(TAG, "LED manager not initialized");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "Setting LED color: R=%d, G=%d, B=%d", red, green, blue);
rgb_to_hsv(red, green, blue, &current_hue, &current_sat, &current_val);
has_color = true;
esp_err_t ret = led_strip_set_pixel_hsv(led_strip, 0, current_hue, current_sat, apply_brightness(current_val));
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set LED pixel: %s", esp_err_to_name(ret));
return ret;
}
// Refresh the strip to send data
ret = led_strip_refresh(led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to refresh LED strip: %s", esp_err_to_name(ret));
return ret;
}
return ESP_OK;
}
esp_err_t led_manager_set_brightness(uint8_t brightness)
{
global_brightness = brightness;
if (!is_initialized || led_strip == NULL || !has_color || is_blinking)
{
return ESP_OK;
}
esp_err_t ret = led_strip_set_pixel_hsv(led_strip, 0, current_hue, current_sat, apply_brightness(current_val));
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set LED pixel: %s", esp_err_to_name(ret));
return ret;
}
ret = led_strip_refresh(led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to refresh LED strip: %s", esp_err_to_name(ret));
return ret;
}
return ESP_OK;
}
esp_err_t led_manager_set_hsv(uint16_t hue, uint8_t saturation, uint8_t value)
{
if (!is_initialized || led_strip == NULL)
{
ESP_LOGE(TAG, "LED manager not initialized");
return ESP_ERR_INVALID_STATE;
}
if (hue > 360)
{
hue = (uint16_t)(hue % 360);
}
current_hue = hue;
current_sat = saturation;
current_val = value;
has_color = true;
if (is_blinking)
{
return ESP_OK;
}
esp_err_t ret = led_strip_set_pixel_hsv(led_strip, 0, current_hue, current_sat, apply_brightness(current_val));
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set LED pixel: %s", esp_err_to_name(ret));
return ret;
}
ret = led_strip_refresh(led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to refresh LED strip: %s", esp_err_to_name(ret));
return ret;
}
return ESP_OK;
}
esp_err_t led_manager_stop_blinking(void)
{
if (is_blinking)
{
is_blinking = false;
// Task will clean itself up
vTaskDelay(pdMS_TO_TICKS(100)); // Allow task to finish
}
return ESP_OK;
}
esp_err_t led_manager_set_blink_rate(uint32_t rate_ms)
{
if (rate_ms < 50)
{
ESP_LOGW(TAG, "Blink rate too fast, minimum is 50ms");
rate_ms = 50;
}
blink_rate_ms = rate_ms;
ESP_LOGI(TAG, "Blink rate set to %lu ms", rate_ms);
return ESP_OK;
}
esp_err_t led_manager_clear(void)
{
if (!is_initialized || led_strip == NULL)
{
ESP_LOGE(TAG, "LED manager not initialized");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "Clearing LED");
esp_err_t ret = led_strip_clear(led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to clear LED strip: %s", esp_err_to_name(ret));
return ret;
}
has_color = false;
current_hue = 0;
current_sat = 0;
current_val = 0;
return ESP_OK;
}
esp_err_t led_manager_deinit(void)
{
if (!is_initialized)
{
ESP_LOGW(TAG, "LED manager not initialized");
return ESP_OK;
}
ESP_LOGI(TAG, "Deinitializing LED manager");
// Stop blinking task if running
if (blink_task_handle != NULL)
{
is_blinking = false;
vTaskDelay(pdMS_TO_TICKS(100)); // Allow task to finish
if (blink_task_handle != NULL)
{
vTaskDelete(blink_task_handle);
blink_task_handle = NULL;
}
}
if (led_strip != NULL)
{
led_strip_clear(led_strip);
esp_err_t ret = led_strip_del(led_strip);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to delete LED strip: %s", esp_err_to_name(ret));
}
led_strip = NULL;
}
is_initialized = false;
has_color = false;
ESP_LOGI(TAG, "LED manager deinitialized");
return ESP_OK;
}
static void rgb_to_hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t *hue, uint8_t *sat, uint8_t *val)
{
uint8_t max = red;
uint8_t min = red;
if (green > max)
{
max = green;
}
if (blue > max)
{
max = blue;
}
if (green < min)
{
min = green;
}
if (blue < min)
{
min = blue;
}
uint8_t delta = max - min;
*val = max;
if (max == 0)
{
*sat = 0;
*hue = 0;
return;
}
*sat = (uint8_t)((uint16_t)delta * 255 / max);
if (delta == 0)
{
*hue = 0;
return;
}
float h;
if (max == red)
{
h = 60.0f * ((float)(green - blue) / (float)delta);
}
else if (max == green)
{
h = 60.0f * (2.0f + (float)(blue - red) / (float)delta);
}
else
{
h = 60.0f * (4.0f + (float)(red - green) / (float)delta);
}
if (h < 0.0f)
{
h += 360.0f;
}
*hue = (uint16_t)(h + 0.5f);
}
static uint8_t apply_brightness(uint8_t value)
{
return (uint8_t)((uint16_t)value * global_brightness / 255);
}