#include "led_manager.h" #include 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); }