198 lines
4.7 KiB
C
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)
|
|
}
|