Add idle->standby support when locked and no music

custom
jacqueline 2 years ago
parent 27f329a9db
commit 764b01e913
  1. 26
      src/drivers/i2s_dac.cpp
  2. 2
      src/drivers/include/touchwheel.hpp
  3. 6
      src/drivers/touchwheel.cpp
  4. 2
      src/system_fsm/CMakeLists.txt
  5. 10
      src/system_fsm/booting.cpp
  6. 18
      src/system_fsm/include/system_events.hpp
  7. 24
      src/system_fsm/include/system_fsm.hpp
  8. 12
      src/system_fsm/running.cpp
  9. 3
      src/ui/ui_fsm.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);

@ -35,6 +35,8 @@ class TouchWheel {
auto Update() -> void;
auto GetTouchWheelData() const -> TouchWheelData;
auto PowerDown() -> void;
private:
TouchWheelData data_;

@ -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

@ -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})

@ -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<Unmounted>();
if (sGpios->Get(drivers::Gpios::Pin::kKeyLock)) {
transit<Running>();
} else {
transit<Idle>();
}
transit<Running>();
}
} // namespace states

@ -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

@ -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<SystemState> {
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<drivers::Gpios> 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

@ -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<Unmounted>();
void Running::react(const KeyLockChanged& ev) {
if (!ev.falling && audio::AudioState::is_in_state<audio::states::Standby>()) {
transit<Idle>();
}
}
void Running::react(const StorageError& ev) {
ESP_LOGW(kTag, "error loading storage");
transit<Unmounted>();
// TODO.
}
} // namespace states

@ -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));
}
}

Loading…
Cancel
Save