/* * MTG RFID Companion - WS2812B Neopixel LED manager (RMT) */ #include "esp_log.h" #include "driver/rmt_tx.h" #include "driver/rmt_encoder.h" #include "hw_pins.h" #include "led_manager.h" static const char *TAG = "led"; static rmt_channel_handle_t s_tx_chan = NULL; static rmt_encoder_handle_t s_enc = NULL; esp_err_t led_manager_init(void) { if (s_tx_chan != NULL) { return ESP_OK; } rmt_tx_channel_config_t chan_cfg = { .gpio_num = HW_NEOPIXEL_GPIO, .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10 * 1000 * 1000, /* 100 ns per tick */ .mem_block_symbols = 64, .trans_queue_depth = 4, }; esp_err_t ret = rmt_new_tx_channel(&chan_cfg, &s_tx_chan); if (ret != ESP_OK) { ESP_LOGE(TAG, "rmt_new_tx_channel failed: %s", esp_err_to_name(ret)); return ret; } rmt_bytes_encoder_config_t enc_cfg = { .bit0 = { .duration0 = 4, /* T0H ~ 400 ns */ .level0 = 1, .duration1 = 8, /* T0L ~ 800 ns */ .level1 = 0, }, .bit1 = { .duration0 = 9, /* T1H ~ 900 ns */ .level0 = 1, .duration1 = 4, /* T1L ~ 400 ns */ .level1 = 0, }, }; ret = rmt_new_bytes_encoder(&enc_cfg, &s_enc); if (ret != ESP_OK) { ESP_LOGE(TAG, "rmt_new_bytes_encoder failed: %s", esp_err_to_name(ret)); return ret; } ret = rmt_enable(s_tx_chan); if (ret != ESP_OK) { ESP_LOGE(TAG, "rmt_enable failed: %s", esp_err_to_name(ret)); return ret; } ESP_LOGI(TAG, "WS2812B LED ready on GPIO %d", HW_NEOPIXEL_GPIO); return ESP_OK; } esp_err_t led_manager_set_color(uint8_t r, uint8_t g, uint8_t b) { if (s_tx_chan == NULL) { esp_err_t ret = led_manager_init(); if (ret != ESP_OK) { return ret; } } /* WS2812B expects GRB byte order */ uint8_t txbuf[3] = { g, r, b }; rmt_transmit_config_t tx_cfg = { .loop_count = 0, /* one-shot; LED latches and holds the level */ }; esp_err_t ret = rmt_transmit(s_tx_chan, s_enc, txbuf, sizeof(txbuf), &tx_cfg); if (ret != ESP_OK) { return ret; } return rmt_tx_wait_all_done(s_tx_chan, pdMS_TO_TICKS(50)); } esp_err_t led_manager_off(void) { return led_manager_set_color(0, 0, 0); }