LED_shit/main/led_driver.c
2025-11-04 21:33:28 +00:00

148 lines
4.5 KiB
C

#include "led_driver.h"
#include "driver/rmt_tx.h"
#include "led_strip_encoder.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_random.h"
#include <string.h>
#include "esp_rom_sys.h"
static const char *TAG = "LED";
static bool led_ready = false; // 🚦 flag de inicialização
static rmt_channel_handle_t led_chan = NULL;
static rmt_encoder_handle_t led_enc = NULL;
static uint8_t led_pixels[LED_COUNT * 3];
// --- Conversão HSV → RGB ---
static void hsv2rgb(uint32_t h, uint32_t s, uint32_t v,
uint8_t *r, uint8_t *g, uint8_t *b)
{
h %= 360;
uint32_t rgb_max = v * 255 / 100;
uint32_t rgb_min = rgb_max * (100 - s) / 100;
uint32_t i = h / 60, diff = h % 60;
uint32_t adj = (rgb_max - rgb_min) * diff / 60;
switch (i) {
case 0: *r = rgb_max; *g = rgb_min + adj; *b = rgb_min; break;
case 1: *r = rgb_max - adj; *g = rgb_max; *b = rgb_min; break;
case 2: *r = rgb_min; *g = rgb_max; *b = rgb_min + adj; break;
case 3: *r = rgb_min; *g = rgb_max - adj; *b = rgb_max; break;
case 4: *r = rgb_min + adj; *g = rgb_min; *b = rgb_max; break;
default:*r = rgb_max; *g = rgb_min; *b = rgb_max - adj; break;
}
}
// --- Inicialização ---
esp_err_t led_init(void)
{
ESP_LOGI(TAG, "Inicializando LEDs no GPIO%d (%d LEDs)", LED_PIN, LED_COUNT);
rmt_tx_channel_config_t tx_cfg = {
.gpio_num = LED_PIN,
.clk_src = RMT_CLK_SRC_DEFAULT,
.mem_block_symbols = 64,
.resolution_hz = LED_RES_HZ,
.trans_queue_depth = 4,
};
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_cfg, &led_chan));
led_strip_encoder_config_t enc_cfg = {.resolution = LED_RES_HZ};
ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&enc_cfg, &led_enc));
ESP_ERROR_CHECK(rmt_enable(led_chan));
memset(led_pixels, 0, sizeof(led_pixels));
led_ready = true; // ✅ marca como pronto
led_show(); // apaga tudo ao iniciar
return ESP_OK;
}
// --- Apagar todos os LEDs ---
esp_err_t led_clear(void)
{
if (!led_ready) return ESP_ERR_INVALID_STATE;
memset(led_pixels, 0, sizeof(led_pixels));
return led_show();
}
// --- Definir cor individual ---
esp_err_t led_set(uint16_t index, uint8_t r, uint8_t g, uint8_t b)
{
if (index >= LED_COUNT) return ESP_ERR_INVALID_ARG;
led_pixels[index * 3 + 0] = g; // WS2812 usa ordem GRB
led_pixels[index * 3 + 1] = r;
led_pixels[index * 3 + 2] = b;
return ESP_OK;
}
// --- Enviar buffer para o anel ---
esp_err_t led_show(void)
{
if (!led_ready || !led_chan || !led_enc) {
ESP_LOGW(TAG, "⚠️ led_show() chamado antes da inicialização — ignorado");
return ESP_ERR_INVALID_STATE;
}
rmt_transmit_config_t tx_cfg = {.loop_count = 0};
esp_err_t err = rmt_transmit(led_chan, led_enc,
led_pixels, sizeof(led_pixels), &tx_cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "❌ rmt_transmit falhou (%s)", esp_err_to_name(err));
return err;
}
err = rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
if (err != ESP_OK) {
ESP_LOGE(TAG, "❌ rmt_tx_wait_all_done falhou (%s)", esp_err_to_name(err));
return err;
}
return ESP_OK;
}
// --- Animação de rotação até posição alvo ---
void led_spin_to(uint16_t target, uint16_t rounds, uint16_t delay_start, uint16_t delay_end)
{
if (!led_ready) return;
uint32_t total_steps = rounds * LED_COUNT + target;
for (uint32_t i = 0; i < total_steps; i++) {
uint16_t pos = i % LED_COUNT;
// Limpa e acende o LED atual
led_clear();
led_set(pos, 255, 150, 0);
led_show();
// Calcula delay progressivo (aceleração -> desaceleração)
uint32_t delay = delay_start + ((delay_end - delay_start) * i) / total_steps;
vTaskDelay(pdMS_TO_TICKS(delay));
}
// Flash final
for (int j = 0; j < 3; j++) {
led_clear();
led_show();
vTaskDelay(pdMS_TO_TICKS(80));
for (int k = 0; k < LED_COUNT; k++)
led_set(k, 255, 200, 50);
led_show();
vTaskDelay(pdMS_TO_TICKS(80));
}
}
// --- Animação idle (arco-íris lento) ---
void led_idle_animation(void)
{
if (!led_ready) return;
static uint16_t hue = 0;
for (int i = 0; i < LED_COUNT; i++) {
uint8_t r, g, b;
hsv2rgb((hue + i * 6) % 360, 100, 10, &r, &g, &b);
led_set(i, r, g, b);
}
led_show();
hue = (hue + 2) % 360;
}