store the screen brightness in nvs

custom
jacqueline 2 years ago
parent 773f285767
commit 4247c9fe7d
  1. 4
      src/drivers/bluetooth.cpp
  2. 25
      src/drivers/include/nvs.hpp
  3. 77
      src/drivers/nvs.cpp
  4. 2
      src/system_fsm/booting.cpp
  5. 21
      src/tasks/tasks.cpp
  6. 1
      src/tasks/tasks.hpp
  7. 2
      src/ui/include/screen_settings.hpp
  8. 6
      src/ui/include/themes.hpp
  9. 28
      src/ui/screen_settings.cpp
  10. 14
      src/ui/themes.cpp
  11. 1
      src/ui/ui_fsm.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_);
}

@ -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_;
};

@ -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,59 +46,80 @@ 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) {
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 {
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> {
-> 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 {
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());
}
nvs_commit(handle_);
return nvs_commit(handle_) == ESP_OK;
});
}
auto NvsStorage::OutputMode() -> Output {
auto NvsStorage::OutputMode() -> std::future<Output> {
return writer_->Dispatch<Output>([&]() -> Output {
uint8_t out = 0;
nvs_get_u8(handle_, kKeyOutput, &out);
switch (out) {
@ -104,11 +129,29 @@ auto NvsStorage::OutputMode() -> Output {
default:
return Output::kHeadphones;
}
});
}
auto NvsStorage::OutputMode(Output out) -> void {
auto NvsStorage::OutputMode(Output out) -> std::future<bool> {
return writer_->Dispatch<bool>([&]() {
nvs_set_u8(handle_, kKeyOutput, static_cast<uint8_t>(out));
nvs_commit(handle_);
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") {

@ -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) {

Loading…
Cancel
Save