make event queue go faster

custom
jacqueline 2 years ago
parent d8194135bb
commit f94be3db2f
  1. 4
      src/audio/audio_fsm.cpp
  2. 8
      src/audio/audio_task.cpp
  3. 4
      src/audio/fatfs_audio_input.cpp
  4. 56
      src/audio/track_queue.cpp
  5. 14
      src/drivers/gpios.cpp
  6. 7
      src/drivers/include/gpios.hpp
  7. 40
      src/events/event_queue.cpp
  8. 106
      src/events/include/event_queue.hpp
  9. 20
      src/main/main.cpp
  10. 31
      src/system_fsm/booting.cpp
  11. 2
      src/system_fsm/include/system_fsm.hpp
  12. 20
      src/system_fsm/running.cpp
  13. 27
      src/system_fsm/system_fsm.cpp
  14. 4
      src/ui/lvgl_task.cpp
  15. 3
      src/ui/screen_menu.cpp
  16. 11
      src/ui/screen_track_browser.cpp
  17. 2
      src/ui/widget_top_bar.cpp

@ -67,14 +67,14 @@ void AudioState::react(const system_fsm::StorageMounted& ev) {
void AudioState::react(const system_fsm::KeyUpChanged& ev) { void AudioState::react(const system_fsm::KeyUpChanged& ev) {
if (ev.falling && sI2SOutput->AdjustVolumeUp()) { if (ev.falling && sI2SOutput->AdjustVolumeUp()) {
ESP_LOGI(kTag, "volume up!"); ESP_LOGI(kTag, "volume up!");
events::Dispatch<VolumeChanged, ui::UiState>({}); events::Ui().Dispatch(VolumeChanged{});
} }
} }
void AudioState::react(const system_fsm::KeyDownChanged& ev) { void AudioState::react(const system_fsm::KeyDownChanged& ev) {
if (ev.falling && sI2SOutput->AdjustVolumeDown()) { if (ev.falling && sI2SOutput->AdjustVolumeDown()) {
ESP_LOGI(kTag, "volume down!"); ESP_LOGI(kTag, "volume down!");
events::Dispatch<VolumeChanged, ui::UiState>({}); events::Ui().Dispatch(VolumeChanged{});
} }
} }

@ -84,13 +84,11 @@ auto Timer::AddBytes(std::size_t bytes) -> void {
} }
if (incremented) { if (incremented) {
ESP_LOGI("timer", "new time %lu", current_seconds_); // ESP_LOGI("timer", "new time %lu", current_seconds_);
/* events::Audio().Dispatch(PlaybackUpdate{
events::Dispatch<PlaybackUpdate, AudioState, ui::UiState>(PlaybackUpdate{
.seconds_elapsed = current_seconds_, .seconds_elapsed = current_seconds_,
.seconds_total = 0, .seconds_total = 0,
}); });
*/
} }
} }

@ -135,7 +135,7 @@ auto FileStreamer::CloseFile() -> void {
ESP_LOGI(kTag, "closing file"); ESP_LOGI(kTag, "closing file");
f_close(file_.get()); f_close(file_.get());
file_ = {}; file_ = {};
events::Dispatch<internal::InputFileClosed, AudioState>({}); events::Audio().Dispatch(internal::InputFileClosed{});
} }
FatfsAudioInput::FatfsAudioInput( FatfsAudioInput::FatfsAudioInput(
@ -296,7 +296,7 @@ auto FatfsAudioInput::OpenFile(const std::string& path) -> void {
streamer_->Restart(std::move(file)); streamer_->Restart(std::move(file));
events::Dispatch<internal::InputFileOpened, AudioState>({}); events::Audio().Dispatch(internal::InputFileOpened{});
} }
auto FatfsAudioInput::CloseCurrentFile() -> void { auto FatfsAudioInput::CloseCurrentFile() -> void {

@ -81,45 +81,57 @@ auto TrackQueue::GetUpcoming(std::size_t limit) const
auto TrackQueue::AddNext(database::TrackId t) -> void { auto TrackQueue::AddNext(database::TrackId t) -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
enqueued_.push_front(t); enqueued_.push_front(t);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = enqueued_.size() < 2}); QueueUpdate ev{.current_changed = enqueued_.size() < 2};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::AddNext(std::shared_ptr<playlist::ISource> src) -> void { auto TrackQueue::AddNext(std::shared_ptr<playlist::ISource> src) -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
enqueued_.push_front(src); enqueued_.push_front(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = enqueued_.size() < 2}); QueueUpdate ev{.current_changed = enqueued_.size() < 2};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::IncludeNext(std::shared_ptr<playlist::IResetableSource> src) auto TrackQueue::IncludeNext(std::shared_ptr<playlist::IResetableSource> src)
-> void { -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
enqueued_.push_front(src); enqueued_.push_front(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = enqueued_.size() < 2}); QueueUpdate ev{.current_changed = enqueued_.size() < 2};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::AddLast(database::TrackId t) -> void { auto TrackQueue::AddLast(database::TrackId t) -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
enqueued_.push_back(t); enqueued_.push_back(t);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = enqueued_.size() < 2}); QueueUpdate ev{.current_changed = enqueued_.size() < 2};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::AddLast(std::shared_ptr<playlist::ISource> src) -> void { auto TrackQueue::AddLast(std::shared_ptr<playlist::ISource> src) -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
enqueued_.push_back(src); enqueued_.push_back(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = enqueued_.size() < 2}); QueueUpdate ev{.current_changed = enqueued_.size() < 2};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::IncludeLast(std::shared_ptr<playlist::IResetableSource> src) auto TrackQueue::IncludeLast(std::shared_ptr<playlist::IResetableSource> src)
-> void { -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
enqueued_.push_back(src); enqueued_.push_back(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = enqueued_.size() < 2}); QueueUpdate ev{.current_changed = enqueued_.size() < 2};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::Next() -> void { auto TrackQueue::Next() -> void {
@ -149,8 +161,9 @@ auto TrackQueue::Next() -> void {
} }
} }
events::Dispatch<QueueUpdate, AudioState, ui::UiState>( QueueUpdate ev{.current_changed = true};
QueueUpdate{.current_changed = true}); events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::Previous() -> void { auto TrackQueue::Previous() -> void {
@ -161,7 +174,9 @@ auto TrackQueue::Previous() -> void {
auto src = std::get<std::shared_ptr<playlist::IResetableSource>>( auto src = std::get<std::shared_ptr<playlist::IResetableSource>>(
enqueued_.front()); enqueued_.front());
if (src->Previous()) { if (src->Previous()) {
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({}); QueueUpdate ev{.current_changed = false};
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
return; return;
} }
} }
@ -180,16 +195,19 @@ auto TrackQueue::Previous() -> void {
} }
played_.pop_front(); played_.pop_front();
events::Dispatch<QueueUpdate, AudioState, ui::UiState>( QueueUpdate ev{.current_changed = true};
QueueUpdate{.current_changed = true}); events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
auto TrackQueue::Clear() -> void { auto TrackQueue::Clear() -> void {
const std::lock_guard<std::mutex> lock(mutex_); const std::lock_guard<std::mutex> lock(mutex_);
QueueUpdate ev{.current_changed = !enqueued_.empty()};
played_.clear(); played_.clear();
enqueued_.clear(); enqueued_.clear();
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
QueueUpdate{.current_changed = true}); events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
} // namespace audio } // namespace audio

@ -59,11 +59,8 @@ constexpr std::pair<uint8_t, uint8_t> unpack(uint16_t ba) {
} }
void interrupt_isr(void* arg) { void interrupt_isr(void* arg) {
Gpios* instance = reinterpret_cast<Gpios*>(arg); SemaphoreHandle_t sem = reinterpret_cast<SemaphoreHandle_t>(arg);
auto listener = instance->listener(); xSemaphoreGive(sem);
if (listener != nullptr) {
std::invoke(*listener);
}
} }
auto Gpios::Create() -> Gpios* { auto Gpios::Create() -> Gpios* {
@ -79,7 +76,7 @@ auto Gpios::Create() -> Gpios* {
Gpios::Gpios() Gpios::Gpios()
: ports_(pack(kPortADefault, kPortBDefault)), : ports_(pack(kPortADefault, kPortBDefault)),
inputs_(0), inputs_(0),
listener_(nullptr) { read_pending_(xSemaphoreCreateBinary()) {
gpio_config_t config{ gpio_config_t config{
.pin_bit_mask = static_cast<uint64_t>(1) << GPIO_NUM_34, .pin_bit_mask = static_cast<uint64_t>(1) << GPIO_NUM_34,
.mode = GPIO_MODE_INPUT, .mode = GPIO_MODE_INPUT,
@ -90,7 +87,6 @@ Gpios::Gpios()
gpio_config(&config); gpio_config(&config);
gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED |
ESP_INTR_FLAG_IRAM); ESP_INTR_FLAG_IRAM);
gpio_isr_handler_add(GPIO_NUM_34, &interrupt_isr, this);
} }
Gpios::~Gpios() { Gpios::~Gpios() {
@ -145,4 +141,8 @@ auto Gpios::Read() -> bool {
return true; return true;
} }
auto Gpios::InstallReadPendingISR() -> void {
gpio_isr_handler_add(GPIO_NUM_34, &interrupt_isr, read_pending_);
}
} // namespace drivers } // namespace drivers

@ -107,9 +107,8 @@ class Gpios : public IGpios {
*/ */
auto Read(void) -> bool; auto Read(void) -> bool;
auto listener() -> std::function<void(void)>* { return listener_; } auto InstallReadPendingISR() -> void;
auto IsReadPending() -> SemaphoreHandle_t { return read_pending_; }
auto set_listener(std::function<void(void)>* l) -> void { listener_ = l; }
// Not copyable or movable. There should usually only ever be once instance // Not copyable or movable. There should usually only ever be once instance
// of this class, and that instance will likely have a static lifetime. // of this class, and that instance will likely have a static lifetime.
@ -122,7 +121,7 @@ class Gpios : public IGpios {
std::atomic<uint16_t> ports_; std::atomic<uint16_t> ports_;
std::atomic<uint16_t> inputs_; std::atomic<uint16_t> inputs_;
std::function<void(void)>* listener_; SemaphoreHandle_t read_pending_;
}; };
} // namespace drivers } // namespace drivers

@ -6,34 +6,42 @@
#include "event_queue.hpp" #include "event_queue.hpp"
#include "audio_fsm.hpp"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h" #include "freertos/portmacro.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "system_fsm.hpp"
#include "ui_fsm.hpp"
namespace events { namespace events {
static const std::size_t kMaxPendingEvents = 16; namespace queues {
static Queue sSystemAndAudio;
static Queue sUi;
EventQueue::EventQueue() auto SystemAndAudio() -> Queue* {
: system_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))), return &sSystemAndAudio;
ui_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))) {} }
auto Ui() -> Queue* {
return &sUi;
}
} // namespace queues
static Dispatcher<system_fsm::SystemState> sSystem{queues::SystemAndAudio()};
static Dispatcher<audio::AudioState> sAudio{queues::SystemAndAudio()};
static Dispatcher<ui::UiState> sUi{queues::Ui()};
auto ServiceQueue(QueueHandle_t queue, TickType_t max_wait_time) -> bool { auto System() -> Dispatcher<system_fsm::SystemState>& {
WorkItem* item; return sSystem;
if (xQueueReceive(queue, &item, max_wait_time)) {
(*item)();
delete item;
return true;
}
return false;
} }
auto EventQueue::ServiceSystemAndAudio(TickType_t max_wait_time) -> bool { auto Audio() -> Dispatcher<audio::AudioState>& {
return ServiceQueue(system_handle_, max_wait_time); return sAudio;
} }
auto EventQueue::ServiceUi(TickType_t max_wait_time) -> bool { auto Ui() -> Dispatcher<ui::UiState>& {
return ServiceQueue(ui_handle_, max_wait_time); return sUi;
} }
} // namespace events } // namespace events

@ -7,6 +7,8 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <mutex>
#include <queue>
#include <type_traits> #include <type_traits>
#include "audio_fsm.hpp" #include "audio_fsm.hpp"
@ -20,62 +22,78 @@
namespace events { namespace events {
typedef std::function<void(void)> WorkItem; class Queue {
/*
* Handles communication of events between the system's state machines. Each
* event will be dispatched separately to each FSM, on the correct task for
* that FSM.
*/
class EventQueue {
public: public:
static EventQueue& GetInstance() { Queue() : has_events_(xSemaphoreCreateBinary()), mut_(), events_() {}
static EventQueue instance;
return instance;
}
template <typename Event> auto Add(std::function<void(void)> fn) {
auto DispatchFromISR(const Event& ev) -> bool { {
WorkItem* item = new WorkItem([=]() { std::lock_guard<std::mutex> lock{mut_};
tinyfsm::FsmList<system_fsm::SystemState>::template dispatch<Event>(ev); events_.push(fn);
}); }
BaseType_t ret; xSemaphoreGive(has_events_);
xQueueSendFromISR(system_handle_, &item, &ret);
return ret;
} }
template <typename Event, typename Machine, typename... Machines> auto Service(TickType_t max_wait) -> bool {
auto Dispatch(const Event& ev) -> void { bool res = xSemaphoreTake(has_events_, max_wait);
WorkItem* item = new WorkItem( if (!res) {
[=]() { tinyfsm::FsmList<Machine>::template dispatch<Event>(ev); }); return false;
if (std::is_same<Machine, ui::UiState>()) {
xQueueSend(ui_handle_, &item, portMAX_DELAY);
} else {
xQueueSend(system_handle_, &item, portMAX_DELAY);
} }
Dispatch<Event, Machines...>(ev);
}
template <typename Event> bool had_work = false;
auto Dispatch(const Event& ev) -> void {} for (;;) {
std::function<void(void)> fn;
{
std::lock_guard<std::mutex> lock{mut_};
if (events_.empty()) {
return had_work;
}
had_work = true;
fn = events_.front();
events_.pop();
}
std::invoke(fn);
}
}
auto ServiceSystemAndAudio(TickType_t max_wait_time) -> bool; auto has_events() -> SemaphoreHandle_t { return has_events_; }
auto ServiceUi(TickType_t max_wait_time) -> bool;
EventQueue(EventQueue const&) = delete; Queue(Queue const&) = delete;
void operator=(EventQueue const&) = delete; void operator=(Queue const&) = delete;
private: private:
EventQueue(); SemaphoreHandle_t has_events_;
std::mutex mut_;
std::queue<std::function<void(void)>> events_;
};
template <class Machine>
class Dispatcher {
public:
Dispatcher(Queue* queue) : queue_(queue) {}
template <typename Event>
auto Dispatch(const Event& ev) -> void {
auto dispatch_fn = [=]() {
tinyfsm::FsmList<Machine>::template dispatch<Event>(ev);
};
queue_->Add(dispatch_fn);
}
Dispatcher(Dispatcher const&) = delete;
void operator=(Dispatcher const&) = delete;
QueueHandle_t system_handle_; private:
QueueHandle_t ui_handle_; Queue* queue_;
}; };
template <typename Event, typename... Machines> namespace queues {
auto Dispatch(const Event& ev) -> void { auto SystemAndAudio() -> Queue*;
EventQueue& queue = EventQueue::GetInstance(); auto Ui() -> Queue*;
queue.Dispatch<Event, Machines...>(ev); } // namespace queues
}
auto System() -> Dispatcher<system_fsm::SystemState>&;
auto Audio() -> Dispatcher<audio::AudioState>&;
auto Ui() -> Dispatcher<ui::UiState>&;
} // namespace events } // namespace events

@ -6,6 +6,9 @@
#include "freertos/portmacro.h" #include "freertos/portmacro.h"
#include "gpios.hpp"
#include "i2c.hpp"
#include "system_events.hpp"
#include "tinyfsm.hpp" #include "tinyfsm.hpp"
#include "audio_fsm.hpp" #include "audio_fsm.hpp"
@ -14,11 +17,24 @@
#include "ui_fsm.hpp" #include "ui_fsm.hpp"
extern "C" void app_main(void) { extern "C" void app_main(void) {
ESP_ERROR_CHECK(drivers::init_i2c());
drivers::Gpios* gpios = system_fsm::SystemState::early_init_gpios();
QueueSetHandle_t set = xQueueCreateSet(2);
auto* event_queue = events::queues::SystemAndAudio();
xQueueAddToSet(event_queue->has_events(), set);
xQueueAddToSet(gpios->IsReadPending(), set);
tinyfsm::FsmList<system_fsm::SystemState, ui::UiState, tinyfsm::FsmList<system_fsm::SystemState, ui::UiState,
audio::AudioState>::start(); audio::AudioState>::start();
auto& queue = events::EventQueue::GetInstance();
while (1) { while (1) {
queue.ServiceSystemAndAudio(portMAX_DELAY); QueueSetMemberHandle_t member = xQueueSelectFromSet(set, portMAX_DELAY);
if (member == event_queue->has_events()) {
event_queue->Service(0);
} else if (member == gpios->IsReadPending()) {
xSemaphoreTake(member, 0);
events::System().Dispatch(system_fsm::internal::GpioInterrupt{});
}
} }
} }

@ -29,36 +29,22 @@ namespace states {
static const char kTag[] = "BOOT"; static const char kTag[] = "BOOT";
static std::function<void(void)> sGpiosCallback = []() {
events::EventQueue::GetInstance().DispatchFromISR(internal::GpioInterrupt{});
};
auto Booting::entry() -> void { auto Booting::entry() -> void {
ESP_LOGI(kTag, "beginning tangara boot"); ESP_LOGI(kTag, "beginning tangara boot");
ESP_LOGI(kTag, "installing early drivers"); ESP_LOGI(kTag, "installing early drivers");
// I2C and SPI are both always needed. We can't even power down or show an // I2C and SPI are both always needed. We can't even power down or show an
// error without these. // error without these.
ESP_ERROR_CHECK(drivers::init_i2c());
ESP_ERROR_CHECK(drivers::init_spi()); ESP_ERROR_CHECK(drivers::init_spi());
sGpios->InstallReadPendingISR();
// These drivers are the bare minimum to even show an error. If these fail,
// then the system is completely hosed.
sGpios.reset(drivers::Gpios::Create());
assert(sGpios != nullptr);
sGpios->set_listener(&sGpiosCallback);
// Start bringing up LVGL now, since we have all of its prerequisites. // Start bringing up LVGL now, since we have all of its prerequisites.
sTrackQueue.reset(new audio::TrackQueue()); sTrackQueue.reset(new audio::TrackQueue());
/*
ESP_LOGI(kTag, "starting ui"); ESP_LOGI(kTag, "starting ui");
if (!ui::UiState::Init(sGpios.get(), sTrackQueue.get())) { if (!ui::UiState::Init(sGpios.get(), sTrackQueue.get())) {
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>( events::System().Dispatch(FatalError{});
FatalError());
return; return;
} }
*/
// Install everything else that is certain to be needed. // Install everything else that is certain to be needed.
ESP_LOGI(kTag, "installing remaining drivers"); ESP_LOGI(kTag, "installing remaining drivers");
@ -67,8 +53,8 @@ auto Booting::entry() -> void {
sTagParser.reset(new database::TagParserImpl()); sTagParser.reset(new database::TagParserImpl());
if (!sSamd || !sBattery) { if (!sSamd || !sBattery) {
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>( events::System().Dispatch(FatalError{});
FatalError()); events::Ui().Dispatch(FatalError{});
return; return;
} }
@ -78,13 +64,14 @@ auto Booting::entry() -> void {
ESP_LOGI(kTag, "starting audio"); ESP_LOGI(kTag, "starting audio");
if (!audio::AudioState::Init(sGpios.get(), sDatabase, sTagParser, if (!audio::AudioState::Init(sGpios.get(), sDatabase, sTagParser,
sTrackQueue.get())) { sTrackQueue.get())) {
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>( events::System().Dispatch(FatalError{});
FatalError()); events::Ui().Dispatch(FatalError{});
return; return;
} }
events::Dispatch<BootComplete, SystemState, ui::UiState, audio::AudioState>( events::System().Dispatch(BootComplete{});
BootComplete()); events::Audio().Dispatch(BootComplete{});
events::Ui().Dispatch(BootComplete{});
} }
auto Booting::exit() -> void { auto Booting::exit() -> void {

@ -33,6 +33,8 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
public: public:
virtual ~SystemState() {} virtual ~SystemState() {}
static auto early_init_gpios() -> drivers::Gpios*;
virtual void entry() {} virtual void entry() {}
virtual void exit() {} virtual void exit() {}

@ -33,8 +33,10 @@ void Running::entry() {
auto storage_res = drivers::SdStorage::Create(sGpios.get()); auto storage_res = drivers::SdStorage::Create(sGpios.get());
if (storage_res.has_error()) { if (storage_res.has_error()) {
ESP_LOGW(kTag, "failed to mount!"); ESP_LOGW(kTag, "failed to mount!");
events::Dispatch<StorageError, SystemState, audio::AudioState, ui::UiState>(
StorageError()); events::System().Dispatch(StorageError{});
events::Audio().Dispatch(StorageError{});
events::Ui().Dispatch(StorageError{});
return; return;
} }
sStorage.reset(storage_res.value()); sStorage.reset(storage_res.value());
@ -45,16 +47,19 @@ void Running::entry() {
auto database_res = database::Database::Open(sFileGatherer, sTagParser.get()); auto database_res = database::Database::Open(sFileGatherer, sTagParser.get());
if (database_res.has_error()) { if (database_res.has_error()) {
ESP_LOGW(kTag, "failed to open!"); ESP_LOGW(kTag, "failed to open!");
events::Dispatch<StorageError, SystemState, audio::AudioState, ui::UiState>( events::System().Dispatch(StorageError{});
StorageError()); events::Audio().Dispatch(StorageError{});
events::Ui().Dispatch(StorageError{});
return; return;
} }
sDatabase.reset(database_res.value()); sDatabase.reset(database_res.value());
console::AppConsole::sDatabase = sDatabase; console::AppConsole::sDatabase = sDatabase;
ESP_LOGI(kTag, "storage loaded okay"); ESP_LOGI(kTag, "storage loaded okay");
events::Dispatch<StorageMounted, SystemState, audio::AudioState, ui::UiState>( StorageMounted ev{.db = sDatabase};
StorageMounted{.db = sDatabase}); events::System().Dispatch(ev);
events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
void Running::exit() { void Running::exit() {
@ -63,8 +68,7 @@ void Running::exit() {
} }
void Running::react(const StorageUnmountRequested& ev) { void Running::react(const StorageUnmountRequested& ev) {
events::Dispatch<internal::ReadyToUnmount, SystemState>( events::System().Dispatch(internal::ReadyToUnmount{});
internal::ReadyToUnmount());
} }
void Running::react(const internal::ReadyToUnmount& ev) { void Running::react(const internal::ReadyToUnmount& ev) {

@ -7,6 +7,7 @@
#include "system_fsm.hpp" #include "system_fsm.hpp"
#include "audio_fsm.hpp" #include "audio_fsm.hpp"
#include "event_queue.hpp" #include "event_queue.hpp"
#include "gpios.hpp"
#include "relative_wheel.hpp" #include "relative_wheel.hpp"
#include "system_events.hpp" #include "system_events.hpp"
#include "tag_parser.hpp" #include "tag_parser.hpp"
@ -30,13 +31,18 @@ std::shared_ptr<audio::TrackQueue> SystemState::sTrackQueue;
console::AppConsole* SystemState::sAppConsole; console::AppConsole* SystemState::sAppConsole;
auto SystemState::early_init_gpios() -> drivers::Gpios* {
sGpios.reset(drivers::Gpios::Create());
return sGpios.get();
}
void SystemState::react(const FatalError& err) { void SystemState::react(const FatalError& err) {
if (!is_in_state<states::Error>()) { if (!is_in_state<states::Error>()) {
transit<states::Error>(); transit<states::Error>();
} }
} }
void SystemState::react(const internal::GpioInterrupt& ev) { void SystemState::react(const internal::GpioInterrupt&) {
bool prev_key_up = sGpios->Get(drivers::Gpios::Pin::kKeyUp); bool prev_key_up = sGpios->Get(drivers::Gpios::Pin::kKeyUp);
bool prev_key_down = sGpios->Get(drivers::Gpios::Pin::kKeyDown); bool prev_key_down = sGpios->Get(drivers::Gpios::Pin::kKeyDown);
bool prev_key_lock = sGpios->Get(drivers::Gpios::Pin::kKeyLock); bool prev_key_lock = sGpios->Get(drivers::Gpios::Pin::kKeyLock);
@ -50,20 +56,23 @@ void SystemState::react(const internal::GpioInterrupt& ev) {
bool has_headphones = !sGpios->Get(drivers::Gpios::Pin::kPhoneDetect); bool has_headphones = !sGpios->Get(drivers::Gpios::Pin::kPhoneDetect);
if (key_up != prev_key_up) { if (key_up != prev_key_up) {
events::Dispatch<KeyUpChanged, audio::AudioState, ui::UiState>( KeyUpChanged ev{.falling = prev_key_up};
{.falling = prev_key_up}); events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
if (key_down != prev_key_down) { if (key_down != prev_key_down) {
events::Dispatch<KeyDownChanged, audio::AudioState, ui::UiState>( KeyDownChanged ev{.falling = prev_key_up};
{.falling = prev_key_down}); events::Audio().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
if (key_lock != prev_key_lock) { if (key_lock != prev_key_lock) {
events::Dispatch<KeyLockChanged, SystemState, ui::UiState>( KeyLockChanged ev{.falling = prev_key_up};
{.falling = prev_key_lock}); events::System().Dispatch(ev);
events::Ui().Dispatch(ev);
} }
if (has_headphones != prev_has_headphones) { if (has_headphones != prev_has_headphones) {
events::Dispatch<HasPhonesChanged, audio::AudioState>( HasPhonesChanged ev{.falling = prev_key_up};
{.falling = prev_has_headphones}); events::Audio().Dispatch(ev);
} }
} }

@ -62,9 +62,9 @@ void LvglMain(std::weak_ptr<drivers::RelativeWheel> weak_touch_wheel,
TouchWheelEncoder encoder(weak_touch_wheel); TouchWheelEncoder encoder(weak_touch_wheel);
std::shared_ptr<Screen> current_screen; std::shared_ptr<Screen> current_screen;
auto& events = events::EventQueue::GetInstance(); auto* events = events::queues::Ui();
while (1) { while (1) {
while (events.ServiceUi(0)) { while (events->Service(0)) {
} }
std::shared_ptr<Screen> screen = UiState::current_screen(); std::shared_ptr<Screen> screen = UiState::current_screen();

@ -33,8 +33,7 @@ static void item_click_cb(lv_event_t* ev) {
database::IndexInfo* index = database::IndexInfo* index =
reinterpret_cast<database::IndexInfo*>(ev->user_data); reinterpret_cast<database::IndexInfo*>(ev->user_data);
events::Dispatch<internal::IndexSelected, UiState>( events::Ui().Dispatch(internal::IndexSelected{.index = *index});
internal::IndexSelected{.index = *index});
} }
Menu::Menu(std::vector<database::IndexInfo> indexes) : indexes_(indexes) { Menu::Menu(std::vector<database::IndexInfo> indexes) : indexes_(indexes) {

@ -137,12 +137,11 @@ auto TrackBrowser::OnItemClicked(lv_event_t* ev) -> void {
for (const auto& page : current_pages_) { for (const auto& page : current_pages_) {
for (std::size_t i = 0; i < page->values().size(); i++) { for (std::size_t i = 0; i < page->values().size(); i++) {
if (index == 0) { if (index == 0) {
events::Dispatch<internal::RecordSelected, UiState>( events::Ui().Dispatch(internal::RecordSelected{
internal::RecordSelected{ .initial_page = initial_page_,
.initial_page = initial_page_, .page = page,
.page = page, .record = i,
.record = i, });
});
return; return;
} }
index--; index--;

@ -20,7 +20,7 @@ namespace ui {
namespace widgets { namespace widgets {
static void back_click_cb(lv_event_t* ev) { static void back_click_cb(lv_event_t* ev) {
events::Dispatch<internal::BackPressed, UiState>({}); events::Ui().Dispatch(internal::BackPressed{});
} }
TopBar::TopBar(lv_obj_t* parent, const Configuration& config) { TopBar::TopBar(lv_obj_t* parent, const Configuration& config) {

Loading…
Cancel
Save