#include "led_indicator.h" #include "driver/gpio.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include #define LED_GPIO GPIO_NUM_2 static esp_timer_handle_t s_timer; static led_state_t s_state = LED_OFF; static int s_phase = 0; /* generic phase counter for multi-step patterns */ static void set_level(int lvl) { gpio_set_level(LED_GPIO, lvl); } static void IRAM_ATTR timer_cb(void *arg) { switch (s_state) { case LED_OFF: set_level(0); break; case LED_PROVISIONING: set_level(s_phase ^= 1); esp_timer_start_once(s_timer, 200 * 1000); break; case LED_CONNECTING: set_level(s_phase ^= 1); esp_timer_start_once(s_timer, 1000 * 1000); break; case LED_SCANNING: set_level(1); break; case LED_CALIBRATING: set_level(s_phase ^= 1); esp_timer_start_once(s_timer, 500 * 1000); break; case LED_SELECTED: { /* Triple flash: on/off/on/off/on/off, then 1s dark. s_phase 0-5 = flashes, 6 = pause */ static const uint64_t us[] = {100000,100000,100000,100000,100000,100000,1000000}; if (s_phase < 6) { set_level(s_phase % 2 == 0 ? 1 : 0); } else { set_level(0); } uint64_t delay = us[s_phase]; s_phase = (s_phase + 1) % 7; esp_timer_start_once(s_timer, delay); break; } case LED_ERROR: set_level(s_phase ^= 1); esp_timer_start_once(s_timer, 50 * 1000); break; } } void led_indicator_init(void) { gpio_config_t io = { .pin_bit_mask = (1ULL << LED_GPIO), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, }; gpio_config(&io); esp_timer_create_args_t args = { .callback = timer_cb, .name = "led", }; esp_timer_create(&args, &s_timer); } void led_indicator_set(led_state_t state) { esp_timer_stop(s_timer); s_state = state; s_phase = 0; if (state == LED_SCANNING) { set_level(1); } else if (state == LED_OFF) { set_level(0); } else { /* Kick off the timer-driven pattern immediately */ esp_timer_start_once(s_timer, 0); } }