diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index 885321d1..679c40b2 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -91,9 +91,7 @@ I2SDac::I2SDac(IGpios* gpio, i2s_chan_handle_t i2s_handle) // Reset all registers back to their default values. wm8523::WriteRegister(wm8523::Register::kReset, 1); vTaskDelay(pdMS_TO_TICKS(10)); - - // Power up the charge pump. - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); } I2SDac::~I2SDac() { @@ -102,24 +100,28 @@ I2SDac::~I2SDac() { } auto I2SDac::Start() -> void { + // Ramp up the amplifier power supply. gpio_->WriteSync(IGpios::Pin::kAmplifierEnable, true); + + // Wait for voltage to stabilise vTaskDelay(pdMS_TO_TICKS(1)); - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); - uint8_t zeroes[256]{0}; - size_t bytes_loaded = 0; - esp_err_t res = ESP_OK; - do { - res = i2s_channel_preload_data(i2s_handle_, zeroes, 256, &bytes_loaded); - } while (bytes_loaded > 0 && res == ESP_OK); + // Ensure the DAC powers up to a muted state. + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); + // Enable MCLK; this has the side effect of triggering the DAC's startup + // sequence. i2s_channel_enable(i2s_handle_); + + // Wait for DAC output lines to stabilise + vTaskDelay(pdMS_TO_TICKS(1)); + + // FIXME: Pull the amp's EN pin here. i2s_active_ = true; } auto I2SDac::Stop() -> void { - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); i2s_channel_disable(i2s_handle_); gpio_->WriteSync(IGpios::Pin::kAmplifierEnable, false); diff --git a/src/drivers/include/touchwheel.hpp b/src/drivers/include/touchwheel.hpp index f42b575b..38e8a9f1 100644 --- a/src/drivers/include/touchwheel.hpp +++ b/src/drivers/include/touchwheel.hpp @@ -35,6 +35,8 @@ class TouchWheel { auto Update() -> void; auto GetTouchWheelData() const -> TouchWheelData; + auto PowerDown() -> void; + private: TouchWheelData data_; diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp index 59c2911e..6b925055 100644 --- a/src/drivers/touchwheel.cpp +++ b/src/drivers/touchwheel.cpp @@ -22,6 +22,8 @@ namespace drivers { +// Touch wheel implementation using a Microchip AT42QT2120 + static const char* kTag = "TOUCHWHEEL"; static const uint8_t kTouchWheelAddress = 0x1C; static const gpio_num_t kIntPin = GPIO_NUM_25; @@ -121,4 +123,8 @@ TouchWheelData TouchWheel::GetTouchWheelData() const { return data_; } +auto TouchWheel::PowerDown() -> void { + WriteRegister(LOW_POWER, 0); +} + } // namespace drivers diff --git a/src/system_fsm/CMakeLists.txt b/src/system_fsm/CMakeLists.txt index d59bd799..037e72c7 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" + SRCS "system_fsm.cpp" "running.cpp" "booting.cpp" "idle.cpp" INCLUDE_DIRS "include" REQUIRES "tinyfsm" "drivers" "database" "ui" "result" "events" "audio" "app_console") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index 6720fb4a..27f2b9c9 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -94,13 +94,11 @@ auto Booting::exit() -> void { auto Booting::react(const BootComplete& ev) -> void { ESP_LOGI(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->GetUsbStatus() == drivers::Samd::UsbStatus::kAttachedMounted) { - transit(); + if (sGpios->Get(drivers::Gpios::Pin::kKeyLock)) { + transit(); + } else { + transit(); } - transit(); } } // namespace states diff --git a/src/system_fsm/include/system_events.hpp b/src/system_fsm/include/system_events.hpp index 87461f0b..f62da801 100644 --- a/src/system_fsm/include/system_events.hpp +++ b/src/system_fsm/include/system_events.hpp @@ -28,15 +28,7 @@ struct BootComplete : tinyfsm::Event {}; */ struct FatalError : tinyfsm::Event {}; -/* - * Sent before unmounting the system storage. Storage will not be unmounted - * until each reaction to this even has returned. FSMs should immediately cease - * their usage of storage. - * - * May be emitted either by UiState in response to user action, or by SysState - * as a part of either entering low-power standby or powering off. - */ -struct StorageUnmountRequested : tinyfsm::Event {}; +struct OnIdle : tinyfsm::Event {}; /* * Sent by SysState when the system storage has been successfully mounted. @@ -64,15 +56,11 @@ struct ChargingStatusChanged : tinyfsm::Event {}; namespace internal { -/* - * Sent when the actual unmount operation should be performed. Always dispatched - * by SysState in response to StoragePrepareToUnmount. - */ -struct ReadyToUnmount : tinyfsm::Event {}; - struct GpioInterrupt : tinyfsm::Event {}; struct SamdInterrupt : tinyfsm::Event {}; +struct IdleTimeout : tinyfsm::Event {}; + } // namespace internal } // namespace system_fsm diff --git a/src/system_fsm/include/system_fsm.hpp b/src/system_fsm/include/system_fsm.hpp index b31cc6b7..0698be9b 100644 --- a/src/system_fsm/include/system_fsm.hpp +++ b/src/system_fsm/include/system_fsm.hpp @@ -22,6 +22,9 @@ #include "tinyfsm.hpp" #include "touchwheel.hpp" +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" + #include "system_events.hpp" #include "track_queue.hpp" @@ -47,10 +50,10 @@ class SystemState : public tinyfsm::Fsm { virtual void react(const DisplayReady&) {} virtual void react(const BootComplete&) {} - virtual void react(const StorageUnmountRequested&) {} - virtual void react(const internal::ReadyToUnmount&) {} virtual void react(const StorageMounted&) {} virtual void react(const StorageError&) {} + virtual void react(const KeyLockChanged&) {} + virtual void react(const internal::IdleTimeout&) {} protected: static std::shared_ptr sGpios; @@ -95,13 +98,24 @@ class Running : public SystemState { void entry() override; void exit() override; - void react(const StorageUnmountRequested&) override; - void react(const internal::ReadyToUnmount&) override; + void react(const KeyLockChanged&) override; void react(const StorageError&) override; using SystemState::react; }; -class Unmounted : public SystemState {}; +class Idle : public SystemState { + public: + void entry() override; + void exit() override; + + void react(const KeyLockChanged&) override; + void react(const internal::IdleTimeout&) override; + + using SystemState::react; + + private: + TimerHandle_t sIdleTimeout; +}; /* * Something unrecoverably bad went wrong. Shows an error (if possible), awaits diff --git a/src/system_fsm/running.cpp b/src/system_fsm/running.cpp index 0e988193..9e250c9b 100644 --- a/src/system_fsm/running.cpp +++ b/src/system_fsm/running.cpp @@ -67,17 +67,15 @@ void Running::exit() { sStorage.reset(); } -void Running::react(const StorageUnmountRequested& ev) { - events::System().Dispatch(internal::ReadyToUnmount{}); -} - -void Running::react(const internal::ReadyToUnmount& ev) { - transit(); +void Running::react(const KeyLockChanged& ev) { + if (!ev.falling && audio::AudioState::is_in_state()) { + transit(); + } } void Running::react(const StorageError& ev) { ESP_LOGW(kTag, "error loading storage"); - transit(); + // TODO. } } // namespace states diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index 30b0be0c..1f83477d 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -10,6 +10,7 @@ #include "core/lv_obj.h" #include "display.hpp" #include "event_queue.hpp" +#include "gpios.hpp" #include "lvgl_task.hpp" #include "relative_wheel.hpp" #include "screen.hpp" @@ -92,7 +93,7 @@ namespace states { void Splash::exit() { if (sDisplay != nullptr) { - sDisplay->SetDisplayOn(true); + sDisplay->SetDisplayOn(sIGpios->Get(drivers::IGpios::Pin::kKeyLock)); } }