summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorailurux <ailuruxx@gmail.com>2023-08-28 14:59:52 +1000
committerailurux <ailuruxx@gmail.com>2023-08-28 14:59:52 +1000
commitdb601935c6145445467692c0a4ff2b81e27cf6ce (patch)
treee2eed4a38abd03f14dba504ce5e8dedee0da6a12 /src
parent6f4ace1dd4b9b34f95af1ba365b68624e209d147 (diff)
parent3a0c42f9240eedfbc6a1e94ad3a59c52664fb5b5 (diff)
downloadtangara-fw-db601935c6145445467692c0a4ff2b81e27cf6ce.tar.gz
Merge branch 'main' of git.sr.ht:~jacqueline/tangara-fw
Diffstat (limited to 'src')
-rw-r--r--src/audio/audio_fsm.cpp14
-rw-r--r--src/audio/include/audio_events.hpp4
-rw-r--r--src/audio/include/audio_fsm.hpp3
-rw-r--r--src/battery/CMakeLists.txt10
-rw-r--r--src/battery/battery.cpp101
-rw-r--r--src/battery/include/battery.hpp44
-rw-r--r--src/drivers/CMakeLists.txt2
-rw-r--r--src/drivers/adc.cpp (renamed from src/drivers/battery.cpp)38
-rw-r--r--src/drivers/include/adc.hpp (renamed from src/drivers/include/battery.hpp)16
-rw-r--r--src/system_fsm/CMakeLists.txt2
-rw-r--r--src/system_fsm/booting.cpp24
-rw-r--r--src/system_fsm/idle.cpp14
-rw-r--r--src/system_fsm/include/system_events.hpp4
-rw-r--r--src/system_fsm/include/system_fsm.hpp10
-rw-r--r--src/system_fsm/running.cpp9
-rw-r--r--src/system_fsm/system_fsm.cpp14
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/include/screen_settings.hpp29
-rw-r--r--src/ui/include/ui_fsm.hpp8
-rw-r--r--src/ui/screen_playing.cpp8
-rw-r--r--src/ui/ui_fsm.cpp16
-rw-r--r--src/ui/widget_top_bar.cpp23
22 files changed, 283 insertions, 112 deletions
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp
index e68eedaf..6cca8211 100644
--- a/src/audio/audio_fsm.cpp
+++ b/src/audio/audio_fsm.cpp
@@ -133,6 +133,12 @@ void Standby::react(const QueueUpdate& ev) {
sFileSource->SetPath(db->GetTrackPath(*current_track));
}
+void Standby::react(const TogglePlayPause& ev) {
+ if (sCurrentTrack) {
+ transit<Playback>();
+ }
+}
+
void Playback::entry() {
ESP_LOGI(kTag, "beginning playback");
sOutput->SetInUse(true);
@@ -142,8 +148,10 @@ void Playback::exit() {
ESP_LOGI(kTag, "finishing playback");
// TODO(jacqueline): Second case where it's useful to wait for the i2s buffer
// to drain.
- vTaskDelay(pdMS_TO_TICKS(250));
+ vTaskDelay(pdMS_TO_TICKS(10));
sOutput->SetInUse(false);
+
+ events::System().Dispatch(PlaybackFinished{});
}
void Playback::react(const QueueUpdate& ev) {
@@ -168,6 +176,10 @@ void Playback::react(const QueueUpdate& ev) {
sFileSource->SetPath(db->GetTrackPath(*current_track));
}
+void Playback::react(const TogglePlayPause& ev) {
+ transit<Standby>();
+}
+
void Playback::react(const PlaybackUpdate& ev) {
ESP_LOGI(kTag, "elapsed: %lu, total: %lu", ev.seconds_elapsed,
ev.seconds_total);
diff --git a/src/audio/include/audio_events.hpp b/src/audio/include/audio_events.hpp
index 28e29863..8ee8b057 100644
--- a/src/audio/include/audio_events.hpp
+++ b/src/audio/include/audio_events.hpp
@@ -25,6 +25,8 @@ struct PlaybackUpdate : tinyfsm::Event {
uint32_t seconds_total;
};
+struct PlaybackFinished : tinyfsm::Event {};
+
struct QueueUpdate : tinyfsm::Event {
bool current_changed;
};
@@ -35,6 +37,8 @@ struct PlayFile : tinyfsm::Event {
struct VolumeChanged : tinyfsm::Event {};
+struct TogglePlayPause : tinyfsm::Event {};
+
namespace internal {
struct InputFileOpened : tinyfsm::Event {};
diff --git a/src/audio/include/audio_fsm.hpp b/src/audio/include/audio_fsm.hpp
index 430bc298..cfa65551 100644
--- a/src/audio/include/audio_fsm.hpp
+++ b/src/audio/include/audio_fsm.hpp
@@ -57,6 +57,7 @@ class AudioState : public tinyfsm::Fsm<AudioState> {
virtual void react(const PlayFile&) {}
virtual void react(const QueueUpdate&) {}
virtual void react(const PlaybackUpdate&) {}
+ virtual void react(const TogglePlayPause&) {}
virtual void react(const internal::InputFileOpened&) {}
virtual void react(const internal::InputFileClosed&) {}
@@ -90,6 +91,7 @@ class Standby : public AudioState {
void react(const PlayFile&) override;
void react(const internal::InputFileOpened&) override;
void react(const QueueUpdate&) override;
+ void react(const TogglePlayPause&) override;
using AudioState::react;
};
@@ -102,6 +104,7 @@ class Playback : public AudioState {
void react(const PlayFile&) override;
void react(const QueueUpdate&) override;
void react(const PlaybackUpdate&) override;
+ void react(const TogglePlayPause&) override;
void react(const internal::InputFileOpened&) override;
void react(const internal::InputFileClosed&) override;
diff --git a/src/battery/CMakeLists.txt b/src/battery/CMakeLists.txt
new file mode 100644
index 00000000..313a3731
--- /dev/null
+++ b/src/battery/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright 2023 jacqueline <me@jacqueline.id.au>
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+idf_component_register(
+ SRCS "battery.cpp"
+ INCLUDE_DIRS "include"
+ REQUIRES "drivers" "events")
+
+target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/battery/battery.cpp b/src/battery/battery.cpp
new file mode 100644
index 00000000..d73f4f29
--- /dev/null
+++ b/src/battery/battery.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "battery.hpp"
+
+#include <cstdint>
+
+#include "adc.hpp"
+#include "event_queue.hpp"
+#include "freertos/portmacro.h"
+#include "samd.hpp"
+#include "system_events.hpp"
+
+namespace battery {
+
+static const TickType_t kBatteryCheckPeriod = pdMS_TO_TICKS(60 * 1000);
+
+/*
+ * Battery voltage, in millivolts, at which the battery charger IC will stop
+ * charging.
+ */
+static const uint32_t kFullChargeMilliVolts = 4200;
+
+/*
+ * Battery voltage, in millivolts, at which *we* will consider the battery to
+ * be completely discharged. This is intentionally higher than the charger IC
+ * cut-off and the protection on the battery itself; we want to make sure we
+ * finish up and have everything unmounted and snoozing before the BMS cuts us
+ * off.
+ */
+static const uint32_t kEmptyChargeMilliVolts = 3200; // BMS limit is 3100.
+
+using ChargeStatus = drivers::Samd::ChargeStatus;
+
+void check_voltage_cb(TimerHandle_t timer) {
+ Battery* instance = reinterpret_cast<Battery*>(pvTimerGetTimerID(timer));
+ instance->Update();
+}
+
+Battery::Battery(drivers::Samd* samd, drivers::AdcBattery* adc)
+ : samd_(samd), adc_(adc) {
+ timer_ = xTimerCreate("BATTERY", kBatteryCheckPeriod, true, this,
+ check_voltage_cb);
+ xTimerStart(timer_, portMAX_DELAY);
+ Update();
+}
+
+Battery::~Battery() {
+ xTimerStop(timer_, portMAX_DELAY);
+ xTimerDelete(timer_, portMAX_DELAY);
+}
+
+auto Battery::Update() -> void {
+ std::lock_guard<std::mutex> lock{state_mutex_};
+
+ auto charge_state = samd_->GetChargeStatus();
+ if (!charge_state || *charge_state == ChargeStatus::kNoBattery) {
+ if (state_) {
+ EmitEvent();
+ }
+ state_.reset();
+ return;
+ }
+ // FIXME: So what we *should* do here is measure the actual real-life
+ // time from full battery -> empty battery, store it in NVS, then rely on
+ // that. If someone could please do this, it would be lovely. Thanks!
+ uint32_t mV = std::max(adc_->Millivolts(), kEmptyChargeMilliVolts);
+ uint_fast8_t percent = static_cast<uint_fast8_t>(std::min<double>(
+ std::max<double>(0.0, mV - kEmptyChargeMilliVolts) /
+ (kFullChargeMilliVolts - kEmptyChargeMilliVolts) * 100.0,
+ 100.0));
+
+ bool is_charging = *charge_state == ChargeStatus::kChargingRegular ||
+ *charge_state == ChargeStatus::kChargingFast ||
+ *charge_state == ChargeStatus::kFullCharge;
+
+ if (!state_ || state_->is_charging != is_charging ||
+ state_->percent != percent) {
+ EmitEvent();
+ }
+
+ state_ = BatteryState{
+ .percent = percent,
+ .is_charging = is_charging,
+ };
+}
+
+auto Battery::State() -> std::optional<BatteryState> {
+ std::lock_guard<std::mutex> lock{state_mutex_};
+ return state_;
+}
+
+auto Battery::EmitEvent() -> void {
+ events::System().Dispatch(system_fsm::BatteryStateChanged{});
+ events::Ui().Dispatch(system_fsm::BatteryStateChanged{});
+}
+
+} // namespace battery
diff --git a/src/battery/include/battery.hpp b/src/battery/include/battery.hpp
new file mode 100644
index 00000000..dcb9b4ea
--- /dev/null
+++ b/src/battery/include/battery.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/timers.h"
+
+#include "adc.hpp"
+#include "samd.hpp"
+
+namespace battery {
+
+class Battery {
+ public:
+ Battery(drivers::Samd* samd, drivers::AdcBattery* adc);
+ ~Battery();
+
+ auto Update() -> void;
+
+ struct BatteryState {
+ uint_fast8_t percent;
+ bool is_charging;
+ };
+
+ auto State() -> std::optional<BatteryState>;
+
+ private:
+ auto EmitEvent() -> void;
+
+ drivers::Samd* samd_;
+ drivers::AdcBattery* adc_;
+
+ TimerHandle_t timer_;
+ std::mutex state_mutex_;
+ std::optional<BatteryState> state_;
+};
+
+} // namespace battery
diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt
index a64495f0..1df58f72 100644
--- a/src/drivers/CMakeLists.txt
+++ b/src/drivers/CMakeLists.txt
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
- SRCS "touchwheel.cpp" "i2s_dac.cpp" "gpios.cpp" "battery.cpp" "storage.cpp" "i2c.cpp"
+ SRCS "touchwheel.cpp" "i2s_dac.cpp" "gpios.cpp" "adc.cpp" "storage.cpp" "i2c.cpp"
"spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "relative_wheel.cpp" "wm8523.cpp"
"nvs.cpp" "bluetooth.cpp"
INCLUDE_DIRS "include"
diff --git a/src/drivers/battery.cpp b/src/drivers/adc.cpp
index 1755fd64..56d2cbb4 100644
--- a/src/drivers/battery.cpp
+++ b/src/drivers/adc.cpp
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-only
*/
-#include "battery.hpp"
+#include "adc.hpp"
#include <cstdint>
#include "esp_adc/adc_cali.h"
@@ -14,21 +14,6 @@
namespace drivers {
-/*
- * Battery voltage, in millivolts, at which the battery charger IC will stop
- * charging.
- */
-static const uint32_t kFullChargeMilliVolts = 4200;
-
-/*
- * Battery voltage, in millivolts, at which *we* will consider the battery to
- * be completely discharged. This is intentionally higher than the charger IC
- * cut-off and the protection on the battery itself; we want to make sure we
- * finish up and have everything unmounted and snoozing before the BMS cuts us
- * off.
- */
-static const uint32_t kEmptyChargeMilliVolts = 3200; // BMS limit is 3100.
-
static const adc_bitwidth_t kAdcBitWidth = ADC_BITWIDTH_12;
static const adc_unit_t kAdcUnit = ADC_UNIT_1;
// Max battery voltage should be a little over 2V due to our divider, so we need
@@ -37,7 +22,7 @@ static const adc_atten_t kAdcAttenuation = ADC_ATTEN_DB_11;
// Corresponds to SENSOR_VP.
static const adc_channel_t kAdcChannel = ADC_CHANNEL_0;
-Battery::Battery() {
+AdcBattery::AdcBattery() {
adc_oneshot_unit_init_cfg_t unit_config = {
.unit_id = kAdcUnit,
};
@@ -59,16 +44,14 @@ Battery::Battery() {
};
ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(
&calibration_config, &adc_calibration_handle_));
-
- UpdatePercent();
}
-Battery::~Battery() {
+AdcBattery::~AdcBattery() {
adc_cali_delete_scheme_line_fitting(adc_calibration_handle_);
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_));
}
-auto Battery::Millivolts() -> uint32_t {
+auto AdcBattery::Millivolts() -> uint32_t {
// GPIO 34
int raw = 0;
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, kAdcChannel, &raw));
@@ -81,17 +64,4 @@ auto Battery::Millivolts() -> uint32_t {
return voltage * 2;
}
-auto Battery::UpdatePercent() -> bool {
- auto old_percent = percent_;
- // FIXME: So what we *should* do here is measure the actual real-life
- // time from full battery -> empty battery, store it in NVS, then rely on
- // that. If someone could please do this, it would be lovely. Thanks!
- uint32_t mV = std::max(Millivolts(), kEmptyChargeMilliVolts);
- percent_ = static_cast<uint_fast8_t>(std::min<double>(
- std::max<double>(0.0, mV - kEmptyChargeMilliVolts) /
- (kFullChargeMilliVolts - kEmptyChargeMilliVolts) * 100.0,
- 100.0));
- return old_percent != percent_;
-}
-
} // namespace drivers
diff --git a/src/drivers/include/battery.hpp b/src/drivers/include/adc.hpp
index 64a00135..3e94a9ee 100644
--- a/src/drivers/include/battery.hpp
+++ b/src/drivers/include/adc.hpp
@@ -15,25 +15,23 @@
namespace drivers {
-class Battery {
+/*
+ * Handles measuring the battery's current voltage.
+ */
+class AdcBattery {
public:
- static auto Create() -> Battery* { return new Battery(); }
- Battery();
- ~Battery();
+ static auto Create() -> AdcBattery* { return new AdcBattery(); }
+ AdcBattery();
+ ~AdcBattery();
/**
* Returns the current battery level in millivolts.
*/
auto Millivolts() -> uint32_t;
- auto UpdatePercent() -> bool;
- auto Percent() -> uint_fast8_t { return percent_; }
-
private:
adc_oneshot_unit_handle_t adc_handle_;
adc_cali_handle_t adc_calibration_handle_;
-
- uint_fast8_t percent_;
};
} // namespace drivers
diff --git a/src/system_fsm/CMakeLists.txt b/src/system_fsm/CMakeLists.txt
index 037e72c7..fced4093 100644
--- a/src/system_fsm/CMakeLists.txt
+++ b/src/system_fsm/CMakeLists.txt
@@ -5,5 +5,5 @@
idf_component_register(
SRCS "system_fsm.cpp" "running.cpp" "booting.cpp" "idle.cpp"
INCLUDE_DIRS "include"
- REQUIRES "tinyfsm" "drivers" "database" "ui" "result" "events" "audio" "app_console")
+ 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 33ed39d1..f33d1679 100644
--- a/src/system_fsm/booting.cpp
+++ b/src/system_fsm/booting.cpp
@@ -38,12 +38,6 @@ namespace states {
static const char kTag[] = "BOOT";
-static const TickType_t kBatteryCheckPeriod = pdMS_TO_TICKS(60 * 1000);
-
-static void battery_timer_cb(TimerHandle_t timer) {
- events::System().Dispatch(internal::BatteryTimerFired{});
-}
-
auto Booting::entry() -> void {
ESP_LOGI(kTag, "beginning tangara boot");
ESP_LOGI(kTag, "installing early drivers");
@@ -53,33 +47,31 @@ auto Booting::entry() -> void {
ESP_ERROR_CHECK(drivers::init_spi());
sGpios.reset(drivers::Gpios::Create());
+ sSamd.reset(drivers::Samd::Create());
+ sAdc.reset(drivers::AdcBattery::Create());
+ assert(sSamd.get() && sAdc.get());
+
+ 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(), sTrackQueue.get())) {
+ if (!ui::UiState::Init(sGpios.get(), sTrackQueue.get(), sBattery)) {
events::System().Dispatch(FatalError{});
return;
}
// Install everything else that is certain to be needed.
ESP_LOGI(kTag, "installing remaining drivers");
- sSamd.reset(drivers::Samd::Create());
- sBattery.reset(drivers::Battery::Create());
sNvs.reset(drivers::NvsStorage::Open());
sTagParser.reset(new database::TagParserImpl());
- if (!sSamd || !sBattery || !sNvs) {
+ if (!sNvs) {
events::System().Dispatch(FatalError{});
events::Ui().Dispatch(FatalError{});
return;
}
- ESP_LOGI(kTag, "battery is at %u%% (= %lu mV)", sBattery->Percent(),
- sBattery->Millivolts());
- TimerHandle_t battery_timer = xTimerCreate("battery", kBatteryCheckPeriod,
- true, NULL, battery_timer_cb);
- xTimerStart(battery_timer, portMAX_DELAY);
-
// ESP_LOGI(kTag, "starting bluetooth");
// sBluetooth.reset(new drivers::Bluetooth(sNvs.get()));
// sBluetooth->Enable();
diff --git a/src/system_fsm/idle.cpp b/src/system_fsm/idle.cpp
index 91075fc6..7cc1fa39 100644
--- a/src/system_fsm/idle.cpp
+++ b/src/system_fsm/idle.cpp
@@ -49,12 +49,17 @@ void Idle::exit() {
}
void Idle::react(const KeyLockChanged& ev) {
- if (!ev.falling) {
+ if (ev.falling) {
transit<Running>();
}
}
void Idle::react(const internal::IdleTimeout& ev) {
+ if (!IdleCondition()) {
+ // Defensively ensure that we didn't miss an idle-ending event.
+ transit<Running>();
+ return;
+ }
ESP_LOGI(kTag, "system shutting down");
// FIXME: It would be neater to just free a bunch of our pointers, deinit the
@@ -79,7 +84,12 @@ void Idle::react(const internal::IdleTimeout& ev) {
sGpios->Flush();
- sSamd->PowerDown();
+ // 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();
+ vTaskDelay(pdMS_TO_TICKS(1000));
+ }
}
} // namespace states
diff --git a/src/system_fsm/include/system_events.hpp b/src/system_fsm/include/system_events.hpp
index 8a3ba5ec..64cbd393 100644
--- a/src/system_fsm/include/system_events.hpp
+++ b/src/system_fsm/include/system_events.hpp
@@ -53,7 +53,7 @@ struct HasPhonesChanged : tinyfsm::Event {
};
struct ChargingStatusChanged : tinyfsm::Event {};
-struct BatteryPercentChanged : tinyfsm::Event {};
+struct BatteryStateChanged : tinyfsm::Event {};
namespace internal {
@@ -62,8 +62,6 @@ struct SamdInterrupt : tinyfsm::Event {};
struct IdleTimeout : tinyfsm::Event {};
-struct BatteryTimerFired : 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 6baceca1..371e5527 100644
--- a/src/system_fsm/include/system_fsm.hpp
+++ b/src/system_fsm/include/system_fsm.hpp
@@ -9,6 +9,7 @@
#include <memory>
#include "app_console.hpp"
+#include "audio_events.hpp"
#include "battery.hpp"
#include "bluetooth.hpp"
#include "database.hpp"
@@ -47,23 +48,26 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
void react(const FatalError&);
void react(const internal::GpioInterrupt&);
void react(const internal::SamdInterrupt&);
- void react(const internal::BatteryTimerFired&);
virtual void react(const DisplayReady&) {}
virtual void react(const BootComplete&) {}
virtual void react(const StorageMounted&) {}
virtual void react(const StorageError&) {}
virtual void react(const KeyLockChanged&) {}
+ virtual void react(const audio::PlaybackFinished&) {}
virtual void react(const internal::IdleTimeout&) {}
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::Battery> sBattery;
+ 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;
@@ -101,6 +105,8 @@ class Running : public SystemState {
void react(const KeyLockChanged&) override;
void react(const StorageError&) override;
+ void react(const audio::PlaybackFinished&) override;
+
using SystemState::react;
};
diff --git a/src/system_fsm/running.cpp b/src/system_fsm/running.cpp
index 9e250c9b..3fc5493f 100644
--- a/src/system_fsm/running.cpp
+++ b/src/system_fsm/running.cpp
@@ -5,6 +5,7 @@
*/
#include "app_console.hpp"
+#include "audio_events.hpp"
#include "file_gatherer.hpp"
#include "freertos/projdefs.h"
#include "result.hpp"
@@ -68,7 +69,13 @@ void Running::exit() {
}
void Running::react(const KeyLockChanged& ev) {
- if (!ev.falling && audio::AudioState::is_in_state<audio::states::Standby>()) {
+ if (IdleCondition()) {
+ transit<Idle>();
+ }
+}
+
+void Running::react(const audio::PlaybackFinished& ev) {
+ if (IdleCondition()) {
transit<Idle>();
}
}
diff --git a/src/system_fsm/system_fsm.cpp b/src/system_fsm/system_fsm.cpp
index 78c4c53e..d21e8bcb 100644
--- a/src/system_fsm/system_fsm.cpp
+++ b/src/system_fsm/system_fsm.cpp
@@ -23,7 +23,8 @@ 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::Battery> SystemState::sBattery;
+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;
@@ -95,14 +96,9 @@ void SystemState::react(const internal::SamdInterrupt&) {
}
}
-void SystemState::react(const internal::BatteryTimerFired&) {
- ESP_LOGI(kTag, "checking battery");
- if (sBattery->UpdatePercent()) {
- ESP_LOGI(kTag, "battery now at %u%%", sBattery->Percent());
- BatteryPercentChanged ev{};
- events::Ui().Dispatch(ev);
- events::System().Dispatch(ev);
- }
+auto SystemState::IdleCondition() -> bool {
+ return !sGpios->Get(drivers::IGpios::Pin::kKeyLock) &&
+ audio::AudioState::is_in_state<audio::states::Standby>();
}
} // namespace system_fsm
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index fa3f2bc1..6b5c393a 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -9,5 +9,5 @@ idf_component_register(
"modal_progress.cpp" "modal.cpp" "modal_confirm.cpp" "screen_settings.cpp"
"splash.c" "font_fusion.c" "font_symbols.c"
INCLUDE_DIRS "include"
- REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer")
+ REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer" "battery")
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/ui/include/screen_settings.hpp b/src/ui/include/screen_settings.hpp
index ebc5bf7d..66124164 100644
--- a/src/ui/include/screen_settings.hpp
+++ b/src/ui/include/screen_settings.hpp
@@ -21,14 +21,15 @@ class Settings : public MenuScreen {
public:
Settings();
~Settings();
- private:
- std::shared_ptr<Screen> bluetooth_;
- std::shared_ptr<Screen> headphones_;
- std::shared_ptr<Screen> appearance_;
- std::shared_ptr<Screen> input_method_;
- std::shared_ptr<Screen> storage_;
- std::shared_ptr<Screen> firmware_update_;
- std::shared_ptr<Screen> about_;
+
+ private:
+ std::shared_ptr<Screen> bluetooth_;
+ std::shared_ptr<Screen> headphones_;
+ std::shared_ptr<Screen> appearance_;
+ std::shared_ptr<Screen> input_method_;
+ std::shared_ptr<Screen> storage_;
+ std::shared_ptr<Screen> firmware_update_;
+ std::shared_ptr<Screen> about_;
};
class Bluetooth : public MenuScreen {
@@ -36,32 +37,32 @@ class Bluetooth : public MenuScreen {
Bluetooth();
};
-class Headphones : public MenuScreen {
+class Headphones : public MenuScreen {
public:
Headphones();
};
-class Appearance : public MenuScreen {
+class Appearance : public MenuScreen {
public:
Appearance();
};
-class InputMethod : public MenuScreen {
+class InputMethod : public MenuScreen {
public:
InputMethod();
};
-class Storage : public MenuScreen {
+class Storage : public MenuScreen {
public:
Storage();
};
-class FirmwareUpdate : public MenuScreen {
+class FirmwareUpdate : public MenuScreen {
public:
FirmwareUpdate();
};
-class About : public MenuScreen {
+class About : public MenuScreen {
public:
About();
};
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index 80c01c68..8f1aa1bc 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -10,6 +10,7 @@
#include <stack>
#include "audio_events.hpp"
+#include "battery.hpp"
#include "relative_wheel.hpp"
#include "screen_playing.hpp"
#include "tinyfsm.hpp"
@@ -27,7 +28,9 @@ namespace ui {
class UiState : public tinyfsm::Fsm<UiState> {
public:
- static auto Init(drivers::IGpios*, audio::TrackQueue*) -> bool;
+ static auto Init(drivers::IGpios*,
+ audio::TrackQueue*,
+ std::shared_ptr<battery::Battery>) -> bool;
virtual ~UiState() {}
@@ -41,7 +44,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
/* Fallback event handler. Does nothing. */
void react(const tinyfsm::Event& ev) {}
- void react(const system_fsm::BatteryPercentChanged&);
+ void react(const system_fsm::BatteryStateChanged&);
virtual void react(const audio::PlaybackStarted&) {}
virtual void react(const audio::PlaybackUpdate&) {}
@@ -76,6 +79,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
static std::shared_ptr<drivers::TouchWheel> sTouchWheel;
static std::shared_ptr<drivers::RelativeWheel> sRelativeWheel;
static std::shared_ptr<drivers::Display> sDisplay;
+ static std::shared_ptr<battery::Battery> sBattery;
static std::weak_ptr<database::Database> sDb;
static std::stack<std::shared_ptr<Screen>> sScreens;
diff --git a/src/ui/screen_playing.cpp b/src/ui/screen_playing.cpp
index ce0f71d6..7538d093 100644
--- a/src/ui/screen_playing.cpp
+++ b/src/ui/screen_playing.cpp
@@ -8,6 +8,7 @@
#include <sys/_stdint.h>
#include <memory>
+#include "audio_events.hpp"
#include "core/lv_event.h"
#include "core/lv_obj.h"
#include "core/lv_obj_scroll.h"
@@ -63,6 +64,10 @@ static void below_fold_focus_cb(lv_event_t* ev) {
instance->OnFocusBelowFold();
}
+static void play_pause_cb(lv_event_t* ev) {
+ events::Audio().Dispatch(audio::TogglePlayPause{});
+}
+
static lv_style_t scrubber_style;
auto info_label(lv_obj_t* parent) -> lv_obj_t* {
@@ -159,7 +164,10 @@ Playing::Playing(std::weak_ptr<database::Database> db, audio::TrackQueue* queue)
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
play_pause_control_ = control_button(controls_container, LV_SYMBOL_PLAY);
+ lv_obj_add_event_cb(play_pause_control_, play_pause_cb, LV_EVENT_CLICKED,
+ NULL);
lv_group_add_obj(group_, play_pause_control_);
+
lv_group_add_obj(group_, control_button(controls_container, LV_SYMBOL_PREV));
lv_group_add_obj(group_, control_button(controls_container, LV_SYMBOL_NEXT));
lv_group_add_obj(group_,
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index 508fb740..32032978 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -8,6 +8,7 @@
#include <memory>
+#include "battery.hpp"
#include "core/lv_obj.h"
#include "misc/lv_gc.h"
@@ -43,16 +44,19 @@ audio::TrackQueue* UiState::sQueue;
std::shared_ptr<drivers::TouchWheel> UiState::sTouchWheel;
std::shared_ptr<drivers::RelativeWheel> UiState::sRelativeWheel;
std::shared_ptr<drivers::Display> UiState::sDisplay;
+std::shared_ptr<battery::Battery> UiState::sBattery;
std::weak_ptr<database::Database> UiState::sDb;
std::stack<std::shared_ptr<Screen>> UiState::sScreens;
std::shared_ptr<Screen> UiState::sCurrentScreen;
std::shared_ptr<Modal> UiState::sCurrentModal;
-auto UiState::Init(drivers::IGpios* gpio_expander, audio::TrackQueue* queue)
- -> bool {
+auto UiState::Init(drivers::IGpios* gpio_expander,
+ audio::TrackQueue* queue,
+ std::shared_ptr<battery::Battery> battery) -> bool {
sIGpios = gpio_expander;
sQueue = queue;
+ sBattery = battery;
lv_init();
sDisplay.reset(
@@ -100,15 +104,17 @@ void UiState::react(const system_fsm::KeyLockChanged& ev) {
sRelativeWheel->SetEnabled(ev.falling);
}
-void UiState::react(const system_fsm::BatteryPercentChanged&) {
+void UiState::react(const system_fsm::BatteryStateChanged&) {
UpdateTopBar();
}
void UiState::UpdateTopBar() {
+ auto battery_state = sBattery->State();
widgets::TopBar::State state{
.playback_state = widgets::TopBar::PlaybackState::kIdle,
- .battery_percent = 50,
- .is_charging = true,
+ .battery_percent = static_cast<uint_fast8_t>(
+ battery_state.has_value() ? battery_state->percent : 100),
+ .is_charging = !battery_state.has_value() || battery_state->is_charging,
};
if (sCurrentScreen) {
sCurrentScreen->UpdateTopBar(state);
diff --git a/src/ui/widget_top_bar.cpp b/src/ui/widget_top_bar.cpp
index 458038a2..24c5e5bd 100644
--- a/src/ui/widget_top_bar.cpp
+++ b/src/ui/widget_top_bar.cpp
@@ -68,17 +68,18 @@ auto TopBar::Update(const State& state) -> void {
break;
}
- if (state.battery_percent >= 95) {
- lv_label_set_text(battery_, "100");
- } else if (state.battery_percent >= 70) {
- lv_label_set_text(battery_, ">70");
- } else if (state.battery_percent >= 40) {
- lv_label_set_text(battery_, ">40");
- } else if (state.battery_percent >= 10) {
- lv_label_set_text(battery_, ">10");
- } else {
- lv_label_set_text(battery_, "0");
- }
+ lv_label_set_text(battery_, std::to_string(state.battery_percent).c_str());
+ // if (state.battery_percent >= 95) {
+ // lv_label_set_text(battery_, "100");
+ // } else if (state.battery_percent >= 70) {
+ // lv_label_set_text(battery_, ">70");
+ // } else if (state.battery_percent >= 40) {
+ // lv_label_set_text(battery_, ">40");
+ // } else if (state.battery_percent >= 10) {
+ // lv_label_set_text(battery_, ">10");
+ // } else {
+ // lv_label_set_text(battery_, "0");
+ // }
}
} // namespace widgets