Various improvements (#547)
- Fixed crash when returning to Setup app (from any of the steps) - Fixed crash when returning to TimeDateSettings app (after locale selection) - Fixed GuiService inconsistent behaviour: now always perform operations async (e.g. to show/hide apps). This fixes crashes in some onHide() calls where onHide() might be called before onShow() was called. - Fix for incorrect WebServService path - Remove CYD-4848S040C SD card functionality, but added a GPIO fix for releasing 3-wire SPI pin sharing. - Fix for saving/loading settings for various apps
This commit is contained in:
committed by
GitHub
parent
a323f8e148
commit
ecad2248d9
@@ -47,6 +47,7 @@ FileSystemApi partition_fs_api = {
|
||||
// endregion file_system stub
|
||||
|
||||
static esp_err_t initNvsFlashSafely() {
|
||||
LOGGER.info("Init NVS");
|
||||
esp_err_t result = nvs_flash_init();
|
||||
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
@@ -75,7 +76,7 @@ size_t getSectorSize() {
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t initPartitionsEsp() {
|
||||
bool initPartitionsEsp() {
|
||||
LOGGER.info("Init partitions");
|
||||
ESP_ERROR_CHECK(initNvsFlashSafely());
|
||||
|
||||
@@ -90,22 +91,25 @@ esp_err_t initPartitionsEsp() {
|
||||
auto system_result = esp_vfs_fat_spiflash_mount_ro("/system", "system", &mount_config);
|
||||
if (system_result != ESP_OK) {
|
||||
LOGGER.error("Failed to mount /system ({})", esp_err_to_name(system_result));
|
||||
} else {
|
||||
LOGGER.info("Mounted /system");
|
||||
static auto system_fs_data = PartitionFsData("/system");
|
||||
file_system_add(&partition_fs_api, &system_fs_data);
|
||||
return false;
|
||||
}
|
||||
LOGGER.info("Mounted /system");
|
||||
static auto system_fs_data = PartitionFsData("/system");
|
||||
file_system_add(&partition_fs_api, &system_fs_data);
|
||||
|
||||
#ifdef CONFIG_TT_USER_DATA_LOCATION_INTERNAL
|
||||
auto data_result = esp_vfs_fat_spiflash_mount_rw_wl("/data", "data", &mount_config, &data_wl_handle);
|
||||
if (data_result != ESP_OK) {
|
||||
LOGGER.error("Failed to mount /data ({})", esp_err_to_name(data_result));
|
||||
} else {
|
||||
LOGGER.info("Mounted /data");
|
||||
static auto data_fs_data = PartitionFsData("/data");
|
||||
file_system_add(&partition_fs_api, &data_fs_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return system_result == ESP_OK && data_result == ESP_OK;
|
||||
LOGGER.info("Mounted /data");
|
||||
static auto data_fs_data = PartitionFsData("/data");
|
||||
file_system_add(&partition_fs_api, &data_fs_data);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,38 +1,25 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include <Tactility/Logger.h>
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <Tactility/PartitionsEsp.h>
|
||||
#include <Tactility/TactilityCore.h>
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
constexpr auto* TAG = "Tactility";
|
||||
|
||||
namespace tt {
|
||||
|
||||
static auto LOGGER = Logger("Tactility");
|
||||
|
||||
// Initialize NVS
|
||||
static void initNvs() {
|
||||
LOGGER.info("Init NVS");
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
LOGGER.info("NVS erasing");
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
static void initNetwork() {
|
||||
LOGGER.info("Init network");
|
||||
LOG_I(TAG, "Init network");
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
}
|
||||
|
||||
void initEsp() {
|
||||
initNvs();
|
||||
initPartitionsEsp();
|
||||
check(initPartitionsEsp(), "Failed to init partitions");
|
||||
initNetwork();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <Tactility/app/chat/ChatProtocol.h>
|
||||
|
||||
#include <Tactility/crypt/Crypt.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/Paths.h>
|
||||
@@ -34,6 +35,8 @@ constexpr auto* KEY_NICKNAME = "nickname";
|
||||
constexpr auto* KEY_ENCRYPTION_KEY = "encryptionKey";
|
||||
constexpr auto* KEY_CHAT_CHANNEL = "chatChannel";
|
||||
|
||||
uint32_t defaultSenderId = 0;
|
||||
|
||||
// IV_SEED provides basic obfuscation for stored encryption keys, not strong encryption.
|
||||
// The device master key (from crypt::getIv) provides the actual security.
|
||||
static constexpr auto* IV_SEED = "chat_key";
|
||||
@@ -112,8 +115,9 @@ static uint32_t generateSenderId() {
|
||||
}
|
||||
|
||||
ChatSettingsData getDefaultSettings() {
|
||||
if (defaultSenderId == 0) defaultSenderId = generateSenderId();
|
||||
return ChatSettingsData{
|
||||
.senderId = 0,
|
||||
.senderId = defaultSenderId,
|
||||
.nickname = "Device",
|
||||
.encryptionKey = {},
|
||||
.hasEncryptionKey = false,
|
||||
@@ -124,8 +128,14 @@ ChatSettingsData getDefaultSettings() {
|
||||
ChatSettingsData loadSettings() {
|
||||
ChatSettingsData settings = getDefaultSettings();
|
||||
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
settings.senderId = generateSenderId();
|
||||
return settings;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
settings.senderId = generateSenderId();
|
||||
return settings;
|
||||
}
|
||||
@@ -176,7 +186,12 @@ bool saveSettings(const ChatSettingsData& settings) {
|
||||
map[KEY_ENCRYPTION_KEY] = "";
|
||||
}
|
||||
|
||||
return file::savePropertiesFile(getSettingsFilePath(), map);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
LOGGER.error("Failed to create parent dir for {}", settings_path);
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
bool settingsFileExists() {
|
||||
|
||||
@@ -53,6 +53,7 @@ class SetupApp final : public App {
|
||||
Phase phase = Phase::Welcome;
|
||||
size_t stepIndex = 0;
|
||||
std::vector<StepConfiguration> steps;
|
||||
bool isShown = false;
|
||||
|
||||
lv_obj_t* titleLabel = nullptr;
|
||||
lv_obj_t* descriptionLabel = nullptr;
|
||||
@@ -105,7 +106,12 @@ class SetupApp final : public App {
|
||||
phase = Phase::Done;
|
||||
}
|
||||
|
||||
renderCurrent();
|
||||
// Widgets may not exist yet: onShow() runs asynchronously on the GUI task and
|
||||
// may not have (re)created them by the time onResult() advances the state.
|
||||
// onShow() calls renderCurrent() itself once the widgets are ready.
|
||||
if (isShown) {
|
||||
renderCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
void onSkipClicked() {
|
||||
@@ -180,9 +186,14 @@ public:
|
||||
lv_obj_align(continueButton, LV_ALIGN_BOTTOM_RIGHT, -12, -12);
|
||||
lv_obj_add_event_cb(continueButton, onContinueClickedCallback, LV_EVENT_SHORT_CLICKED, this);
|
||||
|
||||
isShown = true;
|
||||
renderCurrent();
|
||||
}
|
||||
|
||||
void onHide(AppContext& app) override {
|
||||
isShown = false;
|
||||
}
|
||||
|
||||
void onResult(AppContext& app, LaunchId launchId, Result result, std::unique_ptr<Bundle> bundle) override {
|
||||
lvgl_lock();
|
||||
advanceTo(stepIndex + 1);
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "tactility/lvgl_module.h"
|
||||
|
||||
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
#include <Tactility/app/AppManifest.h>
|
||||
#include <Tactility/app/timezone/TimeZone.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/lvgl/Toolbar.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
#include <Tactility/lvgl/Toolbar.h>
|
||||
#include <Tactility/service/loader/Loader.h>
|
||||
#include <Tactility/settings/Time.h>
|
||||
#include <Tactility/settings/SystemSettings.h>
|
||||
#include <Tactility/settings/Time.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
@@ -23,6 +26,7 @@ class TimeDateSettingsApp final : public App {
|
||||
RecursiveMutex mutex;
|
||||
lv_obj_t* timeZoneLabel = nullptr;
|
||||
lv_obj_t* dateFormatDropdown = nullptr;
|
||||
bool isShown = false;
|
||||
|
||||
static void onTimeFormatChanged(lv_event_t* event) {
|
||||
auto* widget = lv_event_get_target_obj(event);
|
||||
@@ -133,6 +137,12 @@ public:
|
||||
}
|
||||
lv_obj_center(timeZoneLabel);
|
||||
lv_label_set_text(timeZoneLabel, timeZoneName.c_str());
|
||||
|
||||
isShown = true;
|
||||
}
|
||||
|
||||
void onHide(AppContext& app) override {
|
||||
isShown = false;
|
||||
}
|
||||
|
||||
void onResult(AppContext& app, LaunchId launchId, Result result, std::unique_ptr<Bundle> bundle) override {
|
||||
@@ -141,11 +151,13 @@ public:
|
||||
const auto code = timezone::getResultCode(*bundle);
|
||||
LOGGER.info("Result name={} code={}", name, code);
|
||||
|
||||
if (!name.empty()) {
|
||||
if (lvgl::lock(100 / portTICK_PERIOD_MS)) {
|
||||
// onShow() may not have (re)created the widgets yet: onResult() runs synchronously
|
||||
// on the loader thread and can race ahead of the async gui-task redraw.
|
||||
if (!name.empty() && lvgl_try_lock(100 / portTICK_PERIOD_MS)) {
|
||||
if (isShown) {
|
||||
lv_label_set_text(timeZoneLabel, name.c_str());
|
||||
lvgl::unlock();
|
||||
}
|
||||
lvgl_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +60,11 @@ bool hasFileForDevice(const std::string& addr_hex) {
|
||||
}
|
||||
|
||||
bool load(const std::string& addr_hex, PairedDevice& device) {
|
||||
auto file_path = getFilePath(addr_hex);
|
||||
if (!file::isFile(file_path)) return false;
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getFilePath(addr_hex), map)) return false;
|
||||
if (!file::loadPropertiesFile(file_path, map)) return false;
|
||||
if (!map.contains(KEY_ADDR)) return false;
|
||||
if (!hexToAddr(map[KEY_ADDR], device.addr)) return false;
|
||||
|
||||
@@ -83,7 +86,12 @@ bool save(const PairedDevice& device) {
|
||||
map[KEY_ADDR] = addr_hex;
|
||||
map[KEY_AUTO_CONNECT] = device.autoConnect ? "true" : "false";
|
||||
map[KEY_PROFILE_ID] = std::to_string(device.profileId);
|
||||
return file::savePropertiesFile(getFilePath(addr_hex), map);
|
||||
auto file_path = getFilePath(addr_hex);
|
||||
if (!file::findOrCreateParentDirectory(file_path, 0755)) {
|
||||
LOGGER.error("Failed to create parent dir for {}", file_path);
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(file_path, map);
|
||||
}
|
||||
|
||||
bool remove(const std::string& addr_hex) {
|
||||
|
||||
@@ -29,8 +29,13 @@ static BluetoothSettings cached;
|
||||
static bool cached_valid = false;
|
||||
|
||||
static bool load(BluetoothSettings& out) {
|
||||
auto settings_path = getSettingsPath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsPath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
auto it = map.find(KEY_ENABLE_ON_BOOT);
|
||||
@@ -47,11 +52,18 @@ static bool load(BluetoothSettings& out) {
|
||||
|
||||
static bool save(const BluetoothSettings& s) {
|
||||
std::map<std::string, std::string> map;
|
||||
file::loadPropertiesFile(getSettingsPath(), map); // ignore failure — may not exist yet
|
||||
if (file::isFile(getSettingsPath())) {
|
||||
file::loadPropertiesFile(getSettingsPath(), map);
|
||||
}
|
||||
map[KEY_ENABLE_ON_BOOT] = s.enableOnBoot ? "true" : "false";
|
||||
map[KEY_SPP_AUTO_START] = s.sppAutoStart ? "true" : "false";
|
||||
map[KEY_MIDI_AUTO_START] = s.midiAutoStart ? "true" : "false";
|
||||
return file::savePropertiesFile(getSettingsPath(), map);
|
||||
auto settings_path = getSettingsPath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
LOGGER.error("Failed to create parent dir for {}", settings_path);
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
static BluetoothSettings getCachedOrLoad() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/Paths.h>
|
||||
@@ -21,8 +22,13 @@ struct DevelopmentSettings {
|
||||
};
|
||||
|
||||
static bool load(DevelopmentSettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -38,7 +44,12 @@ static bool load(DevelopmentSettings& settings) {
|
||||
static bool save(const DevelopmentSettings& settings) {
|
||||
std::map<std::string, std::string> map;
|
||||
map[SETTINGS_KEY_ENABLE_ON_BOOT] = settings.enableOnBoot ? "true" : "false";
|
||||
return file::savePropertiesFile(getSettingsFilePath(), map);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
LOGGER.error("Failed to create parent dir for {}", settings_path);
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
void setEnableOnBoot(bool enable) {
|
||||
|
||||
@@ -27,14 +27,49 @@ void warnIfRunningOnGuiTask(const char* context) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum class GuiDispatchType { Show, Hide, Exit };
|
||||
|
||||
struct GuiDispatchItem {
|
||||
GuiService* service;
|
||||
GuiDispatchType type;
|
||||
std::shared_ptr<app::AppInstance> appInstance; // only used for Show
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// region AppManifest
|
||||
|
||||
void GuiService::onGuiDispatch(void* context) {
|
||||
std::unique_ptr<GuiDispatchItem> item(static_cast<GuiDispatchItem*>(context));
|
||||
switch (item->type) {
|
||||
case GuiDispatchType::Show:
|
||||
item->service->showApp(item->appInstance);
|
||||
break;
|
||||
case GuiDispatchType::Hide:
|
||||
item->service->hideApp();
|
||||
break;
|
||||
case GuiDispatchType::Exit:
|
||||
item->service->exitRequested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiService::onLoaderEvent(LoaderService::Event event) {
|
||||
GuiDispatchItem* item;
|
||||
if (event == LoaderService::Event::ApplicationShowing) {
|
||||
auto app_instance = std::static_pointer_cast<app::AppInstance>(app::getCurrentAppContext());
|
||||
showApp(app_instance);
|
||||
item = new GuiDispatchItem{this, GuiDispatchType::Show, app_instance};
|
||||
} else if (event == LoaderService::Event::ApplicationHiding) {
|
||||
hideApp();
|
||||
item = new GuiDispatchItem{this, GuiDispatchType::Hide, nullptr};
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispatcher_dispatch(dispatcher, item, onGuiDispatch) != ERROR_NONE) {
|
||||
LOGGER.error("Failed to dispatch gui event");
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,26 +117,8 @@ int32_t GuiService::guiMain() {
|
||||
|
||||
lvgl::unlock();
|
||||
|
||||
while (true) {
|
||||
uint32_t flags = 0;
|
||||
if (service->threadFlags.wait(GUI_THREAD_FLAG_ALL, false, true, &flags, portMAX_DELAY)) {
|
||||
// When service not started or starting -> exit
|
||||
State service_state = getState(manifest.id);
|
||||
if (service_state != State::Started && service_state != State::Starting) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Process and dispatch draw call
|
||||
if (flags & GUI_THREAD_FLAG_DRAW) {
|
||||
service->threadFlags.clear(GUI_THREAD_FLAG_DRAW);
|
||||
service->redraw();
|
||||
}
|
||||
|
||||
if (flags & GUI_THREAD_FLAG_EXIT) {
|
||||
service->threadFlags.clear(GUI_THREAD_FLAG_EXIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!service->exitRequested) {
|
||||
dispatcher_consume(service->dispatcher);
|
||||
}
|
||||
|
||||
service->appRootWidget = nullptr;
|
||||
@@ -177,6 +194,9 @@ void GuiService::redraw() {
|
||||
}
|
||||
|
||||
bool GuiService::onStart(ServiceContext& service) {
|
||||
exitRequested = false;
|
||||
dispatcher = dispatcher_alloc();
|
||||
|
||||
thread = new Thread(
|
||||
GUI_TASK_NAME,
|
||||
4096, // Last known minimum was 2800 for launching desktop
|
||||
@@ -211,8 +231,14 @@ void GuiService::onStop(ServiceContext& service) {
|
||||
appToRender = nullptr;
|
||||
isStarted = false;
|
||||
|
||||
threadFlags.set(GUI_THREAD_FLAG_EXIT);
|
||||
unlock();
|
||||
|
||||
auto* exit_item = new GuiDispatchItem{this, GuiDispatchType::Exit, nullptr};
|
||||
if (dispatcher_dispatch(dispatcher, exit_item, onGuiDispatch) != ERROR_NONE) {
|
||||
LOGGER.error("Failed to dispatch gui exit event");
|
||||
check(false, "Failed to dispatch exit signal to thread.");
|
||||
delete exit_item;
|
||||
}
|
||||
thread->join();
|
||||
|
||||
if (lvgl::lock()) {
|
||||
@@ -226,10 +252,8 @@ void GuiService::onStop(ServiceContext& service) {
|
||||
}
|
||||
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void GuiService::requestDraw() {
|
||||
threadFlags.set(GUI_THREAD_FLAG_DRAW);
|
||||
dispatcher_free(dispatcher);
|
||||
dispatcher = nullptr;
|
||||
}
|
||||
|
||||
void GuiService::showApp(std::shared_ptr<app::AppInstance> app) {
|
||||
@@ -253,7 +277,7 @@ void GuiService::showApp(std::shared_ptr<app::AppInstance> app) {
|
||||
}
|
||||
|
||||
appToRender = std::move(app);
|
||||
requestDraw();
|
||||
redraw();
|
||||
}
|
||||
|
||||
void GuiService::hideApp() {
|
||||
|
||||
@@ -1454,7 +1454,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
|
||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||
// Determine save location: prefer SD card root if mounted, otherwise /data
|
||||
std::string save_path = getUserDataRootPath();
|
||||
std::string save_path = getUserDataPath();
|
||||
|
||||
// Find next available filename with incrementing number
|
||||
std::string screenshot_path;
|
||||
|
||||
@@ -127,6 +127,10 @@ bool load(const std::string& ssid, WifiApSettings& apSettings) {
|
||||
return false;
|
||||
}
|
||||
const auto file_path = getApPropertiesFilePath(service_context->getPaths(), ssid);
|
||||
if (!file::isFile(file_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(file_path, map)) {
|
||||
return false;
|
||||
|
||||
@@ -120,21 +120,25 @@ static void importWifiApSettingsFromDir(const std::string& path) {
|
||||
}
|
||||
|
||||
void bootSplashInit() {
|
||||
LOGGER.info("bootSplashInit begin");
|
||||
LOGGER.info("bootSplashInit dispatch");
|
||||
getMainDispatcher().dispatch([] {
|
||||
LOGGER.info("bootSplashInit dispatch begin");
|
||||
// First import any provisioning files placed on the system data partition.
|
||||
const std::string data_settings_path = file::getChildPath(getUserDataPath(), "provisioning");
|
||||
importWifiApSettingsFromDir(data_settings_path);
|
||||
// Import any provisioning files placed on the system data partition.
|
||||
const std::string provisioning_path = file::getChildPath(getUserDataPath(), "provisioning");
|
||||
if (file::isDirectory(provisioning_path)) {
|
||||
importWifiApSettingsFromDir(provisioning_path);
|
||||
} else {
|
||||
LOGGER.info("Skip provisioning: no files at {}", provisioning_path);
|
||||
}
|
||||
|
||||
// Dispatch WiFi on
|
||||
if (settings::shouldEnableOnBoot()) {
|
||||
LOGGER.info("Auto-enabling due to setting");
|
||||
LOGGER.info("Auto-enabling WiFi");
|
||||
getMainDispatcher().dispatch([] -> void { setEnabled(true); });
|
||||
}
|
||||
|
||||
LOGGER.info("bootSplashInit dispatch end");
|
||||
});
|
||||
LOGGER.info("bootSplashInit end");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/settings/BootSettings.h>
|
||||
|
||||
#include <Tactility/Paths.h>
|
||||
@@ -10,8 +9,6 @@
|
||||
|
||||
namespace tt::settings {
|
||||
|
||||
constexpr auto* TAG = "BootSettings";
|
||||
|
||||
constexpr auto* PROPERTIES_FILE_FORMAT = "{}/settings/boot.properties";
|
||||
constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId";
|
||||
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
||||
@@ -22,6 +19,10 @@ static std::string getPropertiesFilePath() {
|
||||
|
||||
bool loadBootSettings(BootSettings& properties) {
|
||||
const std::string path = getPropertiesFilePath();
|
||||
if (!file::isFile(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file::loadPropertiesFile(path, [&properties](auto& key, auto& value) {
|
||||
if (key == PROPERTIES_KEY_AUTO_START_APP_ID) {
|
||||
properties.autoStartAppId = value;
|
||||
@@ -29,7 +30,6 @@ bool loadBootSettings(BootSettings& properties) {
|
||||
properties.launcherAppId = value;
|
||||
}
|
||||
})) {
|
||||
LOG_I(TAG, "No settings at %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <Tactility/settings/DisplaySettings.h>
|
||||
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Paths.h>
|
||||
#include <tactility/hal/Device.h>
|
||||
@@ -109,8 +110,13 @@ static bool fromString(const std::string& str, ScreensaverType& type) {
|
||||
}
|
||||
|
||||
bool load(DisplaySettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -190,7 +196,11 @@ bool save(const DisplaySettings& settings) {
|
||||
map[SETTINGS_KEY_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0";
|
||||
map[SETTINGS_KEY_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs);
|
||||
map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType);
|
||||
return file::savePropertiesFile(getSettingsFilePath(), map);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <Tactility/settings/KeyboardSettings.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Paths.h>
|
||||
|
||||
@@ -17,8 +18,13 @@ constexpr auto* KEY_BACKLIGHT_TIMEOUT_ENABLED = "backlightTimeoutEnabled";
|
||||
constexpr auto* KEY_BACKLIGHT_TIMEOUT_MS = "backlightTimeoutMs";
|
||||
|
||||
bool load(KeyboardSettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -58,7 +64,11 @@ bool save(const KeyboardSettings& settings) {
|
||||
map[KEY_BACKLIGHT_BRIGHTNESS] = std::to_string(settings.backlightBrightness);
|
||||
map[KEY_BACKLIGHT_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0";
|
||||
map[KEY_BACKLIGHT_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs);
|
||||
return file::savePropertiesFile(getSettingsFilePath(), map);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,6 +80,11 @@ bool saveSystemSettings(const SystemSettings& properties) {
|
||||
map["timeFormat24h"] = properties.timeFormat24h ? "true" : "false";
|
||||
map["dateFormat"] = properties.dateFormat;
|
||||
|
||||
if (!file::findOrCreateParentDirectory(file_path, 0755)) {
|
||||
LOGGER.error("Failed to create parent dir for {}", file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file::savePropertiesFile(file_path, map)) {
|
||||
LOGGER.error("Failed to save {}", file_path);
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <Tactility/settings/TouchCalibrationSettings.h>
|
||||
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
#include <Tactility/Paths.h>
|
||||
@@ -64,8 +65,13 @@ bool isValid(const TouchCalibrationSettings& settings) {
|
||||
}
|
||||
|
||||
bool load(TouchCalibrationSettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,7 +122,12 @@ bool save(const TouchCalibrationSettings& settings) {
|
||||
map[SETTINGS_KEY_Y_MIN] = std::to_string(settings.yMin);
|
||||
map[SETTINGS_KEY_Y_MAX] = std::to_string(settings.yMax);
|
||||
|
||||
if (!file::savePropertiesFile(getSettingsFilePath(), map)) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file::savePropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <Tactility/settings/TrackballSettings.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/Paths.h>
|
||||
|
||||
@@ -23,8 +24,13 @@ constexpr uint8_t MIN_POINTER_SENSITIVITY = 1;
|
||||
constexpr uint8_t MAX_POINTER_SENSITIVITY = 10;
|
||||
|
||||
bool load(TrackballSettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -84,7 +90,11 @@ bool save(const TrackballSettings& settings) {
|
||||
map[KEY_TRACKBALL_MODE] = (settings.trackballMode == TrackballMode::Pointer) ? "1" : "0";
|
||||
map[KEY_ENCODER_SENSITIVITY] = std::to_string(std::clamp(settings.encoderSensitivity, MIN_ENCODER_SENSITIVITY, MAX_ENCODER_SENSITIVITY));
|
||||
map[KEY_POINTER_SENSITIVITY] = std::to_string(std::clamp(settings.pointerSensitivity, MIN_POINTER_SENSITIVITY, MAX_POINTER_SENSITIVITY));
|
||||
return file::savePropertiesFile(getSettingsFilePath(), map);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,8 +90,13 @@ static bool isEmptyCredential(const std::string& value) {
|
||||
}
|
||||
|
||||
bool load(WebServerSettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(getSettingsFilePath(), map)) {
|
||||
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -257,7 +262,12 @@ bool save(const WebServerSettings& settings) {
|
||||
map[KEY_WEBSERVER_USERNAME] = settings.webServerUsername;
|
||||
map[KEY_WEBSERVER_PASSWORD] = settings.webServerPassword;
|
||||
|
||||
return file::savePropertiesFile(getSettingsFilePath(), map);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
LOGGER.error("Failed to create parent dir for {}", settings_path);
|
||||
return false;
|
||||
}
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user