summaryrefslogtreecommitdiff
path: root/src/system_fsm/booting.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-05-19 21:21:27 +1000
committerjacqueline <me@jacqueline.id.au>2023-05-19 21:21:27 +1000
commita6ab1504058304012791281f9eb42c262745888f (patch)
treef82379cd1e66a8ae2f1afbae5cf083a8ab7acc53 /src/system_fsm/booting.cpp
parentb320a6a863cf1c10dc79254af41f573730935564 (diff)
downloadtangara-fw-a6ab1504058304012791281f9eb42c262745888f.tar.gz
Add tinyfsm, start converting core functions to an FSM-based event loop
Diffstat (limited to 'src/system_fsm/booting.cpp')
-rw-r--r--src/system_fsm/booting.cpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp
new file mode 100644
index 00000000..a2a920c8
--- /dev/null
+++ b/src/system_fsm/booting.cpp
@@ -0,0 +1,88 @@
+#include "assert.h"
+#include "audio_fsm.hpp"
+#include "core/lv_obj.h"
+#include "display_init.hpp"
+#include "esp_err.h"
+#include "esp_log.h"
+#include "event_queue.hpp"
+#include "gpio_expander.hpp"
+#include "lvgl/lvgl.h"
+#include "spi.hpp"
+#include "system_events.hpp"
+#include "system_fsm.hpp"
+#include "ui_fsm.hpp"
+
+#include "i2c.hpp"
+#include "touchwheel.hpp"
+
+namespace system_fsm {
+namespace states {
+
+static const char kTag[] = "BOOT";
+
+auto Booting::entry() -> void {
+ ESP_LOGI(kTag, "beginning tangara boot");
+ ESP_LOGI(kTag, "installing bare minimum 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.
+ sGpioExpander.reset(drivers::GpioExpander::Create());
+ assert(sGpioExpander != nullptr);
+
+ // Start bringing up LVGL now, since we have all of its prerequisites.
+ ESP_LOGI(kTag, "starting ui");
+ lv_init();
+ sDisplay.reset(drivers::Display::Create(sGpioExpander.get(),
+ drivers::displays::kST7735R));
+ assert(sDisplay != nullptr);
+
+ // The UI FSM now has everything it needs to start setting up. Do this now,
+ // so that we can properly show the user any errors that appear later.
+ ui::UiState::Init(sGpioExpander.get(), sTouch, sDisplay, sDatabase);
+ events::Dispatch<DisplayReady, ui::UiState>(DisplayReady());
+
+ // These drivers are required for normal operation, but aren't critical for
+ // booting. We will transition to the error state if these aren't present.
+ ESP_LOGI(kTag, "installing required drivers");
+ sSamd.reset(drivers::Samd::Create());
+ sTouch.reset(drivers::TouchWheel::Create());
+
+ auto dac_res = drivers::AudioDac::create(sGpioExpander.get());
+ if (dac_res.has_error() || !sSamd || !sTouch) {
+ events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
+ FatalError());
+ return;
+ }
+ sDac.reset(dac_res.value());
+
+ // These drivers are initialised on boot, but are recoverable (if weird) if
+ // they fail.
+ ESP_LOGI(kTag, "installing extra drivers");
+ sBattery.reset(drivers::Battery::Create());
+
+ // All drivers are now loaded, so we can finish initing the other state
+ // machines.
+ audio::AudioState::Init(sGpioExpander.get(), sDac, sDatabase);
+
+ events::Dispatch<BootComplete, SystemState, ui::UiState, audio::AudioState>(
+ BootComplete());
+}
+
+auto Booting::react(const BootComplete& ev) -> void {
+ ESP_LOGE(kTag, "bootup completely successfully");
+ // It's possible that the SAMD is currently exposing the SD card as a USB
+ // device. Make sure we don't immediately try to claim it.
+ if (sSamd && sSamd->ReadUsbMscStatus() ==
+ drivers::Samd::UsbMscStatus::kAttachedMounted) {
+ transit<Unmounted>();
+ }
+ transit<Running>();
+}
+
+} // namespace states
+} // namespace system_fsm