#include "led_indicator.h" #include "led_strip_encoder.h" #include "device_config.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/rmt_tx.h" #include "esp_log.h" #include static const char *TAG = "LED_INDICATOR"; #define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000) // 10MHz resolution static rmt_channel_handle_t led_channel = NULL; static rmt_encoder_handle_t led_encoder = NULL; static TaskHandle_t led_task_handle = NULL; static led_state_t current_led_state = LED_OFF; static gpio_num_t led_gpio = GPIO_NUM_NC; typedef struct { uint8_t green; uint8_t red; uint8_t blue; } grb_t; static void led_write(grb_t color) { uint8_t led_data[3]; led_data[0] = color.green; led_data[1] = color.red; led_data[2] = color.blue; rmt_transmit_config_t tx_config = { .loop_count = 0, }; ESP_ERROR_CHECK(rmt_enable(led_channel)); ESP_ERROR_CHECK(rmt_transmit(led_channel, led_encoder, led_data, sizeof(led_data), &tx_config)); ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_channel, portMAX_DELAY)); ESP_ERROR_CHECK(rmt_disable(led_channel)); } static void led_indicator_task(void *arg) { grb_t color; uint32_t tick = 0; while (1) { switch (current_led_state) { case LED_OFF: color = (grb_t){0, 0, 0}; led_write(color); vTaskDelay(pdMS_TO_TICKS(1000)); break; case LED_PAIRING: // Azul piscando color = (tick % 2 == 0) ? (grb_t){0, 0, 50} : (grb_t){0, 0, 0}; led_write(color); vTaskDelay(pdMS_TO_TICKS(500)); tick++; break; case LED_CONNECTED: // Verde fixo color = (grb_t){30, 0, 0}; led_write(color); vTaskDelay(pdMS_TO_TICKS(1000)); break; case LED_DISCONNECTED: // Vermelho piscando color = (tick % 2 == 0) ? (grb_t){0, 50, 0} : (grb_t){0, 0, 0}; led_write(color); vTaskDelay(pdMS_TO_TICKS(300)); tick++; break; case LED_RELAY_ON: // Verde brilhante color = (grb_t){60, 0, 0}; led_write(color); vTaskDelay(pdMS_TO_TICKS(100)); break; case LED_RELAY_OFF: // Verde escuro color = (grb_t){10, 0, 0}; led_write(color); vTaskDelay(pdMS_TO_TICKS(100)); break; case LED_FACTORY_RESET: // Arco-íris rotativo { float hue = (tick % 360) * 3.14159f / 180.0f; color = (grb_t){ (uint8_t)(30 * (1 + sinf(hue))), (uint8_t)(30 * (1 + sinf(hue + 2.0943f))), (uint8_t)(30 * (1 + sinf(hue + 4.1888f))) }; led_write(color); vTaskDelay(pdMS_TO_TICKS(20)); tick++; } break; } } } esp_err_t led_indicator_init(gpio_num_t gpio_num) { esp_err_t ret; led_gpio = gpio_num; ESP_LOGI(TAG, "Inicializando LED RGB no GPIO %d", gpio_num); // Configurar canal RMT TX rmt_tx_channel_config_t tx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, .gpio_num = gpio_num, .mem_block_symbols = 64, .resolution_hz = LED_STRIP_RMT_RES_HZ, .trans_queue_depth = 4, }; ret = rmt_new_tx_channel(&tx_chan_config, &led_channel); if (ret != ESP_OK) { ESP_LOGE(TAG, "Falha ao criar canal RMT TX: %s", esp_err_to_name(ret)); return ret; } // Criar encoder customizado para LED strip led_strip_encoder_config_t encoder_config = { .resolution = LED_STRIP_RMT_RES_HZ, }; ret = rmt_new_led_strip_encoder(&encoder_config, &led_encoder); if (ret != ESP_OK) { ESP_LOGE(TAG, "Falha ao criar encoder LED: %s", esp_err_to_name(ret)); return ret; } // Criar task para controlar LED xTaskCreate(led_indicator_task, "led_indicator", 2048, NULL, 5, &led_task_handle); ESP_LOGI(TAG, "LED RGB inicializado com sucesso"); return ESP_OK; } void led_indicator_set_state(led_state_t state) { current_led_state = state; }