make event queue go faster
This commit is contained in:
@@ -67,14 +67,14 @@ void AudioState::react(const system_fsm::StorageMounted& ev) {
|
||||
void AudioState::react(const system_fsm::KeyUpChanged& ev) {
|
||||
if (ev.falling && sI2SOutput->AdjustVolumeUp()) {
|
||||
ESP_LOGI(kTag, "volume up!");
|
||||
events::Dispatch<VolumeChanged, ui::UiState>({});
|
||||
events::Ui().Dispatch(VolumeChanged{});
|
||||
}
|
||||
}
|
||||
|
||||
void AudioState::react(const system_fsm::KeyDownChanged& ev) {
|
||||
if (ev.falling && sI2SOutput->AdjustVolumeDown()) {
|
||||
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) {
|
||||
ESP_LOGI("timer", "new time %lu", current_seconds_);
|
||||
/*
|
||||
events::Dispatch<PlaybackUpdate, AudioState, ui::UiState>(PlaybackUpdate{
|
||||
// ESP_LOGI("timer", "new time %lu", current_seconds_);
|
||||
events::Audio().Dispatch(PlaybackUpdate{
|
||||
.seconds_elapsed = current_seconds_,
|
||||
.seconds_total = 0,
|
||||
});
|
||||
*/
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ auto FileStreamer::CloseFile() -> void {
|
||||
ESP_LOGI(kTag, "closing file");
|
||||
f_close(file_.get());
|
||||
file_ = {};
|
||||
events::Dispatch<internal::InputFileClosed, AudioState>({});
|
||||
events::Audio().Dispatch(internal::InputFileClosed{});
|
||||
}
|
||||
|
||||
FatfsAudioInput::FatfsAudioInput(
|
||||
@@ -296,7 +296,7 @@ auto FatfsAudioInput::OpenFile(const std::string& path) -> void {
|
||||
|
||||
streamer_->Restart(std::move(file));
|
||||
|
||||
events::Dispatch<internal::InputFileOpened, AudioState>({});
|
||||
events::Audio().Dispatch(internal::InputFileOpened{});
|
||||
}
|
||||
|
||||
auto FatfsAudioInput::CloseCurrentFile() -> void {
|
||||
|
||||
+37
-19
@@ -81,45 +81,57 @@ auto TrackQueue::GetUpcoming(std::size_t limit) const
|
||||
auto TrackQueue::AddNext(database::TrackId t) -> void {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
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 {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
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)
|
||||
-> void {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
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 {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
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 {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
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)
|
||||
-> void {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
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 {
|
||||
@@ -149,8 +161,9 @@ auto TrackQueue::Next() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
|
||||
QueueUpdate{.current_changed = true});
|
||||
QueueUpdate ev{.current_changed = true};
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
|
||||
auto TrackQueue::Previous() -> void {
|
||||
@@ -161,7 +174,9 @@ auto TrackQueue::Previous() -> void {
|
||||
auto src = std::get<std::shared_ptr<playlist::IResetableSource>>(
|
||||
enqueued_.front());
|
||||
if (src->Previous()) {
|
||||
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
|
||||
QueueUpdate ev{.current_changed = false};
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -180,16 +195,19 @@ auto TrackQueue::Previous() -> void {
|
||||
}
|
||||
played_.pop_front();
|
||||
|
||||
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
|
||||
QueueUpdate{.current_changed = true});
|
||||
QueueUpdate ev{.current_changed = true};
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
|
||||
auto TrackQueue::Clear() -> void {
|
||||
const std::lock_guard<std::mutex> lock(mutex_);
|
||||
QueueUpdate ev{.current_changed = !enqueued_.empty()};
|
||||
played_.clear();
|
||||
enqueued_.clear();
|
||||
events::Dispatch<QueueUpdate, AudioState, ui::UiState>(
|
||||
QueueUpdate{.current_changed = true});
|
||||
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
|
||||
@@ -59,11 +59,8 @@ constexpr std::pair<uint8_t, uint8_t> unpack(uint16_t ba) {
|
||||
}
|
||||
|
||||
void interrupt_isr(void* arg) {
|
||||
Gpios* instance = reinterpret_cast<Gpios*>(arg);
|
||||
auto listener = instance->listener();
|
||||
if (listener != nullptr) {
|
||||
std::invoke(*listener);
|
||||
}
|
||||
SemaphoreHandle_t sem = reinterpret_cast<SemaphoreHandle_t>(arg);
|
||||
xSemaphoreGive(sem);
|
||||
}
|
||||
|
||||
auto Gpios::Create() -> Gpios* {
|
||||
@@ -79,7 +76,7 @@ auto Gpios::Create() -> Gpios* {
|
||||
Gpios::Gpios()
|
||||
: ports_(pack(kPortADefault, kPortBDefault)),
|
||||
inputs_(0),
|
||||
listener_(nullptr) {
|
||||
read_pending_(xSemaphoreCreateBinary()) {
|
||||
gpio_config_t config{
|
||||
.pin_bit_mask = static_cast<uint64_t>(1) << GPIO_NUM_34,
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
@@ -90,7 +87,6 @@ Gpios::Gpios()
|
||||
gpio_config(&config);
|
||||
gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED |
|
||||
ESP_INTR_FLAG_IRAM);
|
||||
gpio_isr_handler_add(GPIO_NUM_34, &interrupt_isr, this);
|
||||
}
|
||||
|
||||
Gpios::~Gpios() {
|
||||
@@ -145,4 +141,8 @@ auto Gpios::Read() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Gpios::InstallReadPendingISR() -> void {
|
||||
gpio_isr_handler_add(GPIO_NUM_34, &interrupt_isr, read_pending_);
|
||||
}
|
||||
|
||||
} // namespace drivers
|
||||
|
||||
@@ -107,9 +107,8 @@ class Gpios : public IGpios {
|
||||
*/
|
||||
auto Read(void) -> bool;
|
||||
|
||||
auto listener() -> std::function<void(void)>* { return listener_; }
|
||||
|
||||
auto set_listener(std::function<void(void)>* l) -> void { listener_ = l; }
|
||||
auto InstallReadPendingISR() -> void;
|
||||
auto IsReadPending() -> SemaphoreHandle_t { return read_pending_; }
|
||||
|
||||
// Not copyable or movable. There should usually only ever be once instance
|
||||
// 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> inputs_;
|
||||
|
||||
std::function<void(void)>* listener_;
|
||||
SemaphoreHandle_t read_pending_;
|
||||
};
|
||||
|
||||
} // namespace drivers
|
||||
|
||||
+25
-17
@@ -6,34 +6,42 @@
|
||||
|
||||
#include "event_queue.hpp"
|
||||
|
||||
#include "audio_fsm.hpp"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "system_fsm.hpp"
|
||||
#include "ui_fsm.hpp"
|
||||
|
||||
namespace events {
|
||||
|
||||
static const std::size_t kMaxPendingEvents = 16;
|
||||
namespace queues {
|
||||
static Queue sSystemAndAudio;
|
||||
static Queue sUi;
|
||||
|
||||
EventQueue::EventQueue()
|
||||
: system_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))),
|
||||
ui_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))) {}
|
||||
|
||||
auto ServiceQueue(QueueHandle_t queue, TickType_t max_wait_time) -> bool {
|
||||
WorkItem* item;
|
||||
if (xQueueReceive(queue, &item, max_wait_time)) {
|
||||
(*item)();
|
||||
delete item;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
auto SystemAndAudio() -> Queue* {
|
||||
return &sSystemAndAudio;
|
||||
}
|
||||
|
||||
auto EventQueue::ServiceSystemAndAudio(TickType_t max_wait_time) -> bool {
|
||||
return ServiceQueue(system_handle_, max_wait_time);
|
||||
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 System() -> Dispatcher<system_fsm::SystemState>& {
|
||||
return sSystem;
|
||||
}
|
||||
|
||||
auto EventQueue::ServiceUi(TickType_t max_wait_time) -> bool {
|
||||
return ServiceQueue(ui_handle_, max_wait_time);
|
||||
auto Audio() -> Dispatcher<audio::AudioState>& {
|
||||
return sAudio;
|
||||
}
|
||||
|
||||
auto Ui() -> Dispatcher<ui::UiState>& {
|
||||
return sUi;
|
||||
}
|
||||
|
||||
} // namespace events
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <type_traits>
|
||||
|
||||
#include "audio_fsm.hpp"
|
||||
@@ -20,62 +22,78 @@
|
||||
|
||||
namespace events {
|
||||
|
||||
typedef std::function<void(void)> WorkItem;
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
class Queue {
|
||||
public:
|
||||
static EventQueue& GetInstance() {
|
||||
static EventQueue instance;
|
||||
return instance;
|
||||
}
|
||||
Queue() : has_events_(xSemaphoreCreateBinary()), mut_(), events_() {}
|
||||
|
||||
template <typename Event>
|
||||
auto DispatchFromISR(const Event& ev) -> bool {
|
||||
WorkItem* item = new WorkItem([=]() {
|
||||
tinyfsm::FsmList<system_fsm::SystemState>::template dispatch<Event>(ev);
|
||||
});
|
||||
BaseType_t ret;
|
||||
xQueueSendFromISR(system_handle_, &item, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Event, typename Machine, typename... Machines>
|
||||
auto Dispatch(const Event& ev) -> void {
|
||||
WorkItem* item = new WorkItem(
|
||||
[=]() { tinyfsm::FsmList<Machine>::template dispatch<Event>(ev); });
|
||||
if (std::is_same<Machine, ui::UiState>()) {
|
||||
xQueueSend(ui_handle_, &item, portMAX_DELAY);
|
||||
} else {
|
||||
xQueueSend(system_handle_, &item, portMAX_DELAY);
|
||||
auto Add(std::function<void(void)> fn) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{mut_};
|
||||
events_.push(fn);
|
||||
}
|
||||
Dispatch<Event, Machines...>(ev);
|
||||
xSemaphoreGive(has_events_);
|
||||
}
|
||||
|
||||
template <typename Event>
|
||||
auto Dispatch(const Event& ev) -> void {}
|
||||
auto Service(TickType_t max_wait) -> bool {
|
||||
bool res = xSemaphoreTake(has_events_, max_wait);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ServiceSystemAndAudio(TickType_t max_wait_time) -> bool;
|
||||
auto ServiceUi(TickType_t max_wait_time) -> bool;
|
||||
bool had_work = false;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
EventQueue(EventQueue const&) = delete;
|
||||
void operator=(EventQueue const&) = delete;
|
||||
auto has_events() -> SemaphoreHandle_t { return has_events_; }
|
||||
|
||||
Queue(Queue const&) = delete;
|
||||
void operator=(Queue const&) = delete;
|
||||
|
||||
private:
|
||||
EventQueue();
|
||||
|
||||
QueueHandle_t system_handle_;
|
||||
QueueHandle_t ui_handle_;
|
||||
SemaphoreHandle_t has_events_;
|
||||
std::mutex mut_;
|
||||
std::queue<std::function<void(void)>> events_;
|
||||
};
|
||||
|
||||
template <typename Event, typename... Machines>
|
||||
auto Dispatch(const Event& ev) -> void {
|
||||
EventQueue& queue = EventQueue::GetInstance();
|
||||
queue.Dispatch<Event, Machines...>(ev);
|
||||
}
|
||||
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;
|
||||
|
||||
private:
|
||||
Queue* queue_;
|
||||
};
|
||||
|
||||
namespace queues {
|
||||
auto SystemAndAudio() -> Queue*;
|
||||
auto Ui() -> Queue*;
|
||||
} // namespace queues
|
||||
|
||||
auto System() -> Dispatcher<system_fsm::SystemState>&;
|
||||
auto Audio() -> Dispatcher<audio::AudioState>&;
|
||||
auto Ui() -> Dispatcher<ui::UiState>&;
|
||||
|
||||
} // namespace events
|
||||
|
||||
+18
-2
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "freertos/portmacro.h"
|
||||
|
||||
#include "gpios.hpp"
|
||||
#include "i2c.hpp"
|
||||
#include "system_events.hpp"
|
||||
#include "tinyfsm.hpp"
|
||||
|
||||
#include "audio_fsm.hpp"
|
||||
@@ -14,11 +17,24 @@
|
||||
#include "ui_fsm.hpp"
|
||||
|
||||
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,
|
||||
audio::AudioState>::start();
|
||||
|
||||
auto& queue = events::EventQueue::GetInstance();
|
||||
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 std::function<void(void)> sGpiosCallback = []() {
|
||||
events::EventQueue::GetInstance().DispatchFromISR(internal::GpioInterrupt{});
|
||||
};
|
||||
|
||||
auto Booting::entry() -> void {
|
||||
ESP_LOGI(kTag, "beginning tangara boot");
|
||||
ESP_LOGI(kTag, "installing early drivers");
|
||||
|
||||
// I2C and SPI are both always needed. We can't even power down or show an
|
||||
// error without these.
|
||||
ESP_ERROR_CHECK(drivers::init_i2c());
|
||||
ESP_ERROR_CHECK(drivers::init_spi());
|
||||
|
||||
// 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);
|
||||
sGpios->InstallReadPendingISR();
|
||||
|
||||
// Start bringing up LVGL now, since we have all of its prerequisites.
|
||||
sTrackQueue.reset(new audio::TrackQueue());
|
||||
/*
|
||||
ESP_LOGI(kTag, "starting ui");
|
||||
if (!ui::UiState::Init(sGpios.get(), sTrackQueue.get())) {
|
||||
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
|
||||
FatalError());
|
||||
events::System().Dispatch(FatalError{});
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// Install everything else that is certain to be needed.
|
||||
ESP_LOGI(kTag, "installing remaining drivers");
|
||||
@@ -67,8 +53,8 @@ auto Booting::entry() -> void {
|
||||
sTagParser.reset(new database::TagParserImpl());
|
||||
|
||||
if (!sSamd || !sBattery) {
|
||||
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
|
||||
FatalError());
|
||||
events::System().Dispatch(FatalError{});
|
||||
events::Ui().Dispatch(FatalError{});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,13 +64,14 @@ auto Booting::entry() -> void {
|
||||
ESP_LOGI(kTag, "starting audio");
|
||||
if (!audio::AudioState::Init(sGpios.get(), sDatabase, sTagParser,
|
||||
sTrackQueue.get())) {
|
||||
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
|
||||
FatalError());
|
||||
events::System().Dispatch(FatalError{});
|
||||
events::Ui().Dispatch(FatalError{});
|
||||
return;
|
||||
}
|
||||
|
||||
events::Dispatch<BootComplete, SystemState, ui::UiState, audio::AudioState>(
|
||||
BootComplete());
|
||||
events::System().Dispatch(BootComplete{});
|
||||
events::Audio().Dispatch(BootComplete{});
|
||||
events::Ui().Dispatch(BootComplete{});
|
||||
}
|
||||
|
||||
auto Booting::exit() -> void {
|
||||
|
||||
@@ -33,6 +33,8 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
|
||||
public:
|
||||
virtual ~SystemState() {}
|
||||
|
||||
static auto early_init_gpios() -> drivers::Gpios*;
|
||||
|
||||
virtual void entry() {}
|
||||
virtual void exit() {}
|
||||
|
||||
|
||||
@@ -33,8 +33,10 @@ void Running::entry() {
|
||||
auto storage_res = drivers::SdStorage::Create(sGpios.get());
|
||||
if (storage_res.has_error()) {
|
||||
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;
|
||||
}
|
||||
sStorage.reset(storage_res.value());
|
||||
@@ -45,16 +47,19 @@ void Running::entry() {
|
||||
auto database_res = database::Database::Open(sFileGatherer, sTagParser.get());
|
||||
if (database_res.has_error()) {
|
||||
ESP_LOGW(kTag, "failed to open!");
|
||||
events::Dispatch<StorageError, SystemState, audio::AudioState, ui::UiState>(
|
||||
StorageError());
|
||||
events::System().Dispatch(StorageError{});
|
||||
events::Audio().Dispatch(StorageError{});
|
||||
events::Ui().Dispatch(StorageError{});
|
||||
return;
|
||||
}
|
||||
sDatabase.reset(database_res.value());
|
||||
console::AppConsole::sDatabase = sDatabase;
|
||||
|
||||
ESP_LOGI(kTag, "storage loaded okay");
|
||||
events::Dispatch<StorageMounted, SystemState, audio::AudioState, ui::UiState>(
|
||||
StorageMounted{.db = sDatabase});
|
||||
StorageMounted ev{.db = sDatabase};
|
||||
events::System().Dispatch(ev);
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
|
||||
void Running::exit() {
|
||||
@@ -63,8 +68,7 @@ void Running::exit() {
|
||||
}
|
||||
|
||||
void Running::react(const StorageUnmountRequested& ev) {
|
||||
events::Dispatch<internal::ReadyToUnmount, SystemState>(
|
||||
internal::ReadyToUnmount());
|
||||
events::System().Dispatch(internal::ReadyToUnmount{});
|
||||
}
|
||||
|
||||
void Running::react(const internal::ReadyToUnmount& ev) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "system_fsm.hpp"
|
||||
#include "audio_fsm.hpp"
|
||||
#include "event_queue.hpp"
|
||||
#include "gpios.hpp"
|
||||
#include "relative_wheel.hpp"
|
||||
#include "system_events.hpp"
|
||||
#include "tag_parser.hpp"
|
||||
@@ -30,13 +31,18 @@ std::shared_ptr<audio::TrackQueue> SystemState::sTrackQueue;
|
||||
|
||||
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) {
|
||||
if (!is_in_state<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_down = sGpios->Get(drivers::Gpios::Pin::kKeyDown);
|
||||
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);
|
||||
|
||||
if (key_up != prev_key_up) {
|
||||
events::Dispatch<KeyUpChanged, audio::AudioState, ui::UiState>(
|
||||
{.falling = prev_key_up});
|
||||
KeyUpChanged ev{.falling = prev_key_up};
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
if (key_down != prev_key_down) {
|
||||
events::Dispatch<KeyDownChanged, audio::AudioState, ui::UiState>(
|
||||
{.falling = prev_key_down});
|
||||
KeyDownChanged ev{.falling = prev_key_up};
|
||||
events::Audio().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
if (key_lock != prev_key_lock) {
|
||||
events::Dispatch<KeyLockChanged, SystemState, ui::UiState>(
|
||||
{.falling = prev_key_lock});
|
||||
KeyLockChanged ev{.falling = prev_key_up};
|
||||
events::System().Dispatch(ev);
|
||||
events::Ui().Dispatch(ev);
|
||||
}
|
||||
if (has_headphones != prev_has_headphones) {
|
||||
events::Dispatch<HasPhonesChanged, audio::AudioState>(
|
||||
{.falling = prev_has_headphones});
|
||||
HasPhonesChanged ev{.falling = prev_key_up};
|
||||
events::Audio().Dispatch(ev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,9 +62,9 @@ void LvglMain(std::weak_ptr<drivers::RelativeWheel> weak_touch_wheel,
|
||||
TouchWheelEncoder encoder(weak_touch_wheel);
|
||||
|
||||
std::shared_ptr<Screen> current_screen;
|
||||
auto& events = events::EventQueue::GetInstance();
|
||||
auto* events = events::queues::Ui();
|
||||
while (1) {
|
||||
while (events.ServiceUi(0)) {
|
||||
while (events->Service(0)) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Screen> screen = UiState::current_screen();
|
||||
|
||||
@@ -33,8 +33,7 @@ static void item_click_cb(lv_event_t* ev) {
|
||||
database::IndexInfo* index =
|
||||
reinterpret_cast<database::IndexInfo*>(ev->user_data);
|
||||
|
||||
events::Dispatch<internal::IndexSelected, UiState>(
|
||||
internal::IndexSelected{.index = *index});
|
||||
events::Ui().Dispatch(internal::IndexSelected{.index = *index});
|
||||
}
|
||||
|
||||
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 (std::size_t i = 0; i < page->values().size(); i++) {
|
||||
if (index == 0) {
|
||||
events::Dispatch<internal::RecordSelected, UiState>(
|
||||
internal::RecordSelected{
|
||||
.initial_page = initial_page_,
|
||||
.page = page,
|
||||
.record = i,
|
||||
});
|
||||
events::Ui().Dispatch(internal::RecordSelected{
|
||||
.initial_page = initial_page_,
|
||||
.page = page,
|
||||
.record = i,
|
||||
});
|
||||
return;
|
||||
}
|
||||
index--;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ui {
|
||||
namespace widgets {
|
||||
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user