diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 901cad05..3745605d 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -3,6 +3,9 @@ set(SOURCES "audio_codecs/audio_codec.cc" "audio_codecs/box_audio_codec.cc" "audio_codecs/es8311_audio_codec.cc" "audio_codecs/cores3_audio_codec.cc" + "led_strip/single_led.cc" + "led_strip/multiple_led.cc" + "led_strip/led_strip_wrapper.cc" "display/display.cc" "display/no_display.cc" "display/st7789_display.cc" diff --git a/main/application.cc b/main/application.cc index 3119e000..80e0daba 100644 --- a/main/application.cc +++ b/main/application.cc @@ -186,9 +186,8 @@ void Application::StopListening() { void Application::Start() { auto& board = Board::GetInstance(); - auto builtin_led = board.GetBuiltinLed(); - builtin_led->SetBlue(); - builtin_led->StartContinuousBlink(100); + auto led_strip = board.GetLedStrip(); + led_strip->LightOn(kStartup); /* Setup the display */ auto display = board.GetDisplay(); @@ -246,14 +245,13 @@ void Application::Start() { wake_word_detect_.Initialize(codec->input_channels(), codec->input_reference()); wake_word_detect_.OnVadStateChange([this](bool speaking) { Schedule([this, speaking]() { - auto builtin_led = Board::GetInstance().GetBuiltinLed(); + auto led_strip = Board::GetInstance().GetLedStrip(); if (chat_state_ == kChatStateListening) { if (speaking) { - builtin_led->SetRed(HIGH_BRIGHTNESS); + led_strip->LightOn(kListeningAndSpeaking); } else { - builtin_led->SetRed(LOW_BRIGHTNESS); + led_strip->LightOn(kListening); } - builtin_led->TurnOn(); } }); }); @@ -382,8 +380,7 @@ void Application::Start() { // Blink the LED to indicate the device is running display->SetStatus("待命"); - builtin_led->SetGreen(); - builtin_led->BlinkOnce(); + led_strip->LightOn(kStandby); SetChatState(kChatStateIdle); } @@ -545,11 +542,11 @@ void Application::SetChatState(ChatState state) { background_task_.WaitForCompletion(); auto display = Board::GetInstance().GetDisplay(); - auto builtin_led = Board::GetInstance().GetBuiltinLed(); + auto led_strip = Board::GetInstance().GetLedStrip(); switch (state) { case kChatStateUnknown: case kChatStateIdle: - builtin_led->TurnOff(); + led_strip->LightOff(); display->SetStatus("待命"); display->SetEmotion("neutral"); #ifdef CONFIG_IDF_TARGET_ESP32S3 @@ -557,13 +554,11 @@ void Application::SetChatState(ChatState state) { #endif break; case kChatStateConnecting: - builtin_led->SetBlue(); - builtin_led->TurnOn(); + led_strip->LightOn(kConnecting); display->SetStatus("连接中..."); break; case kChatStateListening: - builtin_led->SetRed(); - builtin_led->TurnOn(); + led_strip->LightOn(kListening); display->SetStatus("聆听中..."); display->SetEmotion("neutral"); ResetDecoder(); @@ -574,8 +569,7 @@ void Application::SetChatState(ChatState state) { UpdateIotStates(); break; case kChatStateSpeaking: - builtin_led->SetGreen(); - builtin_led->TurnOn(); + led_strip->LightOn(kSpeaking); display->SetStatus("说话中..."); ResetDecoder(); #if CONFIG_IDF_TARGET_ESP32S3 @@ -583,8 +577,7 @@ void Application::SetChatState(ChatState state) { #endif break; case kChatStateUpgrading: - builtin_led->SetGreen(); - builtin_led->StartContinuousBlink(100); + led_strip->LightOn(kUpgrading); break; default: ESP_LOGE(TAG, "Invalid chat state: %d", chat_state_); diff --git a/main/boards/bread-compact-ml307/compact_ml307_board.cc b/main/boards/bread-compact-ml307/compact_ml307_board.cc index bca70e87..604871b6 100644 --- a/main/boards/bread-compact-ml307/compact_ml307_board.cc +++ b/main/boards/bread-compact-ml307/compact_ml307_board.cc @@ -4,9 +4,9 @@ #include "system_reset.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "iot/thing_manager.h" +#include "led_strip/single_led.h" #include #include @@ -102,9 +102,9 @@ public: InitializeIot(); } - virtual Led* GetBuiltinLed() override { - static Led led(BUILTIN_LED_GPIO); - return &led; + virtual LedStripWrapper* GetLedStrip() override { + static SingleLed led_strip(BUILTIN_LED_GPIO); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/boards/bread-compact-wifi/compact_wifi_board.cc b/main/boards/bread-compact-wifi/compact_wifi_board.cc index 5d9ac8d8..38b2fe15 100644 --- a/main/boards/bread-compact-wifi/compact_wifi_board.cc +++ b/main/boards/bread-compact-wifi/compact_wifi_board.cc @@ -4,9 +4,9 @@ #include "system_reset.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "iot/thing_manager.h" +#include "led_strip/single_led.h" #include #include @@ -107,9 +107,9 @@ public: InitializeIot(); } - virtual Led* GetBuiltinLed() override { - static Led led(BUILTIN_LED_GPIO); - return &led; + virtual LedStripWrapper* GetLedStrip() override { + static SingleLed led_strip(BUILTIN_LED_GPIO); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/boards/common/board.h b/main/boards/common/board.h index 66de827d..6a4bd43d 100644 --- a/main/boards/common/board.h +++ b/main/boards/common/board.h @@ -7,7 +7,7 @@ #include #include -#include "led.h" +#include "led_strip/led_strip_wrapper.h" void* create_board(); class AudioCodec; @@ -32,7 +32,7 @@ public: virtual void StartNetwork() = 0; virtual ~Board() = default; - virtual Led* GetBuiltinLed() = 0; + virtual LedStripWrapper* GetLedStrip() = 0; virtual AudioCodec* GetAudioCodec() = 0; virtual Display* GetDisplay(); virtual Http* CreateHttp() = 0; diff --git a/main/boards/common/led.cc b/main/boards/common/led.cc index e3640af1..61ac0285 100644 --- a/main/boards/common/led.cc +++ b/main/boards/common/led.cc @@ -6,41 +6,29 @@ #define TAG "Led" -Led::Led(gpio_num_t gpio) { +Led::Led(gpio_num_t gpio, uint8_t max_leds) { if (gpio == GPIO_NUM_NC) { ESP_LOGI(TAG, "Builtin LED not connected"); return; } - + led_strip_config_t strip_config = {}; strip_config.strip_gpio_num = gpio; - strip_config.max_leds = 1; + strip_config.max_leds = max_leds; strip_config.led_pixel_format = LED_PIXEL_FORMAT_GRB; strip_config.led_model = LED_MODEL_WS2812; led_strip_rmt_config_t rmt_config = {}; rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz + max_leds_ = max_leds; ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip_)); + led_strip_clear(led_strip_); - SetGrey(); - - esp_timer_create_args_t blink_timer_args = { - .callback = [](void *arg) { - auto led = static_cast(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_)); } Led::~Led() { - esp_timer_stop(blink_timer_); if (led_strip_ != nullptr) { led_strip_del(led_strip_); } @@ -58,8 +46,9 @@ void Led::TurnOn() { } std::lock_guard lock(mutex_); - esp_timer_stop(blink_timer_); - led_strip_set_pixel(led_strip_, 0, r_, g_, b_); + for (int i = 0; i < max_leds_; i++) { + led_strip_set_pixel(led_strip_, i, r_, g_, b_); + } led_strip_refresh(led_strip_); } @@ -69,47 +58,5 @@ void Led::TurnOff() { } std::lock_guard lock(mutex_); - esp_timer_stop(blink_timer_); led_strip_clear(led_strip_); } - -void Led::BlinkOnce() { - Blink(1, 100); -} - -void Led::Blink(int times, int interval_ms) { - StartBlinkTask(times, interval_ms); -} - -void Led::StartContinuousBlink(int interval_ms) { - StartBlinkTask(BLINK_INFINITE, interval_ms); -} - -void Led::StartBlinkTask(int times, int interval_ms) { - if (led_strip_ == nullptr) { - return; - } - - std::lock_guard lock(mutex_); - esp_timer_stop(blink_timer_); - - led_strip_clear(led_strip_); - blink_counter_ = times * 2; - blink_interval_ms_ = interval_ms; - esp_timer_start_periodic(blink_timer_, interval_ms * 1000); -} - -void Led::OnBlinkTimer() { - std::lock_guard 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_); - } - } -} diff --git a/main/boards/common/led.h b/main/boards/common/led.h index e0fe334f..8cd1858d 100644 --- a/main/boards/common/led.h +++ b/main/boards/common/led.h @@ -6,9 +6,6 @@ #include #include -#define BLINK_INFINITE -1 -#define BLINK_TASK_STOPPED_BIT BIT0 -#define BLINK_TASK_RUNNING_BIT BIT1 #define DEFAULT_BRIGHTNESS 4 #define HIGH_BRIGHTNESS 16 @@ -16,12 +13,12 @@ class Led { public: - Led(gpio_num_t gpio); + Led(gpio_num_t gpio, uint8_t max_leds); ~Led(); - void BlinkOnce(); - void Blink(int times, int interval_ms); - void StartContinuousBlink(int interval_ms); + led_strip_handle_t led_strip() { return led_strip_; } + uint8_t max_leds() { return max_leds_; } + void TurnOn(); void TurnOff(); void SetColor(uint8_t r, uint8_t g, uint8_t b); @@ -30,18 +27,12 @@ public: void SetRed(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(brightness, 0, 0); } void SetGreen(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(0, brightness, 0); } void SetBlue(uint8_t brightness = DEFAULT_BRIGHTNESS) { SetColor(0, 0, brightness); } - + private: std::mutex mutex_; - TaskHandle_t blink_task_ = nullptr; + uint8_t max_leds_ = -1; led_strip_handle_t led_strip_ = nullptr; uint8_t r_ = 0, g_ = 0, b_ = 0; - int blink_counter_ = 0; - int blink_interval_ms_ = 0; - esp_timer_handle_t blink_timer_ = nullptr; - - void StartBlinkTask(int times, int interval_ms); - void OnBlinkTimer(); }; #endif // _LED_H_ diff --git a/main/boards/common/wifi_board.cc b/main/boards/common/wifi_board.cc index 31989043..27deca28 100644 --- a/main/boards/common/wifi_board.cc +++ b/main/boards/common/wifi_board.cc @@ -38,15 +38,14 @@ static std::string rssi_to_string(int rssi) { void WifiBoard::StartNetwork() { auto& application = Application::GetInstance(); auto display = Board::GetInstance().GetDisplay(); - auto builtin_led = Board::GetInstance().GetBuiltinLed(); + auto led_strip = Board::GetInstance().GetLedStrip(); // Try to connect to WiFi, if failed, launch the WiFi configuration AP auto& wifi_station = WifiStation::GetInstance(); display->SetStatus(std::string("正在连接 ") + wifi_station.GetSsid()); wifi_station.Start(); if (!wifi_station.IsConnected()) { - builtin_led->SetBlue(); - builtin_led->Blink(1000, 500); + led_strip->LightOn(kConnecting); auto& wifi_ap = WifiConfigurationAp::GetInstance(); wifi_ap.SetSsidPrefix("Xiaozhi"); wifi_ap.Start(); diff --git a/main/boards/esp-box-3/esp_box3_board.cc b/main/boards/esp-box-3/esp_box3_board.cc index 7df36c19..c47c620f 100644 --- a/main/boards/esp-box-3/esp_box3_board.cc +++ b/main/boards/esp-box-3/esp_box3_board.cc @@ -5,9 +5,9 @@ #include "font_awesome_symbols.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "iot/thing_manager.h" +#include "led_strip/single_led.h" #include #include @@ -214,10 +214,10 @@ public: InitializeButtons(); InitializeIot(); } - - virtual Led* GetBuiltinLed() override { - static Led led(GPIO_NUM_NC); - return &led; + + virtual LedStripWrapper* GetLedStrip() override { + static SingleLed led_strip(GPIO_NUM_NC); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/boards/kevin-box-1/kevin_box_board.cc b/main/boards/kevin-box-1/kevin_box_board.cc index 86d9a44c..ba79f4f7 100644 --- a/main/boards/kevin-box-1/kevin_box_board.cc +++ b/main/boards/kevin-box-1/kevin_box_board.cc @@ -3,9 +3,9 @@ #include "display/ssd1306_display.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "iot/thing_manager.h" +#include "led_strip/single_led.h" #include #include @@ -135,10 +135,10 @@ public: InitializeButtons(); InitializeIot(); } - - virtual Led* GetBuiltinLed() override { - static Led led(BUILTIN_LED_GPIO); - return &led; + + virtual LedStripWrapper* GetLedStrip() override { + static SingleLed led_strip(BUILTIN_LED_GPIO); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/boards/kevin-box-2/kevin_box_board.cc b/main/boards/kevin-box-2/kevin_box_board.cc index bddb0bf8..e65be333 100644 --- a/main/boards/kevin-box-2/kevin_box_board.cc +++ b/main/boards/kevin-box-2/kevin_box_board.cc @@ -3,10 +3,10 @@ #include "display/ssd1306_display.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "axp2101.h" #include "iot/thing_manager.h" +#include "led_strip/single_led.h" #include #include @@ -179,10 +179,10 @@ public: InitializePowerSaveTimer(); InitializeIot(); } - - virtual Led* GetBuiltinLed() override { - static Led led(BUILTIN_LED_GPIO); - return &led; + + virtual LedStripWrapper* GetLedStrip() override { + static SingleLed led_strip(BUILTIN_LED_GPIO); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/boards/kevin-c3/config.h b/main/boards/kevin-c3/config.h index a8034e8e..0850d250 100644 --- a/main/boards/kevin-c3/config.h +++ b/main/boards/kevin-c3/config.h @@ -17,7 +17,7 @@ #define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_1 #define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR -#define BUILTIN_LED_GPIO GPIO_NUM_2 +#define BUILTIN_LED_GPIO GPIO_NUM_5 #define BOOT_BUTTON_GPIO GPIO_NUM_9 diff --git a/main/boards/kevin-c3/kevin_box_board.cc b/main/boards/kevin-c3/kevin_box_board.cc index c51b185f..fac28051 100644 --- a/main/boards/kevin-c3/kevin_box_board.cc +++ b/main/boards/kevin-c3/kevin_box_board.cc @@ -2,9 +2,9 @@ #include "audio_codecs/es8311_audio_codec.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "iot/thing_manager.h" +#include "led_strip/multiple_led.h" #include #include @@ -60,15 +60,15 @@ public: KevinBoxBoard() : boot_button_(BOOT_BUTTON_GPIO) { // 把 ESP32C3 的 VDD SPI 引脚作为普通 GPIO 口使用 esp_efuse_write_field_bit(ESP_EFUSE_VDD_SPI_AS_GPIO); - + InitializeCodecI2c(); InitializeButtons(); InitializeIot(); } - virtual Led* GetBuiltinLed() override { - static Led led(BUILTIN_LED_GPIO); - return &led; + virtual LedStripWrapper* GetLedStrip() override { + static MultipleLed led_strip(BUILTIN_LED_GPIO, 8); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/boards/lichuang-dev/lichuang_dev_board.cc b/main/boards/lichuang-dev/lichuang_dev_board.cc index e2799039..257fee0a 100644 --- a/main/boards/lichuang-dev/lichuang_dev_board.cc +++ b/main/boards/lichuang-dev/lichuang_dev_board.cc @@ -3,10 +3,10 @@ #include "display/st7789_display.h" #include "application.h" #include "button.h" -#include "led.h" #include "config.h" #include "i2c_device.h" #include "iot/thing_manager.h" +#include "led_strip/single_led.h" #include #include @@ -135,9 +135,9 @@ public: InitializeIot(); } - virtual Led* GetBuiltinLed() override { - static Led led(GPIO_NUM_NC); - return &led; + virtual LedStripWrapper* GetLedStrip() override { + static SingleLed led_strip(GPIO_NUM_NC); + return &led_strip; } virtual AudioCodec* GetAudioCodec() override { diff --git a/main/led_strip/led_strip_wrapper.cc b/main/led_strip/led_strip_wrapper.cc new file mode 100644 index 00000000..d631445d --- /dev/null +++ b/main/led_strip/led_strip_wrapper.cc @@ -0,0 +1,219 @@ +#include "led_strip_wrapper.h" +#include "board.h" + +#include +#include +#include + +#define TAG "LedStripWrapper" + +LedStripWrapper::LedStripWrapper(gpio_num_t gpio, uint8_t max_leds) { + if (gpio == GPIO_NUM_NC) { + ESP_LOGI(TAG, "Builtin LED not connected"); + return; + } + + led_ = new Led(gpio, max_leds); + + esp_timer_create_args_t led_strip_timer_args = { + .callback = [](void *arg) { + auto light = static_cast(arg); + light->OnBlinkTimer(); + }, + .arg = this, + .dispatch_method = ESP_TIMER_TASK, + .name = "Led Strip Timer", + .skip_unhandled_events = false, + }; + ESP_ERROR_CHECK(esp_timer_create(&led_strip_timer_args, &led_strip_timer_)); +} + +LedStripWrapper::~LedStripWrapper() { + if (led_strip_timer_ != nullptr) { + esp_timer_delete(led_strip_timer_); + } + if (led_ != nullptr) { + delete led_; + } +} + +void LedStripWrapper::OnBlinkTimer() { + std::lock_guard lock(mutex_); + counter_--; + timer_callback_(); +} + +void LedStripWrapper::SetLedBasicColor(LedBasicColor color, uint8_t brightness) { + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + switch (color) { + case kLedColorWhite: + led_->SetWhite(brightness); + break; + case kLedColorGrey: + led_->SetGrey(brightness); + break; + case kLedColorRed: + led_->SetRed(brightness); + break; + case kLedColorGreen: + led_->SetGreen(brightness); + break; + case kLedColorBlue: + led_->SetBlue(brightness); + break; + } +} + +void LedStripWrapper::SetLedStripBasicColor(uint8_t index, LedBasicColor color, uint8_t brightness) { + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + if (index >= led_->max_leds()) { + ESP_LOGE(TAG, "Invalid led index: %d", index); + return; + } + + switch (color) { + case kLedColorWhite: + led_strip_set_pixel(led_->led_strip(), index, brightness, brightness, brightness); + break; + case kLedColorGrey: + led_strip_set_pixel(led_->led_strip(), index, brightness, brightness, brightness); + break; + case kLedColorRed: + led_strip_set_pixel(led_->led_strip(), index, brightness, 0, 0); + break; + case kLedColorGreen: + led_strip_set_pixel(led_->led_strip(), index, 0, brightness, 0); + break; + case kLedColorBlue: + led_strip_set_pixel(led_->led_strip(), index, 0, 0, brightness); + break; + } +} + +void LedStripWrapper::StartBlinkTask(uint32_t times, uint32_t interval_ms) { + std::lock_guard lock(mutex_); + + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + esp_timer_stop(led_strip_timer_); + counter_ = times * 2; + timer_callback_ = [this]() { + if (counter_ & 1) { + led_->TurnOn(); + } else { + led_->TurnOff(); + if (counter_ == 0) { + esp_timer_stop(led_strip_timer_); + } + } + }; + esp_timer_start_periodic(led_strip_timer_, interval_ms * 1000); +} + +void LedStripWrapper::BlinkOnce(LedBasicColor color, uint8_t brightness) { + Blink(color, brightness, 1, 100); +} + +void LedStripWrapper::Blink(LedBasicColor color, uint32_t times, uint32_t interval_ms, uint8_t brightness) { + SetLedBasicColor(color, brightness); + StartBlinkTask(times, interval_ms); +} + +void LedStripWrapper::ContinuousBlink(LedBasicColor color, uint32_t interval_ms, uint8_t brightness) { + SetLedBasicColor(color, brightness); + StartBlinkTask(COUNTER_INFINITE, interval_ms); +} + +void LedStripWrapper::StaticLight(LedBasicColor color, uint8_t brightness) { + std::lock_guard lock(mutex_); + + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + SetLedBasicColor(color, brightness); + esp_timer_stop(led_strip_timer_); + led_->TurnOn(); +} + +void LedStripWrapper::ChasingLight(LedBasicColor base_color, LedBasicColor color, uint32_t interval_ms, uint8_t brightness) { + std::lock_guard lock(mutex_); + + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + esp_timer_stop(led_strip_timer_); + counter_ = COUNTER_INFINITE; + timer_callback_ = [this, base_color, color, brightness]() { + auto index = counter_ % led_->max_leds(); + for (uint8_t i = 0; i < led_->max_leds(); i++) { + if (i == index || i == (index + 1) % led_->max_leds()) { + SetLedStripBasicColor(i, color, brightness); + } else { + SetLedStripBasicColor(i, base_color, LOW_BRIGHTNESS); + } + } + led_strip_refresh(led_->led_strip()); + }; + esp_timer_start_periodic(led_strip_timer_, interval_ms * 1000); +} + +void LedStripWrapper::BreathLight(LedBasicColor color, uint32_t interval_ms) { + std::lock_guard lock(mutex_); + + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + esp_timer_stop(led_strip_timer_); + counter_ = COUNTER_INFINITE; + timer_callback_ = [this, color]() { + static bool increase = true; + static uint32_t brightness = LOW_BRIGHTNESS; + + for (uint8_t i = 0; i < led_->max_leds(); i++) { + SetLedStripBasicColor(i, color, brightness); + } + led_strip_refresh(led_->led_strip()); + + if (brightness == HIGH_BRIGHTNESS) { + increase = false; + } else if (brightness == LOW_BRIGHTNESS) { + increase = true; + } + + if (increase) { + brightness += 2; + } else { + brightness -= 2; + } + }; + esp_timer_start_periodic(led_strip_timer_, interval_ms * 1000); +} + +void LedStripWrapper::LightOff() { + std::lock_guard lock(mutex_); + + if (led_ == nullptr) { + ESP_LOGE(TAG, "Builtin LED not connected"); + return; + } + + esp_timer_stop(led_strip_timer_); + led_->TurnOff(); +} diff --git a/main/led_strip/led_strip_wrapper.h b/main/led_strip/led_strip_wrapper.h new file mode 100644 index 00000000..92ca93a8 --- /dev/null +++ b/main/led_strip/led_strip_wrapper.h @@ -0,0 +1,58 @@ +#ifndef _LED_STRIP_WRAPPER_H_ +#define _LED_STRIP_WRAPPER_H_ + +#include "led.h" + +#define COUNTER_INFINITE -1 + +enum LedStripEvent { + kStartup, + kListening, + kListeningAndSpeaking, + kSpeaking, + kStandby, + kConnecting, + kUpgrading, +}; + +enum LedBasicColor { + kLedColorWhite, + kLedColorGrey, + kLedColorRed, + kLedColorGreen, + kLedColorBlue, +}; + +typedef std::function TimerCallback; + +class LedStripWrapper { +private: + Led* led_ = nullptr; + std::mutex mutex_; + + uint32_t counter_ = 0; + esp_timer_handle_t led_strip_timer_ = nullptr; + TimerCallback timer_callback_; + + void SetLedBasicColor(LedBasicColor color, uint8_t brightness); + void SetLedStripBasicColor(uint8_t index, LedBasicColor color, uint8_t brightness = DEFAULT_BRIGHTNESS); + void StartBlinkTask(uint32_t times, uint32_t interval_ms); + void OnBlinkTimer(); + +public: + LedStripWrapper(gpio_num_t gpio, uint8_t max_leds); + virtual ~LedStripWrapper(); + + void LightOff(); + virtual void LightOn(LedStripEvent event) = 0; + +protected: + void BlinkOnce(LedBasicColor color, uint8_t brightness = DEFAULT_BRIGHTNESS); + void Blink(LedBasicColor color, uint32_t times, uint32_t interval_ms, uint8_t brightness = DEFAULT_BRIGHTNESS); + void ContinuousBlink(LedBasicColor color, uint32_t interval_ms, uint8_t brightness = DEFAULT_BRIGHTNESS); + void StaticLight(LedBasicColor color, uint8_t brightness = DEFAULT_BRIGHTNESS); + void ChasingLight(LedBasicColor base_color, LedBasicColor color, uint32_t interval_ms, uint8_t brightness = DEFAULT_BRIGHTNESS); + void BreathLight(LedBasicColor color, uint32_t interval_ms); +}; + +#endif // _LED_STRIP_WRAPPER_H_ diff --git a/main/led_strip/multiple_led.cc b/main/led_strip/multiple_led.cc new file mode 100644 index 00000000..8b261d40 --- /dev/null +++ b/main/led_strip/multiple_led.cc @@ -0,0 +1,39 @@ +#include "multiple_led.h" +#include + +#define TAG "MultipleLed" + +MultipleLed::MultipleLed(gpio_num_t gpio, uint8_t max_leds) : LedStripWrapper(gpio, max_leds) { +} + +MultipleLed::~MultipleLed() { +} + +void MultipleLed::LightOn(LedStripEvent event) { + switch (event) { + case kStartup: + ChasingLight(kLedColorWhite, kLedColorBlue, 100, HIGH_BRIGHTNESS); + break; + case kListeningAndSpeaking: + BreathLight(kLedColorRed, 100); + break; + case kListening: + BreathLight(kLedColorRed, 100); + break; + case kSpeaking: + StaticLight(kLedColorGreen, HIGH_BRIGHTNESS); + break; + case kStandby: + BlinkOnce(kLedColorGreen); + break; + case kConnecting: + Blink(kLedColorBlue, 1000, 500); + break; + case kUpgrading: + ContinuousBlink(kLedColorGreen, 100); + break; + default: + ESP_LOGE(TAG, "Invalid led strip event: %d", event); + return; + } +} diff --git a/main/led_strip/multiple_led.h b/main/led_strip/multiple_led.h new file mode 100644 index 00000000..14cacd44 --- /dev/null +++ b/main/led_strip/multiple_led.h @@ -0,0 +1,14 @@ +#ifndef _LED_STRIP_EFFECT_V2_H_ +#define _LED_STRIP_EFFECT_V2_H_ + +#include "led_strip_wrapper.h" + +class MultipleLed : public LedStripWrapper { +public: + MultipleLed(gpio_num_t gpio, uint8_t max_leds); + virtual ~MultipleLed(); + + void LightOn(LedStripEvent event) override; +}; + +#endif // _LED_STRIP_EFFECT_V2_H_ diff --git a/main/led_strip/single_led.cc b/main/led_strip/single_led.cc new file mode 100644 index 00000000..fd467914 --- /dev/null +++ b/main/led_strip/single_led.cc @@ -0,0 +1,39 @@ +#include "single_led.h" +#include + +#define TAG "SingleLed" + +SingleLed::SingleLed(gpio_num_t gpio) : LedStripWrapper(gpio, 1) { +} + +SingleLed::~SingleLed() { +} + +void SingleLed::LightOn(LedStripEvent event) { + switch (event) { + case kStartup: + ContinuousBlink(kLedColorBlue, 100); + break; + case kListeningAndSpeaking: + StaticLight(kLedColorRed, HIGH_BRIGHTNESS); + break; + case kListening: + StaticLight(kLedColorRed, LOW_BRIGHTNESS); + break; + case kSpeaking: + StaticLight(kLedColorGreen, HIGH_BRIGHTNESS); + break; + case kStandby: + BlinkOnce(kLedColorGreen); + break; + case kConnecting: + Blink(kLedColorBlue, 1000, 500); + break; + case kUpgrading: + ContinuousBlink(kLedColorGreen, 100); + break; + default: + ESP_LOGE(TAG, "Invalid led strip event: %d", event); + return; + } +} diff --git a/main/led_strip/single_led.h b/main/led_strip/single_led.h new file mode 100644 index 00000000..1d64ea33 --- /dev/null +++ b/main/led_strip/single_led.h @@ -0,0 +1,14 @@ +#ifndef _LED_STRIP_EFFECT_V1_H_ +#define _LED_STRIP_EFFECT_V1_H_ + +#include "led_strip_wrapper.h" + +class SingleLed : public LedStripWrapper { +public: + SingleLed(gpio_num_t gpio); + virtual ~SingleLed(); + + void LightOn(LedStripEvent event) override; +}; + +#endif // _LED_STRIP_EFFECT_V1_H_