494 lines
12 KiB
C
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, ¤t_hue, ¤t_sat, ¤t_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);
|
|
} |