store the screen brightness in nvs
This commit is contained in:
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
|
||||
explicit NvsStorage(nvs_handle_t);
|
||||
auto ScreenBrightness() -> std::future<uint_fast8_t>;
|
||||
auto ScreenBrightness(uint_fast8_t) -> std::future<bool>;
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
|
||||
+89
-46
@@ -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) -> void {
|
||||
nvs_set_u8(handle_, kKeyOutput, static_cast<uint8_t>(out));
|
||||
nvs_commit(handle_);
|
||||
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::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
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -42,6 +42,7 @@ enum class Type {
|
||||
kDatabase,
|
||||
// Task for internal database operations
|
||||
kDatabaseBackground,
|
||||
kNvsWriter,
|
||||
};
|
||||
|
||||
template <Type t>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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") {
|
||||
|
||||
+9
-5
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user