LED_shit/main/led_driver.c
2025-11-23 18:15:56 +00:00

198 lines
4.7 KiB
C

#include "led_driver.h"
#include "driver/rmt_tx.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>
#include "premios.h"
#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;
// passos aleatórios entre min e max
int extra = 0;
if (max_spins > min_spins)
extra = rand() % (max_spins - min_spins + 1);
// número total de passos até ao LED final
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); // cursor verde
else
led_set_pixel(i, 0, 0, 0);
}
led_show();
// aceleração
if (step < total_steps / 3 && delay > 3)
delay--;
// desaceleração
else if (step > (2 * total_steps) / 3)
delay++;
vTaskDelay(pdMS_TO_TICKS(delay));
}
// =======================================
// POSIÇÃO FINAL
// =======================================
int pos_final = total_steps % n;
// LED final destacado
led_set_pixel(pos_final, 0, 60, 0);
led_show();
vTaskDelay(pdMS_TO_TICKS(200));
// =======================================
// PRÉMIO FINAL
// =======================================
uint16_t premio = premio_da_posicao(pos_final);
if (premio > 0) {
// piscar o LED que deu prémio
for (int k = 0; k < 8; k++) {
if (k & 1)
led_set_pixel(pos_final, 0, 0, 0);
else
led_set_pixel(pos_final, 0, 0, 60); // azul prémio
led_show();
vTaskDelay(pdMS_TO_TICKS(120));
}
} else {
// sem prémio → pisca vermelho suave
for (int k = 0; k < 4; k++) {
if (k & 1)
led_set_pixel(pos_final, 0, 0, 0);
else
led_set_pixel(pos_final, 40, 0, 0);
led_show();
vTaskDelay(pdMS_TO_TICKS(120));
}
}
// (aqui no futuro vais mandar MQTT do prémio)
}