diff --git a/Data/data/boot.properties b/Data/data/settings/boot.properties similarity index 100% rename from Data/data/boot.properties rename to Data/data/settings/boot.properties diff --git a/Data/data/service/Wifi/wifi.properties b/Data/data/settings/development.properties similarity index 100% rename from Data/data/service/Wifi/wifi.properties rename to Data/data/settings/development.properties diff --git a/Data/data/settings.properties b/Data/data/settings/system.properties similarity index 100% rename from Data/data/settings.properties rename to Data/data/settings/system.properties diff --git a/Data/data/settings/wifi.properties b/Data/data/settings/wifi.properties new file mode 100644 index 00000000..583f5735 --- /dev/null +++ b/Data/data/settings/wifi.properties @@ -0,0 +1 @@ +enableOnBoot=false \ No newline at end of file diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 4cb1a80e..73dba9f2 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -2,7 +2,6 @@ ## Higher Priority -- Move Development settings from flash to `/data/apps/development/development.properties` (just the "start on boot") - Move Display settings from flash to `/data/apps/display/display.properties` - Expose app::Paths to TactilityC - Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set. diff --git a/Tactility/Include/Tactility/app/display/DisplaySettings.h b/Tactility/Include/Tactility/app/display/DisplaySettings.h deleted file mode 100644 index 4eab847e..00000000 --- a/Tactility/Include/Tactility/app/display/DisplaySettings.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace tt::app::display { - -void setBacklightDuty(uint8_t value); - -bool getBacklightDuty(uint8_t& duty); - -void setGammaCurve(uint8_t curveIndex); - -bool getGammaCurve(uint8_t& curveIndex); - -void setRotation(lv_display_rotation_t rotation); - -lv_display_rotation_t getRotation(); - -} // namespace diff --git a/Tactility/Include/Tactility/service/ServiceRegistration.h b/Tactility/Include/Tactility/service/ServiceRegistration.h index 6a6f03c9..ed5c24a9 100644 --- a/Tactility/Include/Tactility/service/ServiceRegistration.h +++ b/Tactility/Include/Tactility/service/ServiceRegistration.h @@ -40,7 +40,7 @@ State getState(const std::string& id); * @param[in] id the id as defined in the manifest * @return the matching manifest or nullptr when it wasn't found */ -std::shared_ptr _Nullable findManifestId(const std::string& id); +std::shared_ptr _Nullable findManifestById(const std::string& id); /** Find a ServiceContext by its manifest id. * @param[in] id the id as defined in the manifest diff --git a/Tactility/Include/Tactility/BootProperties.h b/Tactility/Include/Tactility/settings/BootSettings.h similarity index 75% rename from Tactility/Include/Tactility/BootProperties.h rename to Tactility/Include/Tactility/settings/BootSettings.h index d94c5867..95a8388e 100644 --- a/Tactility/Include/Tactility/BootProperties.h +++ b/Tactility/Include/Tactility/settings/BootSettings.h @@ -2,9 +2,9 @@ #include -namespace tt { +namespace tt::settings { -struct BootProperties { +struct BootSettings { /** App to start automatically after the splash screen. */ std::string launcherAppId; /** App to start automatically from the launcher screen. */ @@ -12,13 +12,13 @@ struct BootProperties { }; /** - * Load the boot properties from the relevant file location(s). + * Load the boot properties file from the relevant file location(s). * It will first attempt to load them from the SD card and if no file was found, * then it will try to load the one from the data mount point. * * @param[out] properties the resulting properties * @return true when the properties were successfully loaded and the result was set */ -bool loadBootProperties(BootProperties& properties); +bool loadBootSettings(BootSettings& properties); } diff --git a/Tactility/Include/Tactility/settings/DisplaySettings.h b/Tactility/Include/Tactility/settings/DisplaySettings.h new file mode 100644 index 00000000..be25e973 --- /dev/null +++ b/Tactility/Include/Tactility/settings/DisplaySettings.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace tt::settings::display { + +enum class Orientation { + // In order of rotation (to make it easier to convert to LVGL rotation) + Landscape, + Portrait, + LandscapeFlipped, + PortraitFlipped, +}; + +struct DisplaySettings { + Orientation orientation; + uint8_t gammaCurve; + uint8_t backlightDuty; +}; + +/** Compares default settings with the function parameter to return the difference */ +lv_display_rotation_t toLvglDisplayRotation(Orientation orientation); + +bool load(DisplaySettings& settings); + +DisplaySettings loadOrGetDefault(); + +DisplaySettings getDefault(); + +bool save(const DisplaySettings& settings); + +} // namespace diff --git a/Tactility/Include/Tactility/settings/SettingsProperties.h b/Tactility/Include/Tactility/settings/SettingsProperties.h deleted file mode 100644 index 3161c81d..00000000 --- a/Tactility/Include/Tactility/settings/SettingsProperties.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "Language.h" - -namespace tt::settings { - -struct SettingsProperties { - Language language; - bool timeFormat24h; -}; - -bool loadSettingsProperties(SettingsProperties& properties); - -bool saveSettingsProperties(const SettingsProperties& properties); - -} diff --git a/Tactility/Include/Tactility/settings/SystemSettings.h b/Tactility/Include/Tactility/settings/SystemSettings.h new file mode 100644 index 00000000..8d0019b4 --- /dev/null +++ b/Tactility/Include/Tactility/settings/SystemSettings.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Language.h" + +namespace tt::settings { + +struct SystemSettings { + Language language; + bool timeFormat24h; +}; + +bool loadSystemSettings(SystemSettings& properties); + +bool saveSystemSettings(const SystemSettings& properties); + +} diff --git a/Tactility/Private/Tactility/service/development/DevelopmentService.h b/Tactility/Private/Tactility/service/development/DevelopmentService.h index 7fb0d9d4..4feebf59 100644 --- a/Tactility/Private/Tactility/service/development/DevelopmentService.h +++ b/Tactility/Private/Tactility/service/development/DevelopmentService.h @@ -74,17 +74,6 @@ public: */ void setEnabled(bool enabled); - /** - * @return true if the service will enable itself when it is started (e.g. on boot, or manual start) - */ - bool isEnabledOnStart() const; - - /** - * Set whether the service should auto-enable when it is started. - * @param enabled - */ - void setEnabledOnStart(bool enabled); - bool isStarted() const; // region Internal API diff --git a/Tactility/Private/Tactility/service/development/DevelopmentSettings.h b/Tactility/Private/Tactility/service/development/DevelopmentSettings.h new file mode 100644 index 00000000..9a934002 --- /dev/null +++ b/Tactility/Private/Tactility/service/development/DevelopmentSettings.h @@ -0,0 +1,12 @@ +#pragma once +#ifdef ESP_PLATFORM + +namespace tt::service::development { + +void setEnableOnBoot(bool enable); + +bool shouldEnableOnBoot(); + +} + +#endif // ESP_PLATFORM diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 631739d0..fc8801dc 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -1,18 +1,16 @@ -#include "Tactility/TactilityCore.h" - -#include "Tactility/app/AppContext.h" -#include "Tactility/app/display/DisplaySettings.h" -#include "Tactility/service/loader/Loader.h" -#include "Tactility/lvgl/Style.h" - -#include "Tactility/hal/display/DisplayDevice.h" +#include #include +#include +#include +#include #include #include +#include +#include +#include +#include #include -#include -#include #ifdef ESP_PLATFORM #include "Tactility/app/crashdiagnostics/CrashDiagnostics.h" @@ -42,25 +40,25 @@ class BootApp : public App { static void setupDisplay() { const auto hal_display = getHalDisplay(); assert(hal_display != nullptr); + + settings::display::DisplaySettings settings; + if (settings::display::load(settings)) { + if (hal_display->getGammaCurveCount() > 0) { + hal_display->setGammaCurve(settings.gammaCurve); + TT_LOG_I(TAG, "Gamma curve %du", settings.gammaCurve); + } + } else { + settings = settings::display::getDefault(); + } + if (hal_display->supportsBacklightDuty()) { - uint8_t backlight_duty = 200; - display::getBacklightDuty(backlight_duty); - TT_LOG_I(TAG, "backlight %du", backlight_duty); - hal_display->setBacklightDuty(backlight_duty); + TT_LOG_I(TAG, "Backlight %du", settings.backlightDuty); + hal_display->setBacklightDuty(settings.backlightDuty); } else { TT_LOG_I(TAG, "no backlight"); } - - if (hal_display->getGammaCurveCount() > 0) { - uint8_t gamma_curve; - if (display::getGammaCurve(gamma_curve)) { - hal_display->setGammaCurve(gamma_curve); - TT_LOG_I(TAG, "gamma %du", gamma_curve); - } - } } - static bool setupUsbBootMode() { if (!hal::usb::isUsbBootMode()) { return false; @@ -107,8 +105,8 @@ class BootApp : public App { } #endif - BootProperties boot_properties; - if (!loadBootProperties(boot_properties) || boot_properties.launcherAppId.empty()) { + settings::BootSettings boot_properties; + if (!settings::loadBootSettings(boot_properties) || boot_properties.launcherAppId.empty()) { TT_LOG_E(TAG, "Launcher not configured"); stop(); return; diff --git a/Tactility/Source/app/development/Development.cpp b/Tactility/Source/app/development/Development.cpp index cd5e5b90..31564108 100644 --- a/Tactility/Source/app/development/Development.cpp +++ b/Tactility/Source/app/development/Development.cpp @@ -1,17 +1,17 @@ #ifdef ESP_PLATFORM -#include "Tactility/app/AppManifest.h" -#include "Tactility/lvgl/Style.h" -#include "Tactility/lvgl/Toolbar.h" -#include "Tactility/service/development/DevelopmentService.h" - -#include -#include -#include -#include +#include #include +#include +#include +#include #include #include +#include + +#include +#include +#include namespace tt::app::development { @@ -49,10 +49,9 @@ class DevelopmentApp final : public App { auto* widget = static_cast(lv_event_get_target(event)); if (code == LV_EVENT_VALUE_CHANGED) { bool is_on = lv_obj_has_state(widget, LV_STATE_CHECKED); - auto* app = static_cast(lv_event_get_user_data(event)); - bool is_changed = is_on != app->service->isEnabledOnStart(); + bool is_changed = is_on != service::development::shouldEnableOnBoot(); if (is_changed) { - app->service->setEnabledOnStart(is_on); + service::development::setEnableOnBoot(is_on); } } } @@ -125,7 +124,7 @@ public: enableOnBootSwitch = lv_switch_create(wrapper); lv_obj_add_event_cb(enableOnBootSwitch, onEnableOnBootSwitchChanged, LV_EVENT_VALUE_CHANGED, this); lv_obj_align(enableOnBootSwitch, LV_ALIGN_TOP_RIGHT, 0, 0); - if (service->isEnabledOnStart()) { + if (service::development::shouldEnableOnBoot()) { lv_obj_add_state(enableOnBootSwitch, LV_STATE_CHECKED); } else { lv_obj_remove_state(enableOnBootSwitch, LV_STATE_CHECKED); diff --git a/Tactility/Source/app/display/Display.cpp b/Tactility/Source/app/display/Display.cpp index 51169d5b..7d93b5ed 100644 --- a/Tactility/Source/app/display/Display.cpp +++ b/Tactility/Source/app/display/Display.cpp @@ -1,105 +1,70 @@ -#include "Tactility/app/display/DisplaySettings.h" - -#include "Tactility/hal/display/DisplayDevice.h" -#include "Tactility/lvgl/Toolbar.h" - +#include #include +#include +#include #include #include namespace tt::app::display { -#define TAG "display" - -static bool backlight_duty_set = false; -static uint8_t backlight_duty = 255; - -static uint8_t gamma = 255; - -#define ROTATION_DEFAULT 0 -#define ROTATION_180 1 -#define ROTATION_270 2 -#define ROTATION_90 3 +constexpr auto* TAG = "Display"; static std::shared_ptr getHalDisplay() { return hal::findFirstDevice(hal::Device::Type::Display); } -static lv_display_rotation_t orientationSettingToDisplayRotation(uint32_t setting) { - switch (setting) { - case ROTATION_180: - return LV_DISPLAY_ROTATION_180; - case ROTATION_270: - return LV_DISPLAY_ROTATION_270; - case ROTATION_90: - return LV_DISPLAY_ROTATION_90; - default: - return LV_DISPLAY_ROTATION_0; - } -} +class DisplayApp final : public App { -static uint32_t displayOrientationToOrientationSetting(lv_display_rotation_t orientation) { - switch (orientation) { - case LV_DISPLAY_ROTATION_90: - return ROTATION_90; - case LV_DISPLAY_ROTATION_180: - return ROTATION_180; - case LV_DISPLAY_ROTATION_270: - return ROTATION_270; - default: - return ROTATION_DEFAULT; - } -} - -class DisplayApp : public App { + settings::display::DisplaySettings displaySettings; + bool displaySettingsUpdated = false; static void onBacklightSliderEvent(lv_event_t* event) { auto* slider = static_cast(lv_event_get_target(event)); - + auto* app = static_cast(lv_event_get_user_data(event)); auto hal_display = getHalDisplay(); assert(hal_display != nullptr); if (hal_display->supportsBacklightDuty()) { int32_t slider_value = lv_slider_get_value(slider); - - backlight_duty = static_cast(slider_value); - backlight_duty_set = true; - - hal_display->setBacklightDuty(backlight_duty); + app->displaySettings.backlightDuty = static_cast(slider_value); + app->displaySettingsUpdated = true; + hal_display->setBacklightDuty(app->displaySettings.backlightDuty); } } static void onGammaSliderEvent(lv_event_t* event) { auto* slider = static_cast(lv_event_get_target(event)); auto hal_display = hal::findFirstDevice(hal::Device::Type::Display); + auto* app = static_cast(lv_event_get_user_data(event)); assert(hal_display != nullptr); if (hal_display->getGammaCurveCount() > 0) { int32_t slider_value = lv_slider_get_value(slider); - - gamma = static_cast(slider_value); - - hal_display->setGammaCurve(gamma); - setGammaCurve(gamma); + app->displaySettings.gammaCurve = static_cast(slider_value); + app->displaySettingsUpdated = true; + hal_display->setGammaCurve(app->displaySettings.gammaCurve); } } - static void onOrientationSet(lv_event_t* event) { + auto* app = static_cast(lv_event_get_user_data(event)); auto* dropdown = static_cast(lv_event_get_target(event)); - uint32_t selected = lv_dropdown_get_selected(dropdown); - TT_LOG_I(TAG, "Selected %ld", selected); - lv_display_rotation_t rotation = orientationSettingToDisplayRotation(selected); - if (lv_display_get_rotation(lv_display_get_default()) != rotation) { - lv_display_set_rotation(lv_display_get_default(), rotation); - setRotation(rotation); + uint32_t selected_index = lv_dropdown_get_selected(dropdown); + TT_LOG_I(TAG, "Selected %ld", selected_index); + auto selected_orientation = static_cast(selected_index); + if (selected_orientation != app->displaySettings.orientation) { + app->displaySettings.orientation = selected_orientation; + app->displaySettingsUpdated = true; + lv_display_set_rotation(lv_display_get_default(), settings::display::toLvglDisplayRotation(selected_orientation)); } } public: void onShow(AppContext& app, lv_obj_t* parent) override { + displaySettings = settings::display::loadOrGetDefault(); + lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); auto hal_display = getHalDisplay(); @@ -126,14 +91,9 @@ public: lv_obj_set_width(brightness_slider, LV_PCT(50)); lv_obj_align(brightness_slider, LV_ALIGN_TOP_RIGHT, -8, 0); lv_slider_set_range(brightness_slider, 0, 255); - lv_obj_add_event_cb(brightness_slider, onBacklightSliderEvent, LV_EVENT_VALUE_CHANGED, nullptr); + lv_obj_add_event_cb(brightness_slider, onBacklightSliderEvent, LV_EVENT_VALUE_CHANGED, this); - uint8_t value; - if (getBacklightDuty(value)) { - lv_slider_set_value(brightness_slider, value, LV_ANIM_OFF); - } else { - lv_slider_set_value(brightness_slider, 0, LV_ANIM_OFF); - } + lv_slider_set_value(brightness_slider, displaySettings.backlightDuty, LV_ANIM_OFF); } if (hal_display->getGammaCurveCount() > 0) { @@ -151,14 +111,10 @@ public: lv_obj_set_width(gamma_slider, LV_PCT(50)); lv_obj_align(gamma_slider, LV_ALIGN_TOP_RIGHT, -8, 0); lv_slider_set_range(gamma_slider, 0, hal_display->getGammaCurveCount()); - lv_obj_add_event_cb(gamma_slider, onGammaSliderEvent, LV_EVENT_VALUE_CHANGED, nullptr); + lv_obj_add_event_cb(gamma_slider, onGammaSliderEvent, LV_EVENT_VALUE_CHANGED, this); - uint8_t curve_index; - if (getGammaCurve(curve_index)) { - lv_slider_set_value(gamma_slider, curve_index, LV_ANIM_OFF); - } else { - lv_slider_set_value(gamma_slider, 0, LV_ANIM_OFF); - } + uint8_t curve_index = displaySettings.gammaCurve; + lv_slider_set_value(gamma_slider, curve_index, LV_ANIM_OFF); } auto* orientation_wrapper = lv_obj_create(main_wrapper); @@ -170,31 +126,20 @@ public: lv_label_set_text(orientation_label, "Orientation"); lv_obj_align(orientation_label, LV_ALIGN_TOP_LEFT, 0, 8); - auto lvgl_display = lv_obj_get_display(parent); - auto horizontal_px = lv_display_get_horizontal_resolution(lvgl_display); - auto vertical_px = lv_display_get_vertical_resolution(lvgl_display); - bool is_landscape_display = horizontal_px > vertical_px; - auto* orientation_dropdown = lv_dropdown_create(orientation_wrapper); - if (is_landscape_display) { - lv_dropdown_set_options(orientation_dropdown, "Landscape\nLandscape (flipped)\nPortrait Left\nPortrait Right"); - } else { - lv_dropdown_set_options(orientation_dropdown, "Portrait\nPortrait (flipped)\nLandscape Left\nLandscape Right"); - } - + // Note: order correlates with settings::display::Orientation item order + lv_dropdown_set_options(orientation_dropdown, "Landscape\nPortrait Right\nLandscape Flipped\nPortrait Left"); lv_obj_align(orientation_dropdown, LV_ALIGN_TOP_RIGHT, 0, 0); lv_obj_set_style_border_color(orientation_dropdown, lv_color_hex(0xFAFAFA), LV_PART_MAIN); lv_obj_set_style_border_width(orientation_dropdown, 1, LV_PART_MAIN); - lv_obj_add_event_cb(orientation_dropdown, onOrientationSet, LV_EVENT_VALUE_CHANGED, nullptr); - uint32_t orientation_selected = displayOrientationToOrientationSetting( - lv_display_get_rotation(lv_display_get_default()) - ); - lv_dropdown_set_selected(orientation_dropdown, orientation_selected); + lv_obj_add_event_cb(orientation_dropdown, onOrientationSet, LV_EVENT_VALUE_CHANGED, this); + auto orientation = settings::display::toLvglDisplayRotation(displaySettings.orientation); + lv_dropdown_set_selected(orientation_dropdown, orientation); } void onHide(TT_UNUSED AppContext& app) override { - if (backlight_duty_set) { - setBacklightDuty(backlight_duty); + if (displaySettingsUpdated) { + settings::display::save(displaySettings); } } }; diff --git a/Tactility/Source/app/display/DisplaySettings.cpp b/Tactility/Source/app/display/DisplaySettings.cpp deleted file mode 100644 index c50cc356..00000000 --- a/Tactility/Source/app/display/DisplaySettings.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "Tactility/app/display/DisplaySettings.h" - -#include - -namespace tt::app::display { - -tt::Preferences preferences("display"); - -constexpr const char* BACKLIGHT_DUTY_KEY = "backlight_duty"; -constexpr const char* GAMMA_CURVE_KEY = "gamma"; -constexpr const char* ROTATION_KEY = "rotation"; - -void setBacklightDuty(uint8_t value) { - preferences.putInt32(BACKLIGHT_DUTY_KEY, (int32_t)value); -} - -bool getBacklightDuty(uint8_t& duty) { - int32_t result; - if (preferences.optInt32(BACKLIGHT_DUTY_KEY, result)) { - duty = (uint8_t)(result % 256); - return true; - } else { - return false; - } -} - -void setRotation(lv_display_rotation_t rotation) { - preferences.putInt32(ROTATION_KEY, (int32_t)rotation); -} - -lv_display_rotation_t getRotation() { - int32_t rotation; - if (preferences.optInt32(ROTATION_KEY, rotation)) { - return (lv_display_rotation_t)rotation; - } else { - return LV_DISPLAY_ROTATION_0; - } -} - -void setGammaCurve(uint8_t curveIndex) { - preferences.putInt32(GAMMA_CURVE_KEY, (int32_t)curveIndex); -} - -bool getGammaCurve(uint8_t& curveIndex) { - int32_t result; - if (preferences.optInt32(GAMMA_CURVE_KEY, result)) { - curveIndex = (uint8_t)(result % 256); - return true; - } else { - return false; - } -} - -} // namespace diff --git a/Tactility/Source/app/launcher/Launcher.cpp b/Tactility/Source/app/launcher/Launcher.cpp index a6706212..7a460f1a 100644 --- a/Tactility/Source/app/launcher/Launcher.cpp +++ b/Tactility/Source/app/launcher/Launcher.cpp @@ -1,12 +1,12 @@ -#include "Tactility/app/AppContext.h" -#include "Tactility/app/AppRegistration.h" -#include "Tactility/service/loader/Loader.h" - #include -#include -#include +#include +#include #include +#include +#include + +#include namespace tt::app::launcher { @@ -63,8 +63,8 @@ class LauncherApp final : public App { public: void onCreate(TT_UNUSED AppContext& app) override { - BootProperties boot_properties; - if (loadBootProperties(boot_properties) && !boot_properties.autoStartAppId.empty()) { + settings::BootSettings boot_properties; + if (settings::loadBootSettings(boot_properties) && !boot_properties.autoStartAppId.empty()) { TT_LOG_I(TAG, "Starting %s", boot_properties.autoStartAppId.c_str()); service::loader::startApp(boot_properties.autoStartAppId); } diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp index 9f77098a..1cd9b38d 100644 --- a/Tactility/Source/lvgl/Lvgl.cpp +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -9,6 +8,7 @@ #include #include #include +#include #include #ifdef ESP_PLATFORM @@ -93,7 +93,8 @@ void start() { TT_LOG_I(TAG, "Started %s", display->getName().c_str()); auto lvgl_display = display->getLvglDisplay(); assert(lvgl_display != nullptr); - lv_display_rotation_t rotation = app::display::getRotation(); + auto settings = settings::display::loadOrGetDefault(); + lv_display_rotation_t rotation = settings::display::toLvglDisplayRotation(settings.orientation); if (rotation != lv_display_get_rotation(lvgl_display)) { lv_display_set_rotation(lvgl_display, rotation); } @@ -158,16 +159,24 @@ void start() { // Restart services - if (service::getState("Gui") == service::State::Stopped) { - service::startService("Gui"); - } else { - TT_LOG_E(TAG, "Gui service is not in Stopped state"); + // We search for the manifest first, because during the initial start() during boot + // the service won't be registered yet. + if (service::findManifestById("Gui") != nullptr) { + if (service::getState("Gui") == service::State::Stopped) { + service::startService("Gui"); + } else { + TT_LOG_E(TAG, "Gui service is not in Stopped state"); + } } - if (service::getState("Statusbar") == service::State::Stopped) { - service::startService("Statusbar"); - } else { - TT_LOG_E(TAG, "Statusbar service is not in Stopped state"); + // We search for the manifest first, because during the initial start() during boot + // the service won't be registered yet. + if (service::findManifestById("Statusbar") != nullptr) { + if (service::getState("Statusbar") == service::State::Stopped) { + service::startService("Statusbar"); + } else { + TT_LOG_E(TAG, "Statusbar service is not in Stopped state"); + } } // Finalize diff --git a/Tactility/Source/service/ServiceRegistration.cpp b/Tactility/Source/service/ServiceRegistration.cpp index b0580dfb..ffc6091a 100644 --- a/Tactility/Source/service/ServiceRegistration.cpp +++ b/Tactility/Source/service/ServiceRegistration.cpp @@ -1,7 +1,7 @@ -#include "Tactility/service/ServiceRegistration.h" +#include -#include "Tactility/service/ServiceInstance.h" -#include "Tactility/service/ServiceManifest.h" +#include +#include #include @@ -9,7 +9,7 @@ namespace tt::service { -#define TAG "service_registry" +constexpr auto* TAG = "ServiceRegistry"; typedef std::unordered_map> ManifestMap; typedef std::unordered_map> ServiceInstanceMap; @@ -44,7 +44,7 @@ void addService(const ServiceManifest& manifest, bool autoStart) { addService(std::make_shared(manifest), autoStart); } -std::shared_ptr _Nullable findManifestId(const std::string& id) { +std::shared_ptr _Nullable findManifestById(const std::string& id) { manifest_mutex.lock(); auto iterator = service_manifest_map.find(id); auto manifest = iterator != service_manifest_map.end() ? iterator->second : nullptr; @@ -63,7 +63,7 @@ static std::shared_ptr _Nullable findServiceInstanceById(const // TODO: Return proper error/status instead of BOOL? bool startService(const std::string& id) { TT_LOG_I(TAG, "Starting %s", id.c_str()); - auto manifest = findManifestId(id); + auto manifest = findManifestById(id); if (manifest == nullptr) { TT_LOG_E(TAG, "manifest not found for service %s", id.c_str()); return false; diff --git a/Tactility/Source/service/development/DevelopmentService.cpp b/Tactility/Source/service/development/DevelopmentService.cpp index 6091816f..a9caa94d 100644 --- a/Tactility/Source/service/development/DevelopmentService.cpp +++ b/Tactility/Source/service/development/DevelopmentService.cpp @@ -1,24 +1,24 @@ #ifdef ESP_PLATFORM -#include "Tactility/service/development/DevelopmentService.h" +#include -#include "Tactility/network/HttpdReq.h" -#include "Tactility/network/Url.h" -#include "Tactility/TactilityHeadless.h" -#include "Tactility/service/ServiceManifest.h" -#include "Tactility/service/ServiceRegistration.h" -#include "Tactility/service/wifi/Wifi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include namespace tt::service::development { @@ -39,7 +39,7 @@ void DevelopmentService::onStart(ServiceContext& service) { [this](kernel::SystemEvent) { onNetworkDisconnected(); } ); - setEnabled(isEnabledOnStart()); + setEnabled(shouldEnableOnBoot()); } void DevelopmentService::onStop(ServiceContext& service) { @@ -76,18 +76,6 @@ bool DevelopmentService::isEnabled() const { return enabled; } -bool DevelopmentService::isEnabledOnStart() const { - Preferences preferences = Preferences(manifest.id.c_str()); - bool enabled_on_boot = false; - preferences.optBool("enabledOnBoot", enabled_on_boot); - return enabled_on_boot; -} - -void DevelopmentService::setEnabledOnStart(bool enabled) { - Preferences preferences = Preferences(manifest.id.c_str()); - preferences.putBool("enabledOnBoot", enabled); -} - // region Enable/disable void DevelopmentService::startServer() { diff --git a/Tactility/Source/service/development/DevelopmentSettings.cpp b/Tactility/Source/service/development/DevelopmentSettings.cpp new file mode 100644 index 00000000..74153141 --- /dev/null +++ b/Tactility/Source/service/development/DevelopmentSettings.cpp @@ -0,0 +1,55 @@ +#ifdef ESP_PLATFORM +#include +#include +#include +#include +#include + +namespace tt::service::development { + +constexpr auto* TAG = "DevSettings"; +constexpr auto* SETTINGS_FILE = "/data/settings/development.properties"; +constexpr auto* SETTINGS_KEY_ENABLE_ON_BOOT = "enableOnBoot"; + +struct DevelopmentSettings { + bool enableOnBoot; +}; + +static bool load(DevelopmentSettings& settings) { + std::map map; + if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + return false; + } + + if (!map.contains(SETTINGS_KEY_ENABLE_ON_BOOT)) { + return false; + } + + auto enable_on_boot_string = map[SETTINGS_KEY_ENABLE_ON_BOOT]; + settings.enableOnBoot = (enable_on_boot_string == "true"); + return true; +} + +static bool save(const DevelopmentSettings& settings) { + std::map map; + map[SETTINGS_KEY_ENABLE_ON_BOOT] = settings.enableOnBoot ? "true" : "false"; + return file::savePropertiesFile(SETTINGS_FILE, map); +} + +void setEnableOnBoot(bool enable) { + DevelopmentSettings properties { .enableOnBoot = enable }; + if (!save(properties)) { + TT_LOG_E(TAG, "Failed to save %s", SETTINGS_FILE); + } +} + +bool shouldEnableOnBoot() { + DevelopmentSettings settings; + if (!load(settings)) { + return false; + } + return settings.enableOnBoot; +} +} + +#endif // ESP_PLATFORM diff --git a/Tactility/Source/service/wifi/WifiApSettings.cpp b/Tactility/Source/service/wifi/WifiApSettings.cpp index 68906b91..9429cec1 100644 --- a/Tactility/Source/service/wifi/WifiApSettings.cpp +++ b/Tactility/Source/service/wifi/WifiApSettings.cpp @@ -15,7 +15,7 @@ namespace tt::service::wifi::settings { constexpr auto* TAG = "WifiApSettings"; -constexpr auto* AP_SETTINGS_FORMAT = "/data/service/Wifi/{}.ap.properties"; +constexpr auto* AP_SETTINGS_FORMAT = "/data/settings/{}.ap.properties"; constexpr auto* AP_PROPERTIES_KEY_SSID = "ssid"; constexpr auto* AP_PROPERTIES_KEY_PASSWORD = "password"; diff --git a/Tactility/Source/service/wifi/WifiBootSplashInit.cpp b/Tactility/Source/service/wifi/WifiBootSplashInit.cpp index 83e25471..3d92da5a 100644 --- a/Tactility/Source/service/wifi/WifiBootSplashInit.cpp +++ b/Tactility/Source/service/wifi/WifiBootSplashInit.cpp @@ -78,9 +78,9 @@ static void importWifiAp(const std::string& filePath) { } static void importWifiApSettings(std::shared_ptr sdcard) { - // auto lock = sdcard->getLock()->asScopedLock(); - // lock.lock(); - auto path = sdcard->getMountPath(); + auto lock = sdcard->getLock()->asScopedLock(); + lock.lock(); + auto path = file::getChildPath(sdcard->getMountPath(), "settings"); std::vector dirent_list; if (file::scandir(path, dirent_list, [](const dirent* entry) { diff --git a/Tactility/Source/service/wifi/WifiSettings.cpp b/Tactility/Source/service/wifi/WifiSettings.cpp index d2bd369c..d46a6905 100644 --- a/Tactility/Source/service/wifi/WifiSettings.cpp +++ b/Tactility/Source/service/wifi/WifiSettings.cpp @@ -8,14 +8,14 @@ namespace tt::service::wifi::settings { constexpr auto* TAG = "WifiSettings"; -constexpr auto* SETTINGS_FILE = "/data/service/Wifi/wifi.properties"; +constexpr auto* SETTINGS_FILE = "/data/settings/wifi.properties"; constexpr auto* SETTINGS_KEY_ENABLE_ON_BOOT = "enableOnBoot"; -struct WifiProperties { +struct WifiSettings { bool enableOnBoot; }; -static bool load(WifiProperties& properties) { +static bool load(WifiSettings& settings) { std::map map; if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { return false; @@ -26,29 +26,29 @@ static bool load(WifiProperties& properties) { } auto enable_on_boot_string = map[SETTINGS_KEY_ENABLE_ON_BOOT]; - properties.enableOnBoot = (enable_on_boot_string == "true"); + settings.enableOnBoot = (enable_on_boot_string == "true"); return true; } -static bool save(const WifiProperties& properties) { +static bool save(const WifiSettings& settings) { std::map map; - map[SETTINGS_KEY_ENABLE_ON_BOOT] = properties.enableOnBoot ? "true" : "false"; + map[SETTINGS_KEY_ENABLE_ON_BOOT] = settings.enableOnBoot ? "true" : "false"; return file::savePropertiesFile(SETTINGS_FILE, map); } void setEnableOnBoot(bool enable) { - WifiProperties properties { .enableOnBoot = enable }; - if (!save(properties)) { + WifiSettings settings { .enableOnBoot = enable }; + if (!save(settings)) { TT_LOG_E(TAG, "Failed to save %s", SETTINGS_FILE); } } bool shouldEnableOnBoot() { - WifiProperties properties; - if (!load(properties)) { + WifiSettings settings; + if (!load(settings)) { return false; } - return properties.enableOnBoot; + return settings.enableOnBoot; } } // namespace diff --git a/Tactility/Source/BootProperties.cpp b/Tactility/Source/settings/BootSettings.cpp similarity index 79% rename from Tactility/Source/BootProperties.cpp rename to Tactility/Source/settings/BootSettings.cpp index 273dde0d..d830c9ee 100644 --- a/Tactility/Source/BootProperties.cpp +++ b/Tactility/Source/settings/BootSettings.cpp @@ -1,20 +1,18 @@ -#include "Tactility/BootProperties.h" -#include "Tactility/MountPoints.h" -#include "Tactility/file/PropertiesFile.h" -#include "Tactility/hal/sdcard/SdCardDevice.h" - -#include +#include #include +#include +#include +#include +#include -#include #include #include #include -namespace tt { +namespace tt::settings { constexpr auto* TAG = "BootProperties"; -constexpr auto* PROPERTIES_FILE_FORMAT = "{}/boot.properties"; +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"; @@ -29,7 +27,7 @@ static std::string getPropertiesFilePath() { return std::format(PROPERTIES_FILE_FORMAT, file::MOUNT_POINT_DATA); } -bool loadBootProperties(BootProperties& properties) { +bool loadBootSettings(BootSettings& properties) { const std::string path = getPropertiesFilePath(); if (!file::loadPropertiesFile(path, [&properties](auto& key, auto& value) { if (key == PROPERTIES_KEY_AUTO_START_APP_ID) { diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp new file mode 100644 index 00000000..4c8bd77c --- /dev/null +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -0,0 +1,166 @@ +#include + +#include +#include +#include + +#include +#include +#include + +namespace tt::settings::display { + +constexpr auto* TAG = "DisplaySettings"; +constexpr auto* SETTINGS_FILE = "/data/settings/display.properties"; +constexpr auto* SETTINGS_KEY_ORIENTATION = "orientation"; +constexpr auto* SETTINGS_KEY_GAMMA_CURVE = "gammaCurve"; +constexpr auto* SETTINGS_KEY_BACKLIGHT_DUTY = "backlightDuty"; + +static Orientation getDefaultOrientation() { + auto* display = lv_display_get_default(); + if (display == nullptr) { + return Orientation::Landscape; + } + + if (lv_display_get_physical_horizontal_resolution(display) > lv_display_get_physical_vertical_resolution(display)) { + return Orientation::Landscape; + } else { + return Orientation::Portrait; + } +} + +static std::string toString(Orientation orientation) { + switch (orientation) { + using enum Orientation; + case Portrait: + return "Portrait"; + case Landscape: + return "Landscape"; + case PortraitFlipped: + return "PortraitFlipped"; + case LandscapeFlipped: + return "LandscapeFlipped"; + default: + std::unreachable(); + } +} + +static bool fromString(const std::string& str, Orientation& orientation) { + if (str == "Portrait") { + orientation = Orientation::Portrait; + return true; + } else if (str == "Landscape") { + orientation = Orientation::Landscape; + return true; + } else if (str == "PortraitFlipped") { + orientation = Orientation::PortraitFlipped; + return true; + } else if (str == "LandscapeFlipped") { + orientation = Orientation::LandscapeFlipped; + return true; + } else { + return false; + } +} + +bool load(DisplaySettings& settings) { + std::map map; + if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + return false; + } + + auto orientation_entry = map.find(SETTINGS_KEY_ORIENTATION); + Orientation orientation; + if (orientation_entry == map.end() || !fromString(orientation_entry->second, orientation)) { + orientation = getDefaultOrientation(); + } + + auto gamma_entry = map.find(SETTINGS_KEY_GAMMA_CURVE); + int gamma_curve = 0; + if (gamma_entry != map.end()) { + gamma_curve = atoi(gamma_entry->second.c_str()); + } + + auto backlight_duty_entry = map.find(SETTINGS_KEY_BACKLIGHT_DUTY); + int backlight_duty = 200; // default + if (backlight_duty_entry != map.end()) { + backlight_duty = atoi(backlight_duty_entry->second.c_str()); + if (backlight_duty_entry->second != "0" && backlight_duty == 0) { + backlight_duty = 200; + } + } + + settings.orientation = orientation; + settings.gammaCurve = gamma_curve; + settings.backlightDuty = backlight_duty; + + return true; +} + +DisplaySettings getDefault() { + return DisplaySettings { + .orientation = getDefaultOrientation(), + .gammaCurve = 1, + .backlightDuty = 200 + }; +} + +DisplaySettings loadOrGetDefault() { + DisplaySettings settings; + if (!load(settings)) { + settings = getDefault(); + } + return settings; +} + +bool save(const DisplaySettings& settings) { + std::map map; + map[SETTINGS_KEY_BACKLIGHT_DUTY] = std::to_string(settings.backlightDuty); + map[SETTINGS_KEY_GAMMA_CURVE] = std::to_string(settings.gammaCurve); + map[SETTINGS_KEY_ORIENTATION] = toString(settings.orientation); + return file::savePropertiesFile(SETTINGS_FILE, map); +} + +lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) { + auto* lvgl_display = lv_display_get_default(); + auto rotation = lv_display_get_rotation(lvgl_display); + bool is_originally_landscape; + // The lvgl resolution code compensates for rotation. We have to revert the compensation to get the real display resolution + // TODO: Use info from display driver + if (rotation == LV_DISPLAY_ROTATION_0 || rotation == LV_DISPLAY_ROTATION_180) { + is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) > lv_display_get_physical_vertical_resolution(lvgl_display); + } else { + is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) < lv_display_get_physical_vertical_resolution(lvgl_display); + } + if (is_originally_landscape) { + // Landscape display + switch (orientation) { + case Orientation::Landscape: + return LV_DISPLAY_ROTATION_0; + case Orientation::Portrait: + return LV_DISPLAY_ROTATION_90; + case Orientation::LandscapeFlipped: + return LV_DISPLAY_ROTATION_180; + case Orientation::PortraitFlipped: + return LV_DISPLAY_ROTATION_270; + default: + return LV_DISPLAY_ROTATION_0; + } + } else { + // Portrait display + switch (orientation) { + case Orientation::Landscape: + return LV_DISPLAY_ROTATION_90; + case Orientation::Portrait: + return LV_DISPLAY_ROTATION_0; + case Orientation::LandscapeFlipped: + return LV_DISPLAY_ROTATION_270; + case Orientation::PortraitFlipped: + return LV_DISPLAY_ROTATION_180; + default: + return LV_DISPLAY_ROTATION_0; + } + } +} + +} // namespace diff --git a/Tactility/Source/settings/Language.cpp b/Tactility/Source/settings/Language.cpp index 9a0b6dc8..b84e669a 100644 --- a/Tactility/Source/settings/Language.cpp +++ b/Tactility/Source/settings/Language.cpp @@ -1,25 +1,25 @@ #include #include #include -#include +#include namespace tt::settings { constexpr auto* TAG = "Language"; void setLanguage(Language newLanguage) { - SettingsProperties properties; - if (!loadSettingsProperties(properties)) { + SystemSettings properties; + if (!loadSystemSettings(properties)) { return; } properties.language = newLanguage; - saveSettingsProperties(properties); + saveSystemSettings(properties); } Language getLanguage() { - SettingsProperties properties; - if (!loadSettingsProperties(properties)) { + SystemSettings properties; + if (!loadSystemSettings(properties)) { return Language::en_US; } else { return properties.language; diff --git a/Tactility/Source/settings/SettingsProperties.cpp b/Tactility/Source/settings/SystemSettings.cpp similarity index 79% rename from Tactility/Source/settings/SettingsProperties.cpp rename to Tactility/Source/settings/SystemSettings.cpp index 05e56624..67d0d347 100644 --- a/Tactility/Source/settings/SettingsProperties.cpp +++ b/Tactility/Source/settings/SystemSettings.cpp @@ -2,18 +2,18 @@ #include #include #include -#include +#include namespace tt::settings { -constexpr auto* TAG = "SettingsProperties"; -constexpr auto* FILE_PATH = "/data/settings.properties"; +constexpr auto* TAG = "SystemSettings"; +constexpr auto* FILE_PATH = "/data/system.properties"; static Mutex mutex = Mutex(); static bool cached = false; -static SettingsProperties cachedProperties; +static SystemSettings cachedProperties; -static bool loadSettingsPropertiesFromFile(SettingsProperties& properties) { +static bool loadSystemSettingsFromFile(SystemSettings& properties) { std::map map; if (!file::withLock(FILE_PATH, [&map] { return file::loadPropertiesFile(FILE_PATH, map); @@ -39,12 +39,12 @@ static bool loadSettingsPropertiesFromFile(SettingsProperties& properties) { return true; } -bool loadSettingsProperties(SettingsProperties& properties) { +bool loadSystemSettings(SystemSettings& properties) { auto scoped_lock = mutex.asScopedLock(); scoped_lock.lock(); if (!cached) { - if (!loadSettingsPropertiesFromFile(cachedProperties)) { + if (!loadSystemSettingsFromFile(cachedProperties)) { return false; } cached = true; @@ -54,7 +54,7 @@ bool loadSettingsProperties(SettingsProperties& properties) { return true; } -bool saveSettingsProperties(const SettingsProperties& properties) { +bool saveSystemSettings(const SystemSettings& properties) { auto scoped_lock = mutex.asScopedLock(); scoped_lock.lock(); diff --git a/Tactility/Source/settings/Time.cpp b/Tactility/Source/settings/Time.cpp index 48ee837e..a9cfa48e 100644 --- a/Tactility/Source/settings/Time.cpp +++ b/Tactility/Source/settings/Time.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #ifdef ESP_PLATFORM #include @@ -60,8 +60,8 @@ std::string getTimeZoneCode() { } bool isTimeFormat24Hour() { - SettingsProperties properties; - if (!loadSettingsProperties(properties)) { + SystemSettings properties; + if (!loadSystemSettings(properties)) { return true; } else { return properties.timeFormat24h; @@ -69,13 +69,13 @@ bool isTimeFormat24Hour() { } void setTimeFormat24Hour(bool show24Hour) { - SettingsProperties properties; - if (!loadSettingsProperties(properties)) { + SystemSettings properties; + if (!loadSystemSettings(properties)) { return; } properties.timeFormat24h = show24Hour; - saveSettingsProperties(properties); + saveSystemSettings(properties); } }