Add idle->standby support when locked and no music
This commit is contained in:
+14
-12
@@ -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));
|
||||
|
||||
// Ensure the DAC powers up to a muted state.
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
+2
-1
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user