diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-08-30 16:48:10 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-08-30 16:48:10 +1000 |
| commit | 320fdeb9d8355d3c361d5c6d60de8afc64501af9 (patch) | |
| tree | f0d5a2ab82199c78ad6768c6b18ba1239a0b7ee4 /src/system_fsm | |
| parent | 4247c9fe7d25c921fbfc73fc50e849c8780e7ad6 (diff) | |
| download | tangara-fw-320fdeb9d8355d3c361d5c6d60de8afc64501af9.tar.gz | |
Use a service locator instead of passing around subsets of drivers between FSMs
Diffstat (limited to 'src/system_fsm')
| -rw-r--r-- | src/system_fsm/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/system_fsm/booting.cpp | 57 | ||||
| -rw-r--r-- | src/system_fsm/idle.cpp | 26 | ||||
| -rw-r--r-- | src/system_fsm/include/service_locator.hpp | 113 | ||||
| -rw-r--r-- | src/system_fsm/include/system_events.hpp | 9 | ||||
| -rw-r--r-- | src/system_fsm/include/system_fsm.hpp | 19 | ||||
| -rw-r--r-- | src/system_fsm/running.cpp | 15 | ||||
| -rw-r--r-- | src/system_fsm/service_locator.cpp | 21 | ||||
| -rw-r--r-- | src/system_fsm/system_fsm.cpp | 53 |
9 files changed, 211 insertions, 104 deletions
diff --git a/src/system_fsm/CMakeLists.txt b/src/system_fsm/CMakeLists.txt index fced4093..449e14cc 100644 --- a/src/system_fsm/CMakeLists.txt +++ b/src/system_fsm/CMakeLists.txt @@ -3,7 +3,7 @@ # SPDX-License-Identifier: GPL-3.0-only idf_component_register( - SRCS "system_fsm.cpp" "running.cpp" "booting.cpp" "idle.cpp" + SRCS "system_fsm.cpp" "running.cpp" "booting.cpp" "idle.cpp" "service_locator.cpp" INCLUDE_DIRS "include" REQUIRES "tinyfsm" "drivers" "database" "ui" "result" "events" "audio" "app_console" "battery") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index a988c622..006ed395 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -6,8 +6,10 @@ #include <stdint.h> +#include "adc.hpp" #include "assert.h" #include "audio_fsm.hpp" +#include "battery.hpp" #include "bluetooth.hpp" #include "core/lv_obj.h" #include "display_init.hpp" @@ -23,6 +25,7 @@ #include "nvs.hpp" #include "relative_wheel.hpp" #include "samd.hpp" +#include "service_locator.hpp" #include "spi.hpp" #include "system_events.hpp" #include "system_fsm.hpp" @@ -40,65 +43,55 @@ static const char kTag[] = "BOOT"; auto Booting::entry() -> void { ESP_LOGI(kTag, "beginning tangara boot"); - ESP_LOGI(kTag, "installing early drivers"); + sServices.reset(new ServiceLocator()); + 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_spi()); - sGpios.reset(drivers::Gpios::Create()); - - sSamd.reset(drivers::Samd::Create()); - sAdc.reset(drivers::AdcBattery::Create()); - sNvs.reset(drivers::NvsStorage::OpenSync()); - assert(sSamd.get() && sAdc.get() && sNvs.get()); + sServices->gpios(std::unique_ptr<drivers::Gpios>(drivers::Gpios::Create())); - sBattery.reset(new battery::Battery(sSamd.get(), sAdc.get())); - - // 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(), sNvs, sTrackQueue.get(), sBattery)) { + if (!ui::UiState::InitBootSplash(sServices->gpios())) { events::System().Dispatch(FatalError{}); return; } - // Install everything else that is certain to be needed. ESP_LOGI(kTag, "installing remaining drivers"); - sTagParser.reset(new database::TagParserImpl()); + sServices->samd(std::unique_ptr<drivers::Samd>(drivers::Samd::Create())); + sServices->nvs( + std::unique_ptr<drivers::NvsStorage>(drivers::NvsStorage::OpenSync())); + sServices->touchwheel( + std::unique_ptr<drivers::TouchWheel>{drivers::TouchWheel::Create()}); + + auto adc = drivers::AdcBattery::Create(); + sServices->battery(std::make_unique<battery::Battery>( + sServices->samd(), std::unique_ptr<drivers::AdcBattery>(adc))); + + sServices->track_queue(std::make_unique<audio::TrackQueue>()); + sServices->tag_parser(std::make_unique<database::TagParserImpl>()); // ESP_LOGI(kTag, "starting bluetooth"); // sBluetooth.reset(new drivers::Bluetooth(sNvs.get())); // sBluetooth->Enable(); - // At this point we've done all of the essential boot tasks. Start remaining - // state machines and inform them that the system is ready. - - ESP_LOGI(kTag, "starting audio"); - if (!audio::AudioState::Init(sGpios.get(), sDatabase, sTagParser, - sBluetooth.get(), sTrackQueue.get())) { - events::System().Dispatch(FatalError{}); - events::Ui().Dispatch(FatalError{}); - return; - } - - events::System().Dispatch(BootComplete{}); - events::Audio().Dispatch(BootComplete{}); - events::Ui().Dispatch(BootComplete{}); + BootComplete ev{.services = sServices}; + events::Audio().Dispatch(ev); + events::Ui().Dispatch(ev); + events::System().Dispatch(ev); } auto Booting::exit() -> void { // TODO(jacqueline): Gate this on something. Debug flag? Flashing mode? sAppConsole = new console::AppConsole(); - sAppConsole->sTrackQueue = sTrackQueue.get(); - sAppConsole->sBluetooth = sBluetooth.get(); - sAppConsole->sSamd = sSamd.get(); + sAppConsole->sServices = sServices; sAppConsole->Launch(); } auto Booting::react(const BootComplete& ev) -> void { ESP_LOGI(kTag, "bootup completely successfully"); - if (sGpios->Get(drivers::Gpios::Pin::kKeyLock)) { + if (sServices->gpios().Get(drivers::Gpios::Pin::kKeyLock)) { transit<Running>(); } else { transit<Idle>(); diff --git a/src/system_fsm/idle.cpp b/src/system_fsm/idle.cpp index 7cc1fa39..bd327134 100644 --- a/src/system_fsm/idle.cpp +++ b/src/system_fsm/idle.cpp @@ -64,30 +64,32 @@ void Idle::react(const internal::IdleTimeout& ev) { // FIXME: It would be neater to just free a bunch of our pointers, deinit the // other state machines, etc. - if (sTouch) { - sTouch->PowerDown(); + auto touchwheel = sServices->touchwheel(); + if (touchwheel) { + touchwheel.value()->PowerDown(); } + auto& gpios = sServices->gpios(); // Pull down to turn things off - sGpios->WriteBuffered(drivers::IGpios::Pin::kAmplifierEnable, false); - sGpios->WriteBuffered(drivers::IGpios::Pin::kSdPowerEnable, false); - sGpios->WriteBuffered(drivers::IGpios::Pin::kDisplayEnable, false); + gpios.WriteBuffered(drivers::IGpios::Pin::kAmplifierEnable, false); + gpios.WriteBuffered(drivers::IGpios::Pin::kSdPowerEnable, false); + gpios.WriteBuffered(drivers::IGpios::Pin::kDisplayEnable, false); // Leave up to match the external pullups - sGpios->WriteBuffered(drivers::IGpios::Pin::kSdMuxSwitch, true); - sGpios->WriteBuffered(drivers::IGpios::Pin::kSdMuxDisable, true); + gpios.WriteBuffered(drivers::IGpios::Pin::kSdMuxSwitch, true); + gpios.WriteBuffered(drivers::IGpios::Pin::kSdMuxDisable, true); // Pull down to prevent sourcing current uselessly from input pins. - sGpios->WriteBuffered(drivers::IGpios::Pin::kSdCardDetect, false); - sGpios->WriteBuffered(drivers::IGpios::Pin::kKeyUp, false); - sGpios->WriteBuffered(drivers::IGpios::Pin::kKeyDown, false); + gpios.WriteBuffered(drivers::IGpios::Pin::kSdCardDetect, false); + gpios.WriteBuffered(drivers::IGpios::Pin::kKeyUp, false); + gpios.WriteBuffered(drivers::IGpios::Pin::kKeyDown, false); - sGpios->Flush(); + gpios.Flush(); // Retry shutting down in case of a transient failure with the SAMD. e.g. i2c // timeouts. This guards against a buggy SAMD firmware preventing idle. for (;;) { - sSamd->PowerDown(); + sServices->samd().PowerDown(); vTaskDelay(pdMS_TO_TICKS(1000)); } } diff --git a/src/system_fsm/include/service_locator.hpp b/src/system_fsm/include/service_locator.hpp new file mode 100644 index 00000000..00285ed5 --- /dev/null +++ b/src/system_fsm/include/service_locator.hpp @@ -0,0 +1,113 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <memory> + +#include "battery.hpp" +#include "bluetooth.hpp" +#include "database.hpp" +#include "gpios.hpp" +#include "nvs.hpp" +#include "samd.hpp" +#include "tag_parser.hpp" +#include "touchwheel.hpp" +#include "track_queue.hpp" + +namespace system_fsm { + +class ServiceLocator { + public: + static auto instance() -> ServiceLocator&; + + auto gpios() -> drivers::Gpios& { + assert(gpios_ != nullptr); + return *gpios_; + } + + auto gpios(std::unique_ptr<drivers::Gpios> i) { gpios_ = std::move(i); } + + auto samd() -> drivers::Samd& { + assert(samd_ != nullptr); + return *samd_; + } + + auto samd(std::unique_ptr<drivers::Samd> i) { samd_ = std::move(i); } + + auto nvs() -> drivers::NvsStorage& { + assert(nvs_ != nullptr); + return *nvs_; + } + + auto nvs(std::unique_ptr<drivers::NvsStorage> i) { nvs_ = std::move(i); } + + auto bluetooth() -> drivers::Bluetooth& { + assert(bluetooth_ != nullptr); + return *bluetooth_; + } + + auto bluetooth(std::unique_ptr<drivers::Bluetooth> i) { + bluetooth_ = std::move(i); + } + + auto battery() -> battery::Battery& { + assert(battery_ != nullptr); + return *battery_; + } + + auto battery(std::unique_ptr<battery::Battery> i) { battery_ = std::move(i); } + + auto touchwheel() -> std::optional<drivers::TouchWheel*> { + if (!touchwheel_) { + return {}; + } + return touchwheel_.get(); + } + + auto touchwheel(std::unique_ptr<drivers::TouchWheel> i) { + touchwheel_ = std::move(i); + } + + auto database() -> std::weak_ptr<database::Database> { return database_; } + + auto database(std::unique_ptr<database::Database> i) { + database_ = std::move(i); + } + + auto tag_parser() -> database::ITagParser& { + assert(tag_parser_ != nullptr); + return *tag_parser_; + } + + auto tag_parser(std::unique_ptr<database::ITagParser> i) { + tag_parser_ = std::move(i); + } + + auto track_queue() -> audio::TrackQueue& { + assert(queue_ != nullptr); + return *queue_; + } + + auto track_queue(std::unique_ptr<audio::TrackQueue> i) { + queue_ = std::move(i); + } + + private: + std::unique_ptr<drivers::Gpios> gpios_; + std::unique_ptr<drivers::Samd> samd_; + std::unique_ptr<drivers::NvsStorage> nvs_; + std::unique_ptr<drivers::TouchWheel> touchwheel_; + std::unique_ptr<drivers::Bluetooth> bluetooth_; + + std::unique_ptr<audio::TrackQueue> queue_; + std::unique_ptr<battery::Battery> battery_; + + std::shared_ptr<database::Database> database_; + std::unique_ptr<database::ITagParser> tag_parser_; +}; + +} // namespace system_fsm diff --git a/src/system_fsm/include/system_events.hpp b/src/system_fsm/include/system_events.hpp index 64cbd393..e22fe2ae 100644 --- a/src/system_fsm/include/system_events.hpp +++ b/src/system_fsm/include/system_events.hpp @@ -9,6 +9,7 @@ #include <memory> #include "database.hpp" +#include "service_locator.hpp" #include "tinyfsm.hpp" namespace system_fsm { @@ -19,7 +20,9 @@ struct DisplayReady : tinyfsm::Event {}; * Sent by SysState when the system has finished with its boot and self-test, * and is now ready to run normally. */ -struct BootComplete : tinyfsm::Event {}; +struct BootComplete : tinyfsm::Event { + std::shared_ptr<ServiceLocator> services; +}; /* * May be sent by any component to indicate that the system has experienced an @@ -33,9 +36,7 @@ struct OnIdle : tinyfsm::Event {}; /* * Sent by SysState when the system storage has been successfully mounted. */ -struct StorageMounted : tinyfsm::Event { - std::weak_ptr<database::Database> db; -}; +struct StorageMounted : tinyfsm::Event {}; struct StorageError : tinyfsm::Event {}; diff --git a/src/system_fsm/include/system_fsm.hpp b/src/system_fsm/include/system_fsm.hpp index 371e5527..28448e5a 100644 --- a/src/system_fsm/include/system_fsm.hpp +++ b/src/system_fsm/include/system_fsm.hpp @@ -18,6 +18,7 @@ #include "nvs.hpp" #include "relative_wheel.hpp" #include "samd.hpp" +#include "service_locator.hpp" #include "storage.hpp" #include "tag_parser.hpp" #include "tinyfsm.hpp" @@ -60,22 +61,8 @@ class SystemState : public tinyfsm::Fsm<SystemState> { protected: auto IdleCondition() -> bool; - static std::shared_ptr<drivers::Gpios> sGpios; - static std::shared_ptr<drivers::Samd> sSamd; - static std::shared_ptr<drivers::NvsStorage> sNvs; - - static std::shared_ptr<drivers::TouchWheel> sTouch; - static std::shared_ptr<drivers::RelativeWheel> sRelativeTouch; - static std::shared_ptr<drivers::AdcBattery> sAdc; - static std::shared_ptr<battery::Battery> sBattery; - static std::shared_ptr<drivers::SdStorage> sStorage; - static std::shared_ptr<drivers::Display> sDisplay; - static std::shared_ptr<drivers::Bluetooth> sBluetooth; - - static std::shared_ptr<database::Database> sDatabase; - static std::shared_ptr<database::TagParserImpl> sTagParser; - - static std::shared_ptr<audio::TrackQueue> sTrackQueue; + static std::shared_ptr<ServiceLocator> sServices; + static std::unique_ptr<drivers::SdStorage> sStorage; static console::AppConsole* sAppConsole; }; diff --git a/src/system_fsm/running.cpp b/src/system_fsm/running.cpp index 3fc5493f..e42429e7 100644 --- a/src/system_fsm/running.cpp +++ b/src/system_fsm/running.cpp @@ -6,6 +6,7 @@ #include "app_console.hpp" #include "audio_events.hpp" +#include "database.hpp" #include "file_gatherer.hpp" #include "freertos/projdefs.h" #include "result.hpp" @@ -31,7 +32,7 @@ static database::IFileGatherer* sFileGatherer; void Running::entry() { ESP_LOGI(kTag, "mounting sd card"); vTaskDelay(pdMS_TO_TICKS(250)); - auto storage_res = drivers::SdStorage::Create(sGpios.get()); + auto storage_res = drivers::SdStorage::Create(sServices->gpios()); if (storage_res.has_error()) { ESP_LOGW(kTag, "failed to mount!"); @@ -41,11 +42,11 @@ void Running::entry() { return; } sStorage.reset(storage_res.value()); - vTaskDelay(pdMS_TO_TICKS(250)); ESP_LOGI(kTag, "opening database"); sFileGatherer = new database::FileGathererImpl(); - auto database_res = database::Database::Open(sFileGatherer, sTagParser.get()); + auto database_res = + database::Database::Open(*sFileGatherer, sServices->tag_parser()); if (database_res.has_error()) { ESP_LOGW(kTag, "failed to open!"); events::System().Dispatch(StorageError{}); @@ -53,18 +54,18 @@ void Running::entry() { events::Ui().Dispatch(StorageError{}); return; } - sDatabase.reset(database_res.value()); - console::AppConsole::sDatabase = sDatabase; + sServices->database( + std::unique_ptr<database::Database>{database_res.value()}); ESP_LOGI(kTag, "storage loaded okay"); - StorageMounted ev{.db = sDatabase}; + StorageMounted ev{}; events::System().Dispatch(ev); events::Audio().Dispatch(ev); events::Ui().Dispatch(ev); } void Running::exit() { - sDatabase.reset(); + sServices->database({}); sStorage.reset(); } diff --git a/src/system_fsm/service_locator.cpp b/src/system_fsm/service_locator.cpp new file mode 100644 index 00000000..1d4d8a65 --- /dev/null +++ b/src/system_fsm/service_locator.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "service_locator.hpp" + +#include <memory> + +#include "nvs.hpp" +#include "touchwheel.hpp" + +namespace system_fsm { + +auto ServiceLocator::instance() -> ServiceLocator& { + static ServiceLocator sInstance{}; + return sInstance; +} + +} // namespace system_fsm diff --git a/src/system_fsm/system_fsm.cpp b/src/system_fsm/system_fsm.cpp index d21e8bcb..e048cec7 100644 --- a/src/system_fsm/system_fsm.cpp +++ b/src/system_fsm/system_fsm.cpp @@ -9,6 +9,7 @@ #include "event_queue.hpp" #include "gpios.hpp" #include "relative_wheel.hpp" +#include "service_locator.hpp" #include "system_events.hpp" #include "tag_parser.hpp" #include "track_queue.hpp" @@ -17,22 +18,8 @@ static const char kTag[] = "system"; namespace system_fsm { -std::shared_ptr<drivers::Gpios> SystemState::sGpios; -std::shared_ptr<drivers::Samd> SystemState::sSamd; -std::shared_ptr<drivers::NvsStorage> SystemState::sNvs; - -std::shared_ptr<drivers::TouchWheel> SystemState::sTouch; -std::shared_ptr<drivers::RelativeWheel> SystemState::sRelativeTouch; -std::shared_ptr<drivers::AdcBattery> SystemState::sAdc; -std::shared_ptr<battery::Battery> SystemState::sBattery; -std::shared_ptr<drivers::SdStorage> SystemState::sStorage; -std::shared_ptr<drivers::Display> SystemState::sDisplay; -std::shared_ptr<drivers::Bluetooth> SystemState::sBluetooth; - -std::shared_ptr<database::Database> SystemState::sDatabase; -std::shared_ptr<database::TagParserImpl> SystemState::sTagParser; - -std::shared_ptr<audio::TrackQueue> SystemState::sTrackQueue; +std::shared_ptr<ServiceLocator> SystemState::sServices; +std::unique_ptr<drivers::SdStorage> SystemState::sStorage; console::AppConsole* SystemState::sAppConsole; @@ -43,17 +30,18 @@ void SystemState::react(const FatalError& err) { } 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); - bool prev_has_headphones = !sGpios->Get(drivers::Gpios::Pin::kPhoneDetect); + auto& gpios = sServices->gpios(); + bool prev_key_up = gpios.Get(drivers::Gpios::Pin::kKeyUp); + bool prev_key_down = gpios.Get(drivers::Gpios::Pin::kKeyDown); + bool prev_key_lock = gpios.Get(drivers::Gpios::Pin::kKeyLock); + bool prev_has_headphones = !gpios.Get(drivers::Gpios::Pin::kPhoneDetect); - sGpios->Read(); + gpios.Read(); - bool key_up = sGpios->Get(drivers::Gpios::Pin::kKeyUp); - bool key_down = sGpios->Get(drivers::Gpios::Pin::kKeyDown); - bool key_lock = sGpios->Get(drivers::Gpios::Pin::kKeyLock); - bool has_headphones = !sGpios->Get(drivers::Gpios::Pin::kPhoneDetect); + bool key_up = gpios.Get(drivers::Gpios::Pin::kKeyUp); + bool key_down = gpios.Get(drivers::Gpios::Pin::kKeyDown); + bool key_lock = gpios.Get(drivers::Gpios::Pin::kKeyLock); + bool has_headphones = !gpios.Get(drivers::Gpios::Pin::kPhoneDetect); if (key_up != prev_key_up) { KeyUpChanged ev{.falling = prev_key_up}; @@ -77,14 +65,15 @@ void SystemState::react(const internal::GpioInterrupt&) { } void SystemState::react(const internal::SamdInterrupt&) { - auto prev_charge_status = sSamd->GetChargeStatus(); - auto prev_usb_status = sSamd->GetUsbStatus(); + auto& samd = sServices->samd(); + auto prev_charge_status = samd.GetChargeStatus(); + auto prev_usb_status = samd.GetUsbStatus(); - sSamd->UpdateChargeStatus(); - sSamd->UpdateUsbStatus(); + samd.UpdateChargeStatus(); + samd.UpdateUsbStatus(); - auto charge_status = sSamd->GetChargeStatus(); - auto usb_status = sSamd->GetUsbStatus(); + auto charge_status = samd.GetChargeStatus(); + auto usb_status = samd.GetUsbStatus(); if (charge_status != prev_charge_status) { ChargingStatusChanged ev{}; @@ -97,7 +86,7 @@ void SystemState::react(const internal::SamdInterrupt&) { } auto SystemState::IdleCondition() -> bool { - return !sGpios->Get(drivers::IGpios::Pin::kKeyLock) && + return !sServices->gpios().Get(drivers::IGpios::Pin::kKeyLock) && audio::AudioState::is_in_state<audio::states::Standby>(); } |
