summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-01-05 10:38:35 +1100
committerjacqueline <me@jacqueline.id.au>2024-01-05 10:38:35 +1100
commit34cae4e6e4bb00b3453bcdab084368a949c908a4 (patch)
tree024caadd70ea35ab2c73cc782f3a37c93a90702f /src
parent938ba62f57ed2c002bae4aec236eeaeb200e4cba (diff)
downloadtangara-fw-34cae4e6e4bb00b3453bcdab084368a949c908a4.tar.gz
add an alerts module for lua, and implement a volume indicator with it
Diffstat (limited to 'src')
-rw-r--r--src/audio/audio_fsm.cpp12
-rw-r--r--src/audio/i2s_audio_output.cpp1
-rw-r--r--src/audio/include/audio_events.hpp5
-rw-r--r--src/lua/stubs/alerts.lua13
-rw-r--r--src/lua/stubs/volume.lua14
-rw-r--r--src/ui/include/screen.hpp2
-rw-r--r--src/ui/include/ui_events.hpp8
-rw-r--r--src/ui/include/ui_fsm.hpp11
-rw-r--r--src/ui/screen.cpp4
-rw-r--r--src/ui/ui_fsm.cpp72
10 files changed, 134 insertions, 8 deletions
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp
index a5179156..a2f467cb 100644
--- a/src/audio/audio_fsm.cpp
+++ b/src/audio/audio_fsm.cpp
@@ -58,13 +58,19 @@ void AudioState::react(const system_fsm::KeyLockChanged& ev) {
void AudioState::react(const StepUpVolume& ev) {
if (sOutput->AdjustVolumeUp()) {
- events::Ui().Dispatch(VolumeChanged{});
+ events::Ui().Dispatch(VolumeChanged{
+ .percent = sOutput->GetVolumePct(),
+ .db = sOutput->GetVolumeDb(),
+ });
}
}
void AudioState::react(const StepDownVolume& ev) {
if (sOutput->AdjustVolumeDown()) {
- events::Ui().Dispatch(VolumeChanged{});
+ events::Ui().Dispatch(VolumeChanged{
+ .percent = sOutput->GetVolumePct(),
+ .db = sOutput->GetVolumeDb(),
+ });
}
}
@@ -77,7 +83,7 @@ void AudioState::react(const system_fsm::HasPhonesChanged& ev) {
}
void AudioState::react(const ChangeMaxVolume& ev) {
- ESP_LOGI(kTag, "new max volume %u db",
+ ESP_LOGI(kTag, "new max volume %i db",
(ev.new_max - drivers::wm8523::kLineLevelReferenceVolume) / 4);
sI2SOutput->SetMaxVolume(ev.new_max);
sServices->nvs().AmpMaxVolume(ev.new_max);
diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp
index 29d70fb5..4043574e 100644
--- a/src/audio/i2s_audio_output.cpp
+++ b/src/audio/i2s_audio_output.cpp
@@ -93,7 +93,6 @@ auto I2SAudioOutput::SetMaxVolume(uint16_t max) -> void {
auto I2SAudioOutput::SetVolume(uint16_t vol) -> void {
current_volume_ = std::clamp(vol, kMinVolume, max_volume_);
- ESP_LOGI(kTag, "set volume to %u%% = %idB", GetVolumePct(), GetVolumeDb());
int32_t left_unclamped = current_volume_ + left_difference_;
uint16_t left = std::clamp<int32_t>(left_unclamped, kMinVolume, max_volume_);
diff --git a/src/audio/include/audio_events.hpp b/src/audio/include/audio_events.hpp
index 68efcafb..3c5ab723 100644
--- a/src/audio/include/audio_events.hpp
+++ b/src/audio/include/audio_events.hpp
@@ -47,7 +47,10 @@ struct PlayFile : tinyfsm::Event {
struct StepUpVolume : tinyfsm::Event {};
struct StepDownVolume : tinyfsm::Event {};
-struct VolumeChanged : tinyfsm::Event {};
+struct VolumeChanged : tinyfsm::Event {
+ uint_fast8_t percent;
+ int db;
+};
struct ChangeMaxVolume : tinyfsm::Event {
uint16_t new_max;
};
diff --git a/src/lua/stubs/alerts.lua b/src/lua/stubs/alerts.lua
new file mode 100644
index 00000000..9b541d84
--- /dev/null
+++ b/src/lua/stubs/alerts.lua
@@ -0,0 +1,13 @@
+--- Module for interacting with playback volume. The Bluetooth and wired outputs store their current volume separately; this API only allows interacting with the volume of the currently used output device.
+-- @module alerts
+
+local alerts = {}
+
+--- Returns the current volume as a percentage of the current volume limit.
+-- @tparam function constructor Called to create the UI for the alert. A new default root object and group will be set before calling this function.i Alerts are non-interactable; the group created for the constructor will not be granted focus.
+function alerts.show(constructor) end
+
+--- Dismisses any visible alerts, removing them from the screen.
+function alerts.hide() end
+
+return alerts
diff --git a/src/lua/stubs/volume.lua b/src/lua/stubs/volume.lua
new file mode 100644
index 00000000..15499630
--- /dev/null
+++ b/src/lua/stubs/volume.lua
@@ -0,0 +1,14 @@
+--- Module for interacting with playback volume. The Bluetooth and wired outputs store their current volume separately; this API only allows interacting with the volume of the currently used output device.
+-- @module volume
+
+local volume = {}
+
+--- Returns the current volume as a percentage of the current volume limit.
+-- @treturn types.Property an integer property
+function volume.current_pct() end
+
+--- Returns the current volume in terms of dB from line level.
+-- @treturn types.Property an integer property
+function volume.current_db() end
+
+return volume
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
index e9eaeeb0..4fe0a3b7 100644
--- a/src/ui/include/screen.hpp
+++ b/src/ui/include/screen.hpp
@@ -40,6 +40,7 @@ class Screen {
auto root() -> lv_obj_t* { return root_; }
auto content() -> lv_obj_t* { return content_; }
+ auto alert() -> lv_obj_t* { return alert_; }
auto modal_content() -> lv_obj_t* { return modal_content_; }
auto modal_group(lv_group_t* g) -> void { modal_group_ = g; }
@@ -68,6 +69,7 @@ class Screen {
lv_obj_t* const root_;
lv_obj_t* content_;
lv_obj_t* modal_content_;
+ lv_obj_t* alert_;
lv_group_t* const group_;
lv_group_t* modal_group_;
diff --git a/src/ui/include/ui_events.hpp b/src/ui/include/ui_events.hpp
index 111f37a8..59be7606 100644
--- a/src/ui/include/ui_events.hpp
+++ b/src/ui/include/ui_events.hpp
@@ -24,9 +24,9 @@ struct OnStorageChange : tinyfsm::Event {
struct OnSystemError : tinyfsm::Event {};
- struct OnLuaError : tinyfsm::Event {
- std::string message;
- };
+struct OnLuaError : tinyfsm::Event {
+ std::string message;
+};
namespace internal {
@@ -54,6 +54,8 @@ struct OnboardingNavigate : tinyfsm::Event {
struct ModalConfirmPressed : tinyfsm::Event {};
struct ModalCancelPressed : tinyfsm::Event {};
+struct DismissAlerts : tinyfsm::Event {};
+
} // namespace internal
} // namespace ui
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index ba3f5e3f..33f9eac4 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -60,6 +60,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
virtual void react(const audio::PlaybackFinished&);
virtual void react(const audio::PlaybackUpdate&);
virtual void react(const audio::QueueUpdate&);
+ virtual void react(const audio::VolumeChanged&){};
virtual void react(const system_fsm::KeyLockChanged&);
virtual void react(const OnLuaError&) {}
@@ -76,6 +77,8 @@ class UiState : public tinyfsm::Fsm<UiState> {
void react(const internal::ControlSchemeChanged&);
virtual void react(const internal::ReindexDatabase&){};
+ void react(const internal::DismissAlerts&);
+
virtual void react(const database::event::UpdateStarted&){};
virtual void react(const database::event::UpdateProgress&){};
virtual void react(const database::event::UpdateFinished&){};
@@ -129,6 +132,7 @@ class Lua : public UiState {
void react(const audio::PlaybackStarted&) override;
void react(const audio::PlaybackUpdate&) override;
void react(const audio::PlaybackFinished&) override;
+ void react(const audio::VolumeChanged&) override;
void react(const internal::BackPressed&) override;
using UiState::react;
@@ -136,6 +140,10 @@ class Lua : public UiState {
private:
auto PushLuaScreen(lua_State*) -> int;
auto PopLuaScreen(lua_State*) -> int;
+
+ auto ShowAlert(lua_State*) -> int;
+ auto HideAlert(lua_State*) -> int;
+
auto SetPlaying(const lua::LuaValue&) -> bool;
auto SetRandom(const lua::LuaValue&) -> bool;
auto SetRepeat(const lua::LuaValue&) -> bool;
@@ -154,6 +162,9 @@ class Lua : public UiState {
std::shared_ptr<lua::Property> queue_size_;
std::shared_ptr<lua::Property> queue_repeat_;
std::shared_ptr<lua::Property> queue_random_;
+
+ std::shared_ptr<lua::Property> volume_current_pct_;
+ std::shared_ptr<lua::Property> volume_current_db_;
};
class Browse : public UiState {
diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp
index 0b0f7914..9ac5ec0e 100644
--- a/src/ui/screen.cpp
+++ b/src/ui/screen.cpp
@@ -10,6 +10,7 @@
#include "core/lv_obj_pos.h"
#include "core/lv_obj_tree.h"
+#include "hal/lv_hal_disp.h"
#include "misc/lv_area.h"
#include "misc/lv_color.h"
#include "model_top_bar.hpp"
@@ -21,14 +22,17 @@ Screen::Screen()
: root_(lv_obj_create(NULL)),
content_(lv_obj_create(root_)),
modal_content_(lv_obj_create(root_)),
+ alert_(lv_obj_create(root_)),
group_(lv_group_create()),
modal_group_(nullptr) {
lv_obj_set_size(root_, lv_pct(100), lv_pct(100));
lv_obj_set_size(content_, lv_pct(100), lv_pct(100));
lv_obj_set_size(modal_content_, lv_pct(100), lv_pct(100));
+ lv_obj_set_size(alert_, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_center(root_);
lv_obj_center(content_);
lv_obj_center(modal_content_);
+ lv_obj_center(alert_);
lv_obj_set_style_bg_opa(modal_content_, LV_OPA_TRANSP, 0);
lv_obj_set_style_bg_color(modal_content_, lv_color_black(), 0);
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index 8e355fd1..740383a4 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -9,6 +9,8 @@
#include <memory>
#include <variant>
+#include "freertos/portmacro.h"
+#include "freertos/projdefs.h"
#include "lua.h"
#include "lua.hpp"
@@ -44,6 +46,7 @@
#include "spiffs.hpp"
#include "storage.hpp"
#include "system_events.hpp"
+#include "tinyfsm.hpp"
#include "touchwheel.hpp"
#include "track_queue.hpp"
#include "ui_events.hpp"
@@ -70,6 +73,13 @@ models::TopBar UiState::sTopBarModel{{},
UiState::sPlaybackModel.is_playing,
UiState::sPlaybackModel.current_track};
+static TimerHandle_t sAlertTimer;
+static lv_obj_t* sAlertContainer;
+
+static void alert_timer_callback(TimerHandle_t timer) {
+ events::Ui().Dispatch(internal::DismissAlerts{});
+}
+
auto UiState::InitBootSplash(drivers::IGpios& gpios) -> bool {
// Init LVGL first, since the display driver registers itself with LVGL.
lv_init();
@@ -89,6 +99,7 @@ void UiState::PushScreen(std::shared_ptr<Screen> screen) {
sScreens.push(sCurrentScreen);
}
sCurrentScreen = screen;
+ lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
}
int UiState::PopScreen() {
@@ -96,6 +107,8 @@ int UiState::PopScreen() {
return 0;
}
sCurrentScreen = sScreens.top();
+ lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
+
sScreens.pop();
return sScreens.size();
}
@@ -127,6 +140,10 @@ void UiState::react(const internal::ControlSchemeChanged&) {
sInput->mode(sServices->nvs().PrimaryInput());
}
+void UiState::react(const internal::DismissAlerts&) {
+ lv_obj_clean(sAlertContainer);
+}
+
namespace states {
void Splash::exit() {
@@ -164,6 +181,10 @@ void Splash::react(const system_fsm::StorageMounted&) {
void Lua::entry() {
if (!sLua) {
+ sAlertTimer = xTimerCreate("ui_alerts", pdMS_TO_TICKS(1000), false, NULL,
+ alert_timer_callback);
+ sAlertContainer = lv_obj_create(sCurrentScreen->alert());
+
auto bat =
sServices->battery().State().value_or(battery::Battery::BatteryState{});
battery_pct_ =
@@ -184,6 +205,9 @@ void Lua::entry() {
playback_track_ = std::make_shared<lua::Property>();
playback_position_ = std::make_shared<lua::Property>();
+ volume_current_pct_ = std::make_shared<lua::Property>(0);
+ volume_current_db_ = std::make_shared<lua::Property>(0);
+
sLua.reset(lua::LuaThread::Start(*sServices, sCurrentScreen->content()));
sLua->bridge().AddPropertyModule("power",
{
@@ -208,12 +232,23 @@ void Lua::entry() {
{"replay", queue_repeat_},
{"random", queue_random_},
});
+ sLua->bridge().AddPropertyModule("volume",
+ {
+ {"current_pct", volume_current_pct_},
+ {"current_db", volume_current_db_},
+ });
+
sLua->bridge().AddPropertyModule(
"backstack",
{
{"push", [&](lua_State* s) { return PushLuaScreen(s); }},
{"pop", [&](lua_State* s) { return PopLuaScreen(s); }},
});
+ sLua->bridge().AddPropertyModule(
+ "alerts", {
+ {"show", [&](lua_State* s) { return ShowAlert(s); }},
+ {"hide", [&](lua_State* s) { return HideAlert(s); }},
+ });
sCurrentScreen.reset();
sLua->RunScript("/lua/main.lua");
@@ -265,6 +300,38 @@ auto Lua::SetPlaying(const lua::LuaValue& val) -> bool {
return true;
}
+auto Lua::ShowAlert(lua_State* s) -> int {
+ if (!sCurrentScreen) {
+ return 0;
+ }
+ xTimerReset(sAlertTimer, portMAX_DELAY);
+ tinyfsm::FsmList<UiState>::dispatch(internal::DismissAlerts{});
+
+ lv_group_t* prev_group = lv_group_get_default();
+
+ luavgl_set_root(s, sAlertContainer);
+ lv_group_t* catchall = lv_group_create();
+ lv_group_set_default(catchall);
+
+ // Call the constructor for the alert.
+ lua_settop(s, 1); // Make sure the function is actually at top of stack
+ lua::CallProtected(s, 0, 1);
+
+ // Restore the previous group and default object.
+ luavgl_set_root(s, sCurrentScreen->content());
+ lv_group_set_default(prev_group);
+
+ lv_group_del(catchall);
+
+ return 0;
+}
+
+auto Lua::HideAlert(lua_State* s) -> int {
+ xTimerStop(sAlertTimer, portMAX_DELAY);
+ tinyfsm::FsmList<UiState>::dispatch(internal::DismissAlerts{});
+ return 0;
+}
+
auto Lua::SetRandom(const lua::LuaValue& val) -> bool {
if (!std::holds_alternative<bool>(val)) {
return false;
@@ -327,6 +394,11 @@ void Lua::react(const audio::PlaybackFinished&) {
playback_playing_->Update(false);
}
+void Lua::react(const audio::VolumeChanged& ev) {
+ volume_current_pct_->Update(static_cast<int>(ev.percent));
+ volume_current_db_->Update(static_cast<int>(ev.db));
+}
+
void Lua::react(const internal::BackPressed& ev) {
PopLuaScreen(sLua->state());
}