summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-08-29 16:07:56 +1000
committerjacqueline <me@jacqueline.id.au>2023-08-29 16:07:56 +1000
commit4247c9fe7d25c921fbfc73fc50e849c8780e7ad6 (patch)
treeb8288c7772010edfb4a398596bef8fd35b771a95
parent773f2857678727f416a67a3a5ae71bd5b6761078 (diff)
downloadtangara-fw-4247c9fe7d25c921fbfc73fc50e849c8780e7ad6.tar.gz
store the screen brightness in nvs
-rw-r--r--src/drivers/bluetooth.cpp4
-rw-r--r--src/drivers/include/nvs.hpp25
-rw-r--r--src/drivers/nvs.cpp135
-rw-r--r--src/system_fsm/booting.cpp2
-rw-r--r--src/tasks/tasks.cpp21
-rw-r--r--src/tasks/tasks.hpp1
-rw-r--r--src/ui/include/screen_settings.hpp2
-rw-r--r--src/ui/include/themes.hpp6
-rw-r--r--src/ui/screen_settings.cpp28
-rw-r--r--src/ui/themes.cpp14
-rw-r--r--src/ui/ui_fsm.cpp1
11 files changed, 168 insertions, 71 deletions
diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp
index f6992f05..f3373849 100644
--- a/src/drivers/bluetooth.cpp
+++ b/src/drivers/bluetooth.cpp
@@ -120,7 +120,7 @@ std::atomic<StreamBufferHandle_t> BluetoothState::sSource_;
auto BluetoothState::Init(NvsStorage* storage) -> void {
sStorage_ = storage;
- sPreferredDevice_ = storage->PreferredBluetoothDevice();
+ sPreferredDevice_ = storage->PreferredBluetoothDevice().get();
tinyfsm::FsmList<bluetooth::BluetoothState>::start();
}
@@ -428,7 +428,7 @@ void Connecting::react(const events::internal::A2dp& ev) {
void Connected::entry() {
ESP_LOGI(kTag, "entering connected state");
- auto stored_pref = sStorage_->PreferredBluetoothDevice();
+ auto stored_pref = sStorage_->PreferredBluetoothDevice().get();
if (stored_pref != sPreferredDevice_) {
sStorage_->PreferredBluetoothDevice(sPreferredDevice_);
}
diff --git a/src/drivers/include/nvs.hpp b/src/drivers/include/nvs.hpp
index 913ad51e..bc88f88d 100644
--- a/src/drivers/include/nvs.hpp
+++ b/src/drivers/include/nvs.hpp
@@ -7,35 +7,44 @@
#pragma once
#include <stdint.h>
+#include <memory>
#include <optional>
#include "esp_err.h"
#include "nvs.h"
#include "bluetooth_types.hpp"
+#include "tasks.hpp"
namespace drivers {
class NvsStorage {
public:
- static auto Open() -> NvsStorage*;
+ static auto OpenSync() -> NvsStorage*;
- auto SchemaVersion() -> uint8_t;
-
- auto PreferredBluetoothDevice() -> std::optional<bluetooth::mac_addr_t>;
- auto PreferredBluetoothDevice(std::optional<bluetooth::mac_addr_t>) -> void;
+ auto PreferredBluetoothDevice()
+ -> std::future<std::optional<bluetooth::mac_addr_t>>;
+ auto PreferredBluetoothDevice(std::optional<bluetooth::mac_addr_t>)
+ -> std::future<bool>;
enum class Output : uint8_t {
kHeadphones = 0,
kBluetooth = 1,
};
- auto OutputMode() -> Output;
- auto OutputMode(Output) -> void;
+ auto OutputMode() -> std::future<Output>;
+ auto OutputMode(Output) -> std::future<bool>;
+
+ auto ScreenBrightness() -> std::future<uint_fast8_t>;
+ auto ScreenBrightness(uint_fast8_t) -> std::future<bool>;
- explicit NvsStorage(nvs_handle_t);
+ explicit NvsStorage(std::unique_ptr<tasks::Worker>, nvs_handle_t);
~NvsStorage();
private:
+ auto DowngradeSchemaSync() -> bool;
+ auto SchemaVersionSync() -> uint8_t;
+
+ std::unique_ptr<tasks::Worker> writer_;
nvs_handle_t handle_;
};
diff --git a/src/drivers/nvs.cpp b/src/drivers/nvs.cpp
index d2110764..c2832bf4 100644
--- a/src/drivers/nvs.cpp
+++ b/src/drivers/nvs.cpp
@@ -6,14 +6,17 @@
#include "nvs.hpp"
#include <stdint.h>
+#include <sys/_stdint.h>
#include <cstdint>
#include <memory>
#include "bluetooth.hpp"
+#include "bluetooth_types.hpp"
#include "esp_log.h"
#include "nvs.h"
#include "nvs_flash.h"
+#include "tasks.hpp"
namespace drivers {
@@ -23,8 +26,9 @@ static constexpr uint8_t kSchemaVersion = 1;
static constexpr char kKeyVersion[] = "ver";
static constexpr char kKeyBluetooth[] = "bt";
static constexpr char kKeyOutput[] = "out";
+static constexpr char kKeyBrightness[] = "bright";
-auto NvsStorage::Open() -> NvsStorage* {
+auto NvsStorage::OpenSync() -> NvsStorage* {
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_LOGW(kTag, "partition needs initialisation");
@@ -42,73 +46,112 @@ auto NvsStorage::Open() -> NvsStorage* {
return nullptr;
}
- std::unique_ptr<NvsStorage> instance = std::make_unique<NvsStorage>(handle);
- if (instance->SchemaVersion() < kSchemaVersion) {
- ESP_LOGW(kTag, "namespace needs downgrading");
- nvs_erase_all(handle);
- nvs_set_u8(handle, kKeyVersion, kSchemaVersion);
- err = nvs_commit(handle);
- if (err != ESP_OK) {
- ESP_LOGW(kTag, "failed to init namespace");
- return nullptr;
- }
+ std::unique_ptr<NvsStorage> instance = std::make_unique<NvsStorage>(
+ std::unique_ptr<tasks::Worker>(
+ tasks::Worker::Start<tasks::Type::kNvsWriter>()),
+ handle);
+ if (instance->SchemaVersionSync() < kSchemaVersion &&
+ !instance->DowngradeSchemaSync()) {
+ ESP_LOGW(kTag, "failed to init namespace");
+ return nullptr;
}
ESP_LOGI(kTag, "nvm storage initialised okay");
return instance.release();
}
-NvsStorage::NvsStorage(nvs_handle_t handle) : handle_(handle) {}
+NvsStorage::NvsStorage(std::unique_ptr<tasks::Worker> worker,
+ nvs_handle_t handle)
+ : writer_(std::move(worker)), handle_(handle) {}
NvsStorage::~NvsStorage() {
nvs_close(handle_);
nvs_flash_deinit();
}
-auto NvsStorage::SchemaVersion() -> uint8_t {
- uint8_t ret;
- if (nvs_get_u8(handle_, kKeyVersion, &ret) != ESP_OK) {
- return UINT8_MAX;
- }
- return ret;
+auto NvsStorage::DowngradeSchemaSync() -> bool {
+ ESP_LOGW(kTag, "namespace needs downgrading");
+ return writer_
+ ->Dispatch<bool>([&]() -> bool {
+ nvs_erase_all(handle_);
+ nvs_set_u8(handle_, kKeyVersion, kSchemaVersion);
+ return nvs_commit(handle_);
+ })
+ .get() == ESP_OK;
+}
+
+auto NvsStorage::SchemaVersionSync() -> uint8_t {
+ return writer_
+ ->Dispatch<uint8_t>([&]() -> uint8_t {
+ uint8_t ret;
+ if (nvs_get_u8(handle_, kKeyVersion, &ret) != ESP_OK) {
+ return UINT8_MAX;
+ }
+ return ret;
+ })
+ .get();
}
auto NvsStorage::PreferredBluetoothDevice()
- -> std::optional<bluetooth::mac_addr_t> {
- bluetooth::mac_addr_t out{0};
- size_t size = out.size();
- if (nvs_get_blob(handle_, kKeyBluetooth, out.data(), &size) != ESP_OK) {
- return {};
- }
- return out;
+ -> std::future<std::optional<bluetooth::mac_addr_t>> {
+ return writer_->Dispatch<std::optional<bluetooth::mac_addr_t>>(
+ [&]() -> std::optional<bluetooth::mac_addr_t> {
+ bluetooth::mac_addr_t out{0};
+ size_t size = out.size();
+ if (nvs_get_blob(handle_, kKeyBluetooth, out.data(), &size) != ESP_OK) {
+ return {};
+ }
+ return out;
+ });
}
auto NvsStorage::PreferredBluetoothDevice(
- std::optional<bluetooth::mac_addr_t> addr) -> void {
- if (!addr) {
- nvs_erase_key(handle_, kKeyBluetooth);
- } else {
- nvs_set_blob(handle_, kKeyBluetooth, addr.value().data(),
- addr.value().size());
- }
- nvs_commit(handle_);
+ std::optional<bluetooth::mac_addr_t> addr) -> std::future<bool> {
+ return writer_->Dispatch<bool>([&]() {
+ if (!addr) {
+ nvs_erase_key(handle_, kKeyBluetooth);
+ } else {
+ nvs_set_blob(handle_, kKeyBluetooth, addr.value().data(),
+ addr.value().size());
+ }
+ return nvs_commit(handle_) == ESP_OK;
+ });
}
-auto NvsStorage::OutputMode() -> Output {
- uint8_t out = 0;
- nvs_get_u8(handle_, kKeyOutput, &out);
- switch (out) {
- case static_cast<uint8_t>(Output::kBluetooth):
- return Output::kHeadphones;
- case static_cast<uint8_t>(Output::kHeadphones):
- default:
- return Output::kHeadphones;
- }
+auto NvsStorage::OutputMode() -> std::future<Output> {
+ return writer_->Dispatch<Output>([&]() -> Output {
+ uint8_t out = 0;
+ nvs_get_u8(handle_, kKeyOutput, &out);
+ switch (out) {
+ case static_cast<uint8_t>(Output::kBluetooth):
+ return Output::kHeadphones;
+ case static_cast<uint8_t>(Output::kHeadphones):
+ default:
+ return Output::kHeadphones;
+ }
+ });
+}
+
+auto NvsStorage::OutputMode(Output out) -> std::future<bool> {
+ return writer_->Dispatch<bool>([&]() {
+ nvs_set_u8(handle_, kKeyOutput, static_cast<uint8_t>(out));
+ return nvs_commit(handle_) == ESP_OK;
+ });
+}
+
+auto NvsStorage::ScreenBrightness() -> std::future<uint_fast8_t> {
+ return writer_->Dispatch<uint_fast8_t>([&]() -> uint_fast8_t {
+ uint8_t out = 50;
+ nvs_get_u8(handle_, kKeyBrightness, &out);
+ return out;
+ });
}
-auto NvsStorage::OutputMode(Output out) -> void {
- nvs_set_u8(handle_, kKeyOutput, static_cast<uint8_t>(out));
- nvs_commit(handle_);
+auto NvsStorage::ScreenBrightness(uint_fast8_t val) -> std::future<bool> {
+ return writer_->Dispatch<bool>([&]() {
+ nvs_set_u8(handle_, kKeyBrightness, val);
+ return nvs_commit(handle_) == ESP_OK;
+ });
}
} // namespace drivers
diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp
index cdbe4d55..a988c622 100644
--- a/src/system_fsm/booting.cpp
+++ b/src/system_fsm/booting.cpp
@@ -49,7 +49,7 @@ auto Booting::entry() -> void {
sSamd.reset(drivers::Samd::Create());
sAdc.reset(drivers::AdcBattery::Create());
- sNvs.reset(drivers::NvsStorage::Open());
+ sNvs.reset(drivers::NvsStorage::OpenSync());
assert(sSamd.get() && sAdc.get() && sNvs.get());
sBattery.reset(new battery::Battery(sSamd.get(), sAdc.get()));
diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp
index 493d6ba9..f7dc0279 100644
--- a/src/tasks/tasks.cpp
+++ b/src/tasks/tasks.cpp
@@ -45,6 +45,10 @@ template <>
auto Name<Type::kDatabaseBackground>() -> std::string {
return "DB_BG";
}
+template <>
+auto Name<Type::kNvsWriter>() -> std::string {
+ return "NVS";
+}
template <Type t>
auto AllocateStack() -> cpp::span<StackType_t>;
@@ -102,6 +106,13 @@ auto AllocateStack<Type::kDatabaseBackground>() -> cpp::span<StackType_t> {
return {static_cast<StackType_t*>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM)),
size};
}
+template <>
+auto AllocateStack<Type::kNvsWriter>() -> cpp::span<StackType_t> {
+ std::size_t size = 2 * 1024;
+ return {static_cast<StackType_t*>(
+ heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)),
+ size};
+}
// 2048 bytes in internal ram
// 302 KiB in external ram.
@@ -113,6 +124,12 @@ auto AllocateStack<Type::kDatabaseBackground>() -> cpp::span<StackType_t> {
template <Type t>
auto Priority() -> UBaseType_t;
+// NVS writing requires suspending one of our cores, and disabling tasks with
+// their stacks in PSRAM. Get it over and done with as soon as possible.
+template <>
+auto Priority<Type::kNvsWriter>() -> UBaseType_t {
+ return 13;
+}
// Realtime audio is the entire point of this device, so give this task the
// highest priority.
template <>
@@ -171,6 +188,10 @@ template <>
auto WorkerQueueSize<Type::kUiFlush>() -> std::size_t {
return 2;
}
+template <>
+auto WorkerQueueSize<Type::kNvsWriter>() -> std::size_t {
+ return 2;
+}
auto PersistentMain(void* fn) -> void {
auto* function = reinterpret_cast<std::function<void(void)>*>(fn);
diff --git a/src/tasks/tasks.hpp b/src/tasks/tasks.hpp
index a0c201d5..17836795 100644
--- a/src/tasks/tasks.hpp
+++ b/src/tasks/tasks.hpp
@@ -42,6 +42,7 @@ enum class Type {
kDatabase,
// Task for internal database operations
kDatabaseBackground,
+ kNvsWriter,
};
template <Type t>
diff --git a/src/ui/include/screen_settings.hpp b/src/ui/include/screen_settings.hpp
index 53d9277b..61375fa9 100644
--- a/src/ui/include/screen_settings.hpp
+++ b/src/ui/include/screen_settings.hpp
@@ -40,12 +40,14 @@ class Appearance : public MenuScreen {
Appearance(drivers::NvsStorage* nvs, drivers::Display* display);
auto ChangeBrightness(uint_fast8_t) -> void;
+ auto CommitBrightness() -> void;
private:
drivers::NvsStorage* nvs_;
drivers::Display* display_;
lv_obj_t* current_brightness_label_;
+ uint_fast8_t current_brightness_;
};
class InputMethod : public MenuScreen {
diff --git a/src/ui/include/themes.hpp b/src/ui/include/themes.hpp
index ef0e719c..ee4bb05d 100644
--- a/src/ui/include/themes.hpp
+++ b/src/ui/include/themes.hpp
@@ -5,13 +5,9 @@
namespace ui {
namespace themes {
- enum class Style {
- kMenuItem,
- kTopBar
- };
+enum class Style { kMenuItem, kTopBar };
class Theme {
public:
-
void Apply(void);
void Callback(lv_obj_t* obj);
void ApplyStyle(lv_obj_t* obj, Style style);
diff --git a/src/ui/screen_settings.cpp b/src/ui/screen_settings.cpp
index c496ce00..6bafb9a8 100644
--- a/src/ui/screen_settings.cpp
+++ b/src/ui/screen_settings.cpp
@@ -5,6 +5,7 @@
*/
#include "screen_settings.hpp"
+#include <string>
#include "core/lv_event.h"
#include "core/lv_obj.h"
@@ -151,6 +152,15 @@ static void change_brightness_cb(lv_event_t* ev) {
instance->ChangeBrightness(lv_slider_get_value(ev->target));
}
+static void release_brightness_cb(lv_event_t* ev) {
+ Appearance* instance = reinterpret_cast<Appearance*>(ev->user_data);
+ instance->CommitBrightness();
+}
+
+static auto brightness_str(uint_fast8_t percent) -> std::string {
+ return std::to_string(percent) + "%";
+}
+
Appearance::Appearance(drivers::NvsStorage* nvs, drivers::Display* display)
: MenuScreen("Appearance"), nvs_(nvs), display_(display) {
lv_obj_t* toggle_container = settings_container(content_);
@@ -160,25 +170,35 @@ Appearance::Appearance(drivers::NvsStorage* nvs, drivers::Display* display)
lv_obj_t* toggle = lv_switch_create(toggle_container);
lv_group_add_obj(group_, toggle);
+ uint_fast8_t initial_brightness = nvs_->ScreenBrightness().get();
+
lv_obj_t* brightness_label = lv_label_create(content_);
lv_label_set_text(brightness_label, "Brightness");
lv_obj_t* brightness = lv_slider_create(content_);
lv_obj_set_width(brightness, lv_pct(100));
lv_slider_set_range(brightness, 10, 100);
- lv_slider_set_value(brightness, 50, LV_ANIM_OFF);
+ lv_slider_set_value(brightness, initial_brightness, LV_ANIM_OFF);
lv_group_add_obj(group_, brightness);
current_brightness_label_ = lv_label_create(content_);
- lv_label_set_text(current_brightness_label_, "50%");
+ lv_label_set_text(current_brightness_label_,
+ brightness_str(initial_brightness).c_str());
lv_obj_set_size(current_brightness_label_, lv_pct(100), LV_SIZE_CONTENT);
lv_obj_add_event_cb(brightness, change_brightness_cb, LV_EVENT_VALUE_CHANGED,
this);
+ lv_obj_add_event_cb(brightness, release_brightness_cb, LV_EVENT_RELEASED,
+ this);
}
auto Appearance::ChangeBrightness(uint_fast8_t new_level) -> void {
+ current_brightness_ = new_level;
display_->SetBrightness(new_level);
- std::string new_str = std::to_string(new_level) + "%";
- lv_label_set_text(current_brightness_label_, new_str.c_str());
+ lv_label_set_text(current_brightness_label_,
+ brightness_str(new_level).c_str());
+}
+
+auto Appearance::CommitBrightness() -> void {
+ nvs_->ScreenBrightness(current_brightness_);
}
InputMethod::InputMethod() : MenuScreen("Input Method") {
diff --git a/src/ui/themes.cpp b/src/ui/themes.cpp
index dd9ef423..38bcd9fd 100644
--- a/src/ui/themes.cpp
+++ b/src/ui/themes.cpp
@@ -1,7 +1,7 @@
#include "themes.hpp"
#include "core/lv_obj.h"
-#include "misc/lv_color.h"
#include "esp_log.h"
+#include "misc/lv_color.h"
LV_FONT_DECLARE(font_fusion);
@@ -19,7 +19,8 @@ Theme::Theme() {
lv_style_set_bg_color(&button_style_, lv_color_white());
lv_style_init(&button_style_focused_);
- lv_style_set_bg_color(&button_style_focused_, lv_palette_lighten(LV_PALETTE_BLUE_GREY, 2));
+ lv_style_set_bg_color(&button_style_focused_,
+ lv_palette_lighten(LV_PALETTE_BLUE_GREY, 2));
lv_theme_t* parent_theme = lv_disp_get_theme(NULL);
theme_ = *parent_theme;
@@ -41,15 +42,18 @@ void Theme::Callback(lv_obj_t* obj) {
if (lv_obj_check_type(obj, &lv_btn_class) ||
lv_obj_check_type(obj, &lv_list_btn_class)) {
lv_obj_add_style(obj, &button_style_, LV_PART_MAIN);
- lv_obj_add_style(obj, &button_style_focused_, LV_PART_MAIN | LV_STATE_FOCUSED);
+ lv_obj_add_style(obj, &button_style_focused_,
+ LV_PART_MAIN | LV_STATE_FOCUSED);
}
}
void Theme::ApplyStyle(lv_obj_t* obj, Style style) {
if (style == Style::kTopBar) {
- lv_obj_set_style_border_color(obj, lv_palette_darken(LV_PALETTE_BLUE_GREY, 2), LV_PART_MAIN);
+ lv_obj_set_style_border_color(
+ obj, lv_palette_darken(LV_PALETTE_BLUE_GREY, 2), LV_PART_MAIN);
lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN);
- lv_obj_set_style_border_side(obj, LV_BORDER_SIDE_BOTTOM|LV_BORDER_SIDE_TOP, LV_PART_MAIN);
+ lv_obj_set_style_border_side(
+ obj, LV_BORDER_SIDE_BOTTOM | LV_BORDER_SIDE_TOP, LV_PART_MAIN);
lv_obj_set_style_pad_top(obj, 2, LV_PART_MAIN);
lv_obj_set_style_pad_bottom(obj, 2, LV_PART_MAIN);
}
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index 733b6bee..1febd1c7 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -69,6 +69,7 @@ auto UiState::Init(drivers::IGpios* gpio_expander,
if (sDisplay == nullptr) {
return false;
}
+ sDisplay->SetBrightness(nvs->ScreenBrightness().get());
sTouchWheel.reset(drivers::TouchWheel::Create());
if (sTouchWheel != nullptr) {