* Initial plan * Add GPIO_NUM_NC guards for LampController and SingleLed across all board files Boards crash when LAMP_GPIO or BUILTIN_LED_GPIO is set to GPIO_NUM_NC because LampController and SingleLed are instantiated unconditionally. Fix: Guard LampController with `if (LAMP_GPIO != GPIO_NUM_NC)` in InitializeTools() and guard SingleLed with `if (BUILTIN_LED_GPIO != GPIO_NUM_NC)` in GetLed(), falling back to NoLed when GPIO is not connected. Fixes the reported crash on bread-compact-wifi-lcd and hardens all similar boards. Co-authored-by: 78 <4488133+78@users.noreply.github.com> * Fix crash when LAMP_GPIO or BUILTIN_LED_GPIO is GPIO_NUM_NC (minimal 2-file fix) Instead of adding guards in every board file (36 files), fix the root cause in just 2 source files: 1. SingleLed constructor: replace assert(gpio != GPIO_NUM_NC) with graceful early return, leaving led_strip_ as nullptr (all methods already null-check it) 2. LampController constructor: add early return when gpio_num == GPIO_NUM_NC This fixes the crash on bread-compact-wifi-lcd and any other board where these GPIOs are set to GPIO_NUM_NC. Co-authored-by: 78 <4488133+78@users.noreply.github.com> * Remove esp_timer_delete from destructor to match original behavior Co-authored-by: 78 <4488133+78@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: 78 <4488133+78@users.noreply.github.com>
168 lines
4.3 KiB
C++
168 lines
4.3 KiB
C++
#include "single_led.h"
|
|
#include "application.h"
|
|
#include <esp_log.h>
|
|
|
|
#define TAG "SingleLed"
|
|
|
|
#define DEFAULT_BRIGHTNESS 4
|
|
#define HIGH_BRIGHTNESS 16
|
|
#define LOW_BRIGHTNESS 2
|
|
|
|
#define BLINK_INFINITE -1
|
|
|
|
|
|
SingleLed::SingleLed(gpio_num_t gpio) {
|
|
if (gpio == GPIO_NUM_NC) {
|
|
ESP_LOGW(TAG, "SingleLed initialized with GPIO_NUM_NC, LED will not function");
|
|
return;
|
|
}
|
|
|
|
led_strip_config_t strip_config = {};
|
|
strip_config.strip_gpio_num = gpio;
|
|
strip_config.max_leds = 1;
|
|
strip_config.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB;
|
|
strip_config.led_model = LED_MODEL_WS2812;
|
|
|
|
led_strip_rmt_config_t rmt_config = {};
|
|
rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz
|
|
|
|
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip_));
|
|
led_strip_clear(led_strip_);
|
|
|
|
esp_timer_create_args_t blink_timer_args = {
|
|
.callback = [](void *arg) {
|
|
auto led = static_cast<SingleLed*>(arg);
|
|
led->OnBlinkTimer();
|
|
},
|
|
.arg = this,
|
|
.dispatch_method = ESP_TIMER_TASK,
|
|
.name = "blink_timer",
|
|
.skip_unhandled_events = false,
|
|
};
|
|
ESP_ERROR_CHECK(esp_timer_create(&blink_timer_args, &blink_timer_));
|
|
}
|
|
|
|
SingleLed::~SingleLed() {
|
|
if (blink_timer_ != nullptr) {
|
|
esp_timer_stop(blink_timer_);
|
|
}
|
|
if (led_strip_ != nullptr) {
|
|
led_strip_del(led_strip_);
|
|
}
|
|
}
|
|
|
|
|
|
void SingleLed::SetColor(uint8_t r, uint8_t g, uint8_t b) {
|
|
r_ = r;
|
|
g_ = g;
|
|
b_ = b;
|
|
}
|
|
|
|
void SingleLed::TurnOn() {
|
|
if (led_strip_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
esp_timer_stop(blink_timer_);
|
|
led_strip_set_pixel(led_strip_, 0, r_, g_, b_);
|
|
led_strip_refresh(led_strip_);
|
|
}
|
|
|
|
void SingleLed::TurnOff() {
|
|
if (led_strip_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
esp_timer_stop(blink_timer_);
|
|
led_strip_clear(led_strip_);
|
|
}
|
|
|
|
void SingleLed::BlinkOnce() {
|
|
Blink(1, 100);
|
|
}
|
|
|
|
void SingleLed::Blink(int times, int interval_ms) {
|
|
StartBlinkTask(times, interval_ms);
|
|
}
|
|
|
|
void SingleLed::StartContinuousBlink(int interval_ms) {
|
|
StartBlinkTask(BLINK_INFINITE, interval_ms);
|
|
}
|
|
|
|
void SingleLed::StartBlinkTask(int times, int interval_ms) {
|
|
if (led_strip_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
esp_timer_stop(blink_timer_);
|
|
|
|
blink_counter_ = times * 2;
|
|
blink_interval_ms_ = interval_ms;
|
|
esp_timer_start_periodic(blink_timer_, interval_ms * 1000);
|
|
}
|
|
|
|
void SingleLed::OnBlinkTimer() {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
blink_counter_--;
|
|
if (blink_counter_ & 1) {
|
|
led_strip_set_pixel(led_strip_, 0, r_, g_, b_);
|
|
led_strip_refresh(led_strip_);
|
|
} else {
|
|
led_strip_clear(led_strip_);
|
|
|
|
if (blink_counter_ == 0) {
|
|
esp_timer_stop(blink_timer_);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SingleLed::OnStateChanged() {
|
|
auto& app = Application::GetInstance();
|
|
auto device_state = app.GetDeviceState();
|
|
switch (device_state) {
|
|
case kDeviceStateStarting:
|
|
SetColor(0, 0, DEFAULT_BRIGHTNESS);
|
|
StartContinuousBlink(100);
|
|
break;
|
|
case kDeviceStateWifiConfiguring:
|
|
SetColor(0, 0, DEFAULT_BRIGHTNESS);
|
|
StartContinuousBlink(500);
|
|
break;
|
|
case kDeviceStateIdle:
|
|
TurnOff();
|
|
break;
|
|
case kDeviceStateConnecting:
|
|
SetColor(0, 0, DEFAULT_BRIGHTNESS);
|
|
TurnOn();
|
|
break;
|
|
case kDeviceStateListening:
|
|
case kDeviceStateAudioTesting:
|
|
if (app.IsVoiceDetected()) {
|
|
SetColor(HIGH_BRIGHTNESS, 0, 0);
|
|
} else {
|
|
SetColor(LOW_BRIGHTNESS, 0, 0);
|
|
}
|
|
TurnOn();
|
|
break;
|
|
case kDeviceStateSpeaking:
|
|
SetColor(0, DEFAULT_BRIGHTNESS, 0);
|
|
TurnOn();
|
|
break;
|
|
case kDeviceStateUpgrading:
|
|
SetColor(0, DEFAULT_BRIGHTNESS, 0);
|
|
StartContinuousBlink(100);
|
|
break;
|
|
case kDeviceStateActivating:
|
|
SetColor(0, DEFAULT_BRIGHTNESS, 0);
|
|
StartContinuousBlink(500);
|
|
break;
|
|
default:
|
|
ESP_LOGW(TAG, "Unknown led strip event: %d", device_state);
|
|
return;
|
|
}
|
|
}
|