From 5c8707075f9688e1038c78e7114e6efdfe986dfc Mon Sep 17 00:00:00 2001 From: laride <198868291+laride@users.noreply.github.com> Date: Fri, 18 Jul 2025 01:35:31 +0800 Subject: [PATCH] feat: add state change events and callbacks (#798) --- main/CMakeLists.txt | 1 + main/application.cc | 3 +++ main/application.h | 15 +------------ main/device_state.h | 18 +++++++++++++++ main/device_state_event.cc | 46 ++++++++++++++++++++++++++++++++++++++ main/device_state_event.h | 39 ++++++++++++++++++++++++++++++++ main/led/gpio_led.cc | 1 + 7 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 main/device_state.h create mode 100644 main/device_state_event.cc create mode 100644 main/device_state_event.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index f57efdb7..25b98b0b 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES "audio_codecs/audio_codec.cc" "ota.cc" "settings.cc" "background_task.cc" + "device_state_event.cc" "main.cc" ) diff --git a/main/application.cc b/main/application.cc index 2816537b..04ebc05a 100644 --- a/main/application.cc +++ b/main/application.cc @@ -990,6 +990,9 @@ void Application::SetDeviceState(DeviceState state) { // The state is changed, wait for all background tasks to finish background_task_->WaitForCompletion(); + // Send the state change event + DeviceStateEventManager::GetInstance().PostStateChangeEvent(previous_state, state); + auto& board = Board::GetInstance(); auto display = board.GetDisplay(); auto led = board.GetLed(); diff --git a/main/application.h b/main/application.h index ff23fc61..221a5c75 100644 --- a/main/application.h +++ b/main/application.h @@ -23,6 +23,7 @@ #include "audio_processor.h" #include "wake_word.h" #include "audio_debugger.h" +#include "device_state_event.h" #define SCHEDULE_EVENT (1 << 0) #define SEND_AUDIO_EVENT (1 << 1) @@ -34,20 +35,6 @@ enum AecMode { kAecOnServerSide, }; -enum DeviceState { - kDeviceStateUnknown, - kDeviceStateStarting, - kDeviceStateWifiConfiguring, - kDeviceStateIdle, - kDeviceStateConnecting, - kDeviceStateListening, - kDeviceStateSpeaking, - kDeviceStateUpgrading, - kDeviceStateActivating, - kDeviceStateAudioTesting, - kDeviceStateFatalError -}; - #define OPUS_FRAME_DURATION_MS 60 #define MAX_AUDIO_PACKETS_IN_QUEUE (2400 / OPUS_FRAME_DURATION_MS) #define AUDIO_TESTING_MAX_DURATION_MS 10000 diff --git a/main/device_state.h b/main/device_state.h new file mode 100644 index 00000000..4ffafae2 --- /dev/null +++ b/main/device_state.h @@ -0,0 +1,18 @@ +#ifndef _DEVICE_STATE_H_ +#define _DEVICE_STATE_H_ + +enum DeviceState { + kDeviceStateUnknown, + kDeviceStateStarting, + kDeviceStateWifiConfiguring, + kDeviceStateIdle, + kDeviceStateConnecting, + kDeviceStateListening, + kDeviceStateSpeaking, + kDeviceStateUpgrading, + kDeviceStateActivating, + kDeviceStateAudioTesting, + kDeviceStateFatalError +}; + +#endif // _DEVICE_STATE_H_ \ No newline at end of file diff --git a/main/device_state_event.cc b/main/device_state_event.cc new file mode 100644 index 00000000..81e2be22 --- /dev/null +++ b/main/device_state_event.cc @@ -0,0 +1,46 @@ +#include "device_state_event.h" + +ESP_EVENT_DEFINE_BASE(XIAOZHI_STATE_EVENTS); + +DeviceStateEventManager& DeviceStateEventManager::GetInstance() { + static DeviceStateEventManager instance; + return instance; +} + +void DeviceStateEventManager::RegisterStateChangeCallback(std::function callback) { + std::lock_guard lock(mutex_); + callbacks_.push_back(callback); +} + +void DeviceStateEventManager::PostStateChangeEvent(DeviceState previous_state, DeviceState current_state) { + device_state_event_data_t event_data = { + .previous_state = previous_state, + .current_state = current_state + }; + esp_event_post(XIAOZHI_STATE_EVENTS, XIAOZHI_STATE_CHANGED_EVENT, &event_data, sizeof(event_data), portMAX_DELAY); +} + +std::vector> DeviceStateEventManager::GetCallbacks() { + std::lock_guard lock(mutex_); + return callbacks_; +} + +DeviceStateEventManager::DeviceStateEventManager() { + esp_err_t err = esp_event_loop_create_default(); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + ESP_ERROR_CHECK(err); + } + + ESP_ERROR_CHECK(esp_event_handler_register(XIAOZHI_STATE_EVENTS, XIAOZHI_STATE_CHANGED_EVENT, + [](void* handler_args, esp_event_base_t base, int32_t id, void* event_data) { + auto* data = static_cast(event_data); + auto& manager = DeviceStateEventManager::GetInstance(); + for (const auto& callback : manager.GetCallbacks()) { + callback(data->previous_state, data->current_state); + } + }, nullptr)); +} + +DeviceStateEventManager::~DeviceStateEventManager() { + esp_event_handler_unregister(XIAOZHI_STATE_EVENTS, XIAOZHI_STATE_CHANGED_EVENT, nullptr); +} \ No newline at end of file diff --git a/main/device_state_event.h b/main/device_state_event.h new file mode 100644 index 00000000..03e27134 --- /dev/null +++ b/main/device_state_event.h @@ -0,0 +1,39 @@ +#ifndef _DEVICE_STATE_EVENT_H_ +#define _DEVICE_STATE_EVENT_H_ + +#include +#include +#include +#include +#include "device_state.h" + +ESP_EVENT_DECLARE_BASE(XIAOZHI_STATE_EVENTS); + +enum { + XIAOZHI_STATE_CHANGED_EVENT, +}; + +struct device_state_event_data_t { + DeviceState previous_state; + DeviceState current_state; +}; + +class DeviceStateEventManager { +public: + static DeviceStateEventManager& GetInstance(); + DeviceStateEventManager(const DeviceStateEventManager&) = delete; + DeviceStateEventManager& operator=(const DeviceStateEventManager&) = delete; + + void RegisterStateChangeCallback(std::function callback); + void PostStateChangeEvent(DeviceState previous_state, DeviceState current_state); + std::vector> GetCallbacks(); + +private: + DeviceStateEventManager(); + ~DeviceStateEventManager(); + + std::vector> callbacks_; + std::mutex mutex_; +}; + +#endif // _DEVICE_STATE_EVENT_H_ \ No newline at end of file diff --git a/main/led/gpio_led.cc b/main/led/gpio_led.cc index e719adf2..c3c32666 100644 --- a/main/led/gpio_led.cc +++ b/main/led/gpio_led.cc @@ -1,5 +1,6 @@ #include "gpio_led.h" #include "application.h" +#include "device_state.h" #include #define TAG "GpioLed"