#include "led_driver.h" #include "driver/rmt_tx.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include #define LED_PIN 18 // <-- CERTIFICA-TE disto #define RMT_RESOLUTION_HZ 10000000 // 10 MHz (1 tick = 0.1us) typedef struct { uint8_t r,g,b; } led_color_t; static led_color_t leds[LED_COUNT]; static rmt_channel_handle_t rmt_chan = NULL; static rmt_encoder_handle_t encoder = NULL; static rmt_transmit_config_t tx_config = { .loop_count = 0 }; static uint8_t global_brightness = 255; void led_set_global_brightness(uint8_t level) { global_brightness = level; } void led_driver_init(void) { gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); rmt_tx_channel_config_t chan_cfg = { .gpio_num = LED_PIN, .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = RMT_RESOLUTION_HZ, .mem_block_symbols = 64, .trans_queue_depth = 1, }; ESP_ERROR_CHECK(rmt_new_tx_channel(&chan_cfg, &rmt_chan)); ESP_ERROR_CHECK(rmt_enable(rmt_chan)); // WS2812B timings (EXATOS) rmt_bytes_encoder_config_t enc_cfg = { .bit0 = { .duration0 = 4, .level0 = 1, // 0.4us HIGH .duration1 = 9, .level1 = 0 // 0.9us LOW }, .bit1 = { .duration0 = 9, .level0 = 1, // 0.9us HIGH .duration1 = 4, .level1 = 0 // 0.4us LOW }, .flags.msb_first = 1 }; ESP_ERROR_CHECK(rmt_new_bytes_encoder(&enc_cfg, &encoder)); memset(leds, 0, sizeof(leds)); led_show(); } void led_set_pixel(int index, uint8_t r, uint8_t g, uint8_t b) { if (index < 0 || index >= LED_COUNT) return; leds[index].r = r; leds[index].g = g; leds[index].b = b; } void led_clear(void) { memset(leds, 0, sizeof(leds)); } static void hw_update(void) { uint8_t buf[LED_COUNT * 3]; // Previne divisão por zero uint8_t br = (global_brightness == 0) ? 1 : global_brightness; for (int i = 0; i < LED_COUNT; i++) { // Escala (r,g,b) com brilho global (0..255) uint8_t r = (leds[i].r * br) >> 8; uint8_t g = (leds[i].g * br) >> 8; uint8_t b = (leds[i].b * br) >> 8; // GRB buf[i*3 + 0] = g; buf[i*3 + 1] = r; buf[i*3 + 2] = b; } ESP_ERROR_CHECK(rmt_transmit(rmt_chan, encoder, buf, sizeof(buf), &tx_config)); rmt_tx_wait_all_done(rmt_chan, -1); esp_rom_delay_us(60); // reset 60us } void led_show(void) { hw_update(); } int led_get_count(void) { return LED_COUNT; } void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_ms) { int n = LED_COUNT; if (min_spins < 1) min_spins = 1; if (max_spins < min_spins) max_spins = min_spins; int extra = 0; if (max_spins > min_spins) extra = rand() % (max_spins - min_spins + 1); int total_steps = (min_spins + extra) * n + (target % n); int delay = base_delay_ms; for (int step = 0; step <= total_steps; step++) { int pos = step % n; for (int i = 0; i < n; i++) { if (i == pos) led_set_pixel(i, 0, 40, 0); // verde fraco no cursor else led_set_pixel(i, 0, 0, 0); } led_show(); if (step < total_steps / 3 && delay > 3) delay--; else if (step > (2 * total_steps) / 3) delay++; vTaskDelay(pdMS_TO_TICKS(delay)); } }