diff --git a/App/Source/HelloWorld/HelloWorld.cpp b/App/Source/HelloWorld/HelloWorld.cpp index f02e3fc4..ddd7d1c2 100644 --- a/App/Source/HelloWorld/HelloWorld.cpp +++ b/App/Source/HelloWorld/HelloWorld.cpp @@ -17,7 +17,7 @@ class HelloWorldApp : public App { }; extern const AppManifest hello_world_app = { - .id = "HelloWorld", - .name = "Hello World", + .appId = "HelloWorld", + .appName = "Hello World", .createApp = create }; diff --git a/Boards/CYD-4848S040C/Source/CYD4848S040C.cpp b/Boards/CYD-4848S040C/Source/CYD4848S040C.cpp index 1252f528..6d19a855 100644 --- a/Boards/CYD-4848S040C/Source/CYD4848S040C.cpp +++ b/Boards/CYD-4848S040C/Source/CYD4848S040C.cpp @@ -1,4 +1,7 @@ #include "CYD4848S040C.h" + +#include "Tactility/kernel/SystemEvents.h" +#include "Tactility/lvgl/LvglSync.h" #include "devices/St7701Display.h" #include "devices/SdCard.h" @@ -12,7 +15,7 @@ static bool initBoot() { static DeviceVector createDevices() { return { - std::reinterpret_pointer_cast(std::make_shared()), + std::make_shared(), createSdCard() }; } @@ -59,7 +62,7 @@ const Configuration cyd_4848s040c_config = { } }, .spi { - //SD Card + // SD Card & display init spi::Configuration { .device = SPI2_HOST, .dma = SPI_DMA_CH_AUTO, @@ -68,20 +71,20 @@ const Configuration cyd_4848s040c_config = { .miso_io_num = GPIO_NUM_41, .sclk_io_num = GPIO_NUM_48, .quadwp_io_num = -1, - .quadhd_io_num = -1, + .quadhd_io_num = GPIO_NUM_42, .data4_io_num = -1, .data5_io_num = -1, .data6_io_num = -1, .data7_io_num = -1, .data_io_default_level = false, - .max_transfer_sz = 8192, + .max_transfer_sz = 1024 * 128, .flags = 0, .isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO, .intr_flags = 0 }, .initMode = spi::InitMode::ByTactility, .isMutable = false, - .lock = nullptr + .lock = tt::lvgl::getSyncLock() } } }; diff --git a/Boards/CYD-4848S040C/Source/devices/SdCard.cpp b/Boards/CYD-4848S040C/Source/devices/SdCard.cpp index 53b1710c..e8def0e4 100644 --- a/Boards/CYD-4848S040C/Source/devices/SdCard.cpp +++ b/Boards/CYD-4848S040C/Source/devices/SdCard.cpp @@ -11,7 +11,9 @@ std::shared_ptr createSdCard() { GPIO_NUM_NC, GPIO_NUM_NC, GPIO_NUM_NC, - SdCardDevice::MountBehaviour::AtBoot + SdCardDevice::MountBehaviour::AtBoot, + tt::lvgl::getSyncLock(), + std::vector { GPIO_NUM_39 } ); auto sdcard = std::make_shared( diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e4d4c10..9937bb78 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,39 +1,32 @@ # Contributing -## Accepted changes +## New features and boards -Before releasing version 1.0.0, the APIs are changing rapidly. -I want to minimize the amount of changes that I have to maintain, because it limits the amount of breaking changes that I have to deal with when the APIs change. +Feel free to open an [issue](https://github.com/ByteWelder/Tactility/issues/new) +to discuss ideas you have regarding the implementation of new boards or features. -### New features +Keep in mind that the internal APIs are changing rapidly. They might change considerably in a short timespan. +This means it's likely that you get merge conflicts while developing new features or boards. -These are currently not accepted. +## Fixing things -### Visual / interaction design changes - -These are currently not accepted. I'm aware that there is a lot of room for improvement, but I want to mainly focusing on strong technical foundations before -I start building further on top of that. -Feel free to open an [issue](https://github.com/ByteWelder/Tactility/issues/new) to discuss ideas you have, if you feel like they will have a considerable impact. - -### Fixing things - -The general take here is that minor changes are not accepted at this stage. I don't want to spend my time reviewing and discussing these during the current stage of the project. +The general take here is that minor changes are not accepted at this stage. +I don't want to spend my time reviewing and discussing these during the current stage of the project. Only fixes for serious issues are accepted, like: + - Bugs - Crashes - Security issues Some examples of non-serious issues include: -- Documentation changes + +- Code documentation changes - Renaming code -- Fixes for compiler warnings that have low impact on the actual application logic (e.g. only happens on simulator when calling a logging function) +- Typographical errors +- Fixes for compiler warnings that have a low impact on the actual application logic (e.g. only happens on simulator when calling a logging function) -### New board implementations - -Please open an [issue](https://github.com/ByteWelder/Tactility/issues/new) on GitHub to discuss new boards. - -### Anything that doesn't fall in the above categories? +## Anything that doesn't fall in the above categories? Please [contact me](https://tactility.one/#/support) first! @@ -42,6 +35,13 @@ Please [contact me](https://tactility.one/#/support) first! Pull requests should only contain a single set of changes that are related to each other. That way, an approved set of changes will not be blocked by an unapproved set of changes. +## Licensing + +All contributions to a Tactility (sub)project will be licensed under the license(s) of that project. + +When third party code is used, its license must be included. +It's important that these third-party licenses are compatible with the relevant Tactility (sub)projects. + ## Code Style See [this document](CODING_STYLE.md) and [.clang-format](.clang-format). diff --git a/Data/system/app/TimeZone/search.png b/Data/system/app/TimeZone/assets/search.png similarity index 100% rename from Data/system/app/TimeZone/search.png rename to Data/system/app/TimeZone/assets/search.png diff --git a/Data/system/service/Statusbar/location.png b/Data/system/service/Statusbar/assets/location.png similarity index 100% rename from Data/system/service/Statusbar/location.png rename to Data/system/service/Statusbar/assets/location.png diff --git a/Data/system/service/Statusbar/power_0.png b/Data/system/service/Statusbar/assets/power_0.png similarity index 100% rename from Data/system/service/Statusbar/power_0.png rename to Data/system/service/Statusbar/assets/power_0.png diff --git a/Data/system/service/Statusbar/power_10.png b/Data/system/service/Statusbar/assets/power_10.png similarity index 100% rename from Data/system/service/Statusbar/power_10.png rename to Data/system/service/Statusbar/assets/power_10.png diff --git a/Data/system/service/Statusbar/power_100.png b/Data/system/service/Statusbar/assets/power_100.png similarity index 100% rename from Data/system/service/Statusbar/power_100.png rename to Data/system/service/Statusbar/assets/power_100.png diff --git a/Data/system/service/Statusbar/power_20.png b/Data/system/service/Statusbar/assets/power_20.png similarity index 100% rename from Data/system/service/Statusbar/power_20.png rename to Data/system/service/Statusbar/assets/power_20.png diff --git a/Data/system/service/Statusbar/power_30.png b/Data/system/service/Statusbar/assets/power_30.png similarity index 100% rename from Data/system/service/Statusbar/power_30.png rename to Data/system/service/Statusbar/assets/power_30.png diff --git a/Data/system/service/Statusbar/power_40.png b/Data/system/service/Statusbar/assets/power_40.png similarity index 100% rename from Data/system/service/Statusbar/power_40.png rename to Data/system/service/Statusbar/assets/power_40.png diff --git a/Data/system/service/Statusbar/power_50.png b/Data/system/service/Statusbar/assets/power_50.png similarity index 100% rename from Data/system/service/Statusbar/power_50.png rename to Data/system/service/Statusbar/assets/power_50.png diff --git a/Data/system/service/Statusbar/power_60.png b/Data/system/service/Statusbar/assets/power_60.png similarity index 100% rename from Data/system/service/Statusbar/power_60.png rename to Data/system/service/Statusbar/assets/power_60.png diff --git a/Data/system/service/Statusbar/power_70.png b/Data/system/service/Statusbar/assets/power_70.png similarity index 100% rename from Data/system/service/Statusbar/power_70.png rename to Data/system/service/Statusbar/assets/power_70.png diff --git a/Data/system/service/Statusbar/power_80.png b/Data/system/service/Statusbar/assets/power_80.png similarity index 100% rename from Data/system/service/Statusbar/power_80.png rename to Data/system/service/Statusbar/assets/power_80.png diff --git a/Data/system/service/Statusbar/power_90.png b/Data/system/service/Statusbar/assets/power_90.png similarity index 100% rename from Data/system/service/Statusbar/power_90.png rename to Data/system/service/Statusbar/assets/power_90.png diff --git a/Data/system/service/Statusbar/sdcard.png b/Data/system/service/Statusbar/assets/sdcard.png similarity index 100% rename from Data/system/service/Statusbar/sdcard.png rename to Data/system/service/Statusbar/assets/sdcard.png diff --git a/Data/system/service/Statusbar/sdcard_alert.png b/Data/system/service/Statusbar/assets/sdcard_alert.png similarity index 100% rename from Data/system/service/Statusbar/sdcard_alert.png rename to Data/system/service/Statusbar/assets/sdcard_alert.png diff --git a/Data/system/service/Statusbar/wifi_off_white.png b/Data/system/service/Statusbar/assets/wifi_off_white.png similarity index 100% rename from Data/system/service/Statusbar/wifi_off_white.png rename to Data/system/service/Statusbar/assets/wifi_off_white.png diff --git a/Data/system/service/Statusbar/wifi_scan_white.png b/Data/system/service/Statusbar/assets/wifi_scan_white.png similarity index 100% rename from Data/system/service/Statusbar/wifi_scan_white.png rename to Data/system/service/Statusbar/assets/wifi_scan_white.png diff --git a/Data/system/service/Statusbar/wifi_signal_medium_white.png b/Data/system/service/Statusbar/assets/wifi_signal_medium_white.png similarity index 100% rename from Data/system/service/Statusbar/wifi_signal_medium_white.png rename to Data/system/service/Statusbar/assets/wifi_signal_medium_white.png diff --git a/Data/system/service/Statusbar/wifi_signal_strong_white.png b/Data/system/service/Statusbar/assets/wifi_signal_strong_white.png similarity index 100% rename from Data/system/service/Statusbar/wifi_signal_strong_white.png rename to Data/system/service/Statusbar/assets/wifi_signal_strong_white.png diff --git a/Data/system/service/Statusbar/wifi_signal_weak_white.png b/Data/system/service/Statusbar/assets/wifi_signal_weak_white.png similarity index 100% rename from Data/system/service/Statusbar/wifi_signal_weak_white.png rename to Data/system/service/Statusbar/assets/wifi_signal_weak_white.png diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 8c14c0c6..a48e93e8 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -93,6 +93,7 @@ - RSS reader - Static file web server (with option to specify path and port) - Diceware +- Port TamaFi https://github.com/cifertech/TamaFi # App Store diff --git a/ExternalApps/Calculator/manifest.properties b/ExternalApps/Calculator/manifest.properties index ad8abb36..83001b50 100644 --- a/ExternalApps/Calculator/manifest.properties +++ b/ExternalApps/Calculator/manifest.properties @@ -4,10 +4,7 @@ version=0.1 sdk=0.6.0-SNAPSHOT1 platforms=esp32,esp32s3 [app] -id=com.bytewelder.calculator -version=0.1.0 +id=one.tactility.calculator +versionName=0.1.0 +versionCode=1 name=Calculator -description=Math is cool -[author] -name=ByteWelder -website=https://bytewelder.com diff --git a/ExternalApps/Calculator/tactility.py b/ExternalApps/Calculator/tactility.py index 292e61e9..faa4dfba 100644 --- a/ExternalApps/Calculator/tactility.py +++ b/ExternalApps/Calculator/tactility.py @@ -14,7 +14,7 @@ import shutil import configparser ttbuild_path = ".tactility" -ttbuild_version = "2.1.1" +ttbuild_version = "2.2.0" ttbuild_cdn = "https://cdn.tactility.one" ttbuild_sdk_json_validity = 3600 # seconds ttport = 6666 @@ -242,19 +242,12 @@ def validate_manifest(manifest): exit_with_error("Invalid manifest format: [app] not found") if not "id" in manifest["app"]: exit_with_error("Invalid manifest format: [app] id not found") - if not "version" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] version not found") + if not "versionName" in manifest["app"]: + exit_with_error("Invalid manifest format: [app] versionName not found") + if not "versionCode" in manifest["app"]: + exit_with_error("Invalid manifest format: [app] versionCode not found") if not "name" in manifest["app"]: exit_with_error("Invalid manifest format: [app] name not found") - if not "description" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] description not found") - # [author] - if not "author" in manifest: - exit_with_error("Invalid manifest format: [author] not found") - if not "name" in manifest["author"]: - exit_with_error("Invalid manifest format: [author] name not found") - if not "website" in manifest["author"]: - exit_with_error("Invalid manifest format: [author] website not found") def is_valid_manifest_platform(manifest, platform): manifest_platforms = manifest["target"]["platforms"].split(",") diff --git a/ExternalApps/GraphicsDemo/manifest.properties b/ExternalApps/GraphicsDemo/manifest.properties index 69374cbe..dc797514 100644 --- a/ExternalApps/GraphicsDemo/manifest.properties +++ b/ExternalApps/GraphicsDemo/manifest.properties @@ -4,10 +4,7 @@ version=0.1 sdk=0.6.0-SNAPSHOT1 platforms=esp32,esp32s3 [app] -id=com.bytewelder.graphicsdemo -version=0.1.0 +id=one.tactility.graphicsdemo +versionName=0.1.0 +versionCode=1 name=Graphics Demo -description=A graphics and touch driver demonstration -[author] -name=ByteWelder -website=https://bytewelder.com diff --git a/ExternalApps/GraphicsDemo/tactility.py b/ExternalApps/GraphicsDemo/tactility.py index 292e61e9..faa4dfba 100644 --- a/ExternalApps/GraphicsDemo/tactility.py +++ b/ExternalApps/GraphicsDemo/tactility.py @@ -14,7 +14,7 @@ import shutil import configparser ttbuild_path = ".tactility" -ttbuild_version = "2.1.1" +ttbuild_version = "2.2.0" ttbuild_cdn = "https://cdn.tactility.one" ttbuild_sdk_json_validity = 3600 # seconds ttport = 6666 @@ -242,19 +242,12 @@ def validate_manifest(manifest): exit_with_error("Invalid manifest format: [app] not found") if not "id" in manifest["app"]: exit_with_error("Invalid manifest format: [app] id not found") - if not "version" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] version not found") + if not "versionName" in manifest["app"]: + exit_with_error("Invalid manifest format: [app] versionName not found") + if not "versionCode" in manifest["app"]: + exit_with_error("Invalid manifest format: [app] versionCode not found") if not "name" in manifest["app"]: exit_with_error("Invalid manifest format: [app] name not found") - if not "description" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] description not found") - # [author] - if not "author" in manifest: - exit_with_error("Invalid manifest format: [author] not found") - if not "name" in manifest["author"]: - exit_with_error("Invalid manifest format: [author] name not found") - if not "website" in manifest["author"]: - exit_with_error("Invalid manifest format: [author] website not found") def is_valid_manifest_platform(manifest, platform): manifest_platforms = manifest["target"]["platforms"].split(",") diff --git a/ExternalApps/HelloWorld/manifest.properties b/ExternalApps/HelloWorld/manifest.properties index 8c1322b6..ba386934 100644 --- a/ExternalApps/HelloWorld/manifest.properties +++ b/ExternalApps/HelloWorld/manifest.properties @@ -4,10 +4,7 @@ version=0.1 sdk=0.6.0-SNAPSHOT1 platforms=esp32,esp32s3 [app] -id=com.bytewelder.helloworld -version=0.1.0 -name=Hello World -description=A demonstration app that says hi -[author] -name=ByteWelder -website=https://bytewelder.com +id=one.tactility.helloworld +versionName=0.1.0 +versionCode=1 +name=Hello World \ No newline at end of file diff --git a/ExternalApps/HelloWorld/tactility.py b/ExternalApps/HelloWorld/tactility.py index 292e61e9..faa4dfba 100644 --- a/ExternalApps/HelloWorld/tactility.py +++ b/ExternalApps/HelloWorld/tactility.py @@ -14,7 +14,7 @@ import shutil import configparser ttbuild_path = ".tactility" -ttbuild_version = "2.1.1" +ttbuild_version = "2.2.0" ttbuild_cdn = "https://cdn.tactility.one" ttbuild_sdk_json_validity = 3600 # seconds ttport = 6666 @@ -242,19 +242,12 @@ def validate_manifest(manifest): exit_with_error("Invalid manifest format: [app] not found") if not "id" in manifest["app"]: exit_with_error("Invalid manifest format: [app] id not found") - if not "version" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] version not found") + if not "versionName" in manifest["app"]: + exit_with_error("Invalid manifest format: [app] versionName not found") + if not "versionCode" in manifest["app"]: + exit_with_error("Invalid manifest format: [app] versionCode not found") if not "name" in manifest["app"]: exit_with_error("Invalid manifest format: [app] name not found") - if not "description" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] description not found") - # [author] - if not "author" in manifest: - exit_with_error("Invalid manifest format: [author] not found") - if not "name" in manifest["author"]: - exit_with_error("Invalid manifest format: [author] name not found") - if not "website" in manifest["author"]: - exit_with_error("Invalid manifest format: [author] website not found") def is_valid_manifest_platform(manifest, platform): manifest_platforms = manifest["target"]["platforms"].split(",") diff --git a/Tactility/Include/Tactility/Paths.h b/Tactility/Include/Tactility/Paths.h new file mode 100644 index 00000000..005bd6e5 --- /dev/null +++ b/Tactility/Include/Tactility/Paths.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace tt { + +bool findFirstMountedSdCardPath(std::string& path); + +std::string getSystemRootPath(); + +std::string getTempPath(); + +std::string getAppInstallPath(); + +std::string getAppInstallPath(const std::string& appId); + +std::string getUserPath(); + +std::string getAppUserPath(const std::string& appId); + +} diff --git a/Tactility/Include/Tactility/app/App.h b/Tactility/Include/Tactility/app/App.h index cf98611b..f0d14807 100644 --- a/Tactility/Include/Tactility/app/App.h +++ b/Tactility/Include/Tactility/app/App.h @@ -94,10 +94,6 @@ std::shared_ptr _Nullable getCurrentAppContext(); /** @return the currently running app (it is only ever null before the splash screen is shown) */ std::shared_ptr _Nullable getCurrentApp(); -std::string getTempPath(); - -std::string getInstallPath(); - bool install(const std::string& path); bool uninstall(const std::string& appId); diff --git a/Tactility/Include/Tactility/app/AppContext.h b/Tactility/Include/Tactility/app/AppContext.h index 6f90b8fd..d425c744 100644 --- a/Tactility/Include/Tactility/app/AppContext.h +++ b/Tactility/Include/Tactility/app/AppContext.h @@ -7,7 +7,7 @@ namespace tt::app { // Forward declarations class App; -class Paths; +class AppPaths; struct AppManifest; enum class Result; @@ -32,70 +32,10 @@ public: virtual const AppManifest& getManifest() const = 0; virtual std::shared_ptr getParameters() const = 0; - virtual std::unique_ptr getPaths() const = 0; + virtual std::unique_ptr getPaths() const = 0; virtual std::shared_ptr getApp() const = 0; }; -class Paths { - -public: - - Paths() = default; - virtual ~Paths() = default; - - /** - * Returns the directory path for the data location for an app. - * The data directory is intended to survive OS upgrades. - * The path will not end with a "/". - */ - virtual std::string getDataDirectory() const = 0; - - /** - * @see getDataDirectory(), but with LVGL prefix. - */ - virtual std::string getDataDirectoryLvgl() const = 0; - - /** - * Returns the full path for an entry inside the data location for an app. - * The data directory is intended to survive OS upgrades. - * Configuration data should be stored here. - * @param[in] childPath the path without a "/" prefix - */ - virtual std::string getDataPath(const std::string& childPath) const = 0; - - /** - * @see getDataPath(), but with LVGL prefix. - */ - virtual std::string getDataPathLvgl(const std::string& childPath) const = 0; - - /** - * Returns the directory path for the system location for an app. - * The system directory is not intended to survive OS upgrades. - * You should not store configuration data here. - * The path will not end with a "/". - * This is mainly used for core apps (system/boot/settings type). - */ - virtual std::string getSystemDirectory() const = 0; - - /** - * @see getSystemDirectory(), but with LVGL prefix. - */ - virtual std::string getSystemDirectoryLvgl() const = 0; - - /** - * Returns the full path for an entry inside the system location for an app. - * The data directory is not intended to survive OS upgrades. - * You should not store configuration data here. - * This is mainly used for core apps (system/boot/settings type). - * @param[in] childPath the path without a "/" prefix - */ - virtual std::string getSystemPath(const std::string& childPath) const = 0; - - /** - * @see getSystemPath(), but with LVGL prefix. - */ - virtual std::string getSystemPathLvgl(const std::string& childPath) const = 0; -}; } diff --git a/Tactility/Include/Tactility/app/AppManifest.h b/Tactility/Include/Tactility/app/AppManifest.h index 63f74d5f..c774e33d 100644 --- a/Tactility/Include/Tactility/app/AppManifest.h +++ b/Tactility/Include/Tactility/app/AppManifest.h @@ -63,30 +63,45 @@ struct AppManifest { constexpr static uint32_t Hidden = 1 << 1; }; + /** The version of the manifest file format */ + std::string manifestVersion = {}; + + /** The SDK version that was used to compile this app. (e.g. "0.6.0") */ + std::string targetSdk = {}; + + /** Comma-separated list of platforms, e.g. "esp32,esp32s3" */ + std::string targetPlatforms = {}; + /** The identifier by which the app is launched by the system and other apps. */ - std::string id = {}; + std::string appId = {}; /** The user-readable name of the app. Used in UI. */ - std::string name = {}; + std::string appName = {}; /** Optional icon. */ - std::string icon = {}; + std::string appIcon = {}; + + /** The version as it is displayed to the user (e.g. "1.2.0") */ + std::string appVersionName = {}; + + /** The technical version (must be incremented with new releases of the app */ + uint64_t appVersionCode = {}; /** App category helps with listing apps in Launcher, app list or settings apps. */ - Category category = Category::User; + Category appCategory = Category::User; /** Where the app is located */ - Location location = Location::internal(); + Location appLocation = Location::internal(); /** Controls various settings */ - uint32_t flags = Flags::None; + uint32_t appFlags = Flags::None; /** Create the instance of the app */ CreateApp createApp = nullptr; }; struct { - bool operator()(const std::shared_ptr& left, const std::shared_ptr& right) const { return left->name < right->name; } + bool operator()(const std::shared_ptr& left, const std::shared_ptr& right) const { return left->appName < right->appName; } } SortAppManifestByName; } // namespace diff --git a/Tactility/Include/Tactility/app/AppPaths.h b/Tactility/Include/Tactility/app/AppPaths.h new file mode 100644 index 00000000..621dd58a --- /dev/null +++ b/Tactility/Include/Tactility/app/AppPaths.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +namespace tt::app { + +// Forward declarations +class AppManifest; + +class AppPaths { + + const AppManifest& manifest; + +public: + + explicit AppPaths(const AppManifest& manifest) : manifest(manifest) {} + + /** + * The user data directory is intended to survive OS upgrades. + * The path will not end with a "/". + */ + std::string getUserDataPath() const; + + /** + * The user data directory is intended to survive OS upgrades. + * Configuration data should be stored here. + * @param[in] childPath the path without a "/" prefix + */ + std::string getUserDataPath(const std::string& childPath) const; + + /** + * You should not store configuration data here. + * The path will not end with a "/". + * This is mainly used for core apps (system/boot/settings type). + */ + std::string getAssetsDirectory() const; + + /** + * You should not store configuration data here. + * This is mainly used for core apps (system/boot/settings type). + * @param[in] childPath the path without a "/" prefix + */ + std::string getAssetsPath(const std::string& childPath) const; +}; + +} \ No newline at end of file diff --git a/Tactility/Include/Tactility/service/ServiceContext.h b/Tactility/Include/Tactility/service/ServiceContext.h index fc1cd86a..7362ebe1 100644 --- a/Tactility/Include/Tactility/service/ServiceContext.h +++ b/Tactility/Include/Tactility/service/ServiceContext.h @@ -1,14 +1,11 @@ #pragma once -#include "ServiceManifest.h" - -#include - #include namespace tt::service { -class Paths; +struct ServiceManifest; +class ServicePaths; /** * The public representation of a service instance. @@ -26,68 +23,8 @@ public: virtual const ServiceManifest& getManifest() const = 0; /** Retrieve the paths that are relevant to this service */ - virtual std::unique_ptr getPaths() const = 0; + virtual std::unique_ptr getPaths() const = 0; }; -class Paths { - -public: - - Paths() = default; - virtual ~Paths() = default; - - /** - * Returns the directory path for the data location for a service. - * The data directory is intended to survive OS upgrades. - * The path will not end with a "/". - */ - virtual std::string getDataDirectory() const = 0; - - /** - * @see getDataDirectory(), but with LVGL prefix. - */ - virtual std::string getDataDirectoryLvgl() const = 0; - - /** - * Returns the full path for an entry inside the data location for a service. - * The data directory is intended to survive OS upgrades. - * Configuration data should be stored here. - * @param[in] childPath the path without a "/" prefix - */ - virtual std::string getDataPath(const std::string& childPath) const = 0; - - /** - * @see getDataPath(), but with LVGL prefix. - */ - virtual std::string getDataPathLvgl(const std::string& childPath) const = 0; - - /** - * Returns the directory path for the system location for a service. - * The system directory is not intended to survive OS upgrades. - * You should not store configuration data here. - * The path will not end with a "/". - * This is mainly used for core services. - */ - virtual std::string getSystemDirectory() const = 0; - - /** - * @see getSystemDirectory(), but with LVGL prefix. - */ - virtual std::string getSystemDirectoryLvgl() const = 0; - - /** - * Returns the full path for an entry inside the system location for an app. - * The data directory is not intended to survive OS upgrades. - * You should not store configuration data here. - * This is mainly used for core apps (system/boot/settings type). - * @param[in] childPath the path without a "/" prefix - */ - virtual std::string getSystemPath(const std::string& childPath) const = 0; - - /** - * @see getSystemPath(), but with LVGL prefix. - */ - virtual std::string getSystemPathLvgl(const std::string& childPath) const = 0; -}; } // namespace diff --git a/Tactility/Include/Tactility/service/ServiceManifest.h b/Tactility/Include/Tactility/service/ServiceManifest.h index e55e0895..48485536 100644 --- a/Tactility/Include/Tactility/service/ServiceManifest.h +++ b/Tactility/Include/Tactility/service/ServiceManifest.h @@ -1,6 +1,6 @@ #pragma once -#include "Tactility/service/Service.h" +#include #include diff --git a/Tactility/Include/Tactility/service/ServicePaths.h b/Tactility/Include/Tactility/service/ServicePaths.h new file mode 100644 index 00000000..b9cbd524 --- /dev/null +++ b/Tactility/Include/Tactility/service/ServicePaths.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +namespace tt::service { + +// Forward declarations +class ServiceManifest; + +class ServicePaths { + + std::shared_ptr manifest; + +public: + + explicit ServicePaths(std::shared_ptr manifest) : manifest(std::move(manifest)) {} + + /** + * The user data directory is intended to survive OS upgrades. + * The path will not end with a "/". + */ + std::string getUserDataDirectory() const; + + /** + * The user data directory is intended to survive OS upgrades. + * Configuration data should be stored here. + * @param[in] childPath the path without a "/" prefix + */ + std::string getUserDataPath(const std::string& childPath) const; + + /** + * You should not store configuration data here. + * The path will not end with a "/". + */ + std::string getAssetsDirectory() const; + + /** + * You should not store configuration data here. + * @param[in] childPath the path without a "/" prefix + */ + std::string getAssetsPath(const std::string& childPath) const; +}; + +} \ No newline at end of file diff --git a/Tactility/Include/Tactility/service/gps/GpsService.h b/Tactility/Include/Tactility/service/gps/GpsService.h index f0314429..5d7b4bd0 100644 --- a/Tactility/Include/Tactility/service/gps/GpsService.h +++ b/Tactility/Include/Tactility/service/gps/GpsService.h @@ -24,7 +24,7 @@ class GpsService final : public Service { Mutex stateMutex; std::vector deviceRecords; std::shared_ptr> statePubSub = std::make_shared>(); - std::unique_ptr paths; + std::unique_ptr paths; State state = State::Off; bool startGpsDevice(GpsDeviceRecord& deviceRecord); diff --git a/Tactility/Private/Tactility/app/AppInstance.h b/Tactility/Private/Tactility/app/AppInstance.h index 7b1ce70d..974420ac 100644 --- a/Tactility/Private/Tactility/app/AppInstance.h +++ b/Tactility/Private/Tactility/app/AppInstance.h @@ -41,10 +41,10 @@ class AppInstance : public AppContext { static std::shared_ptr createApp( const std::shared_ptr& manifest ) { - if (manifest->location.isInternal()) { + if (manifest->appLocation.isInternal()) { assert(manifest->createApp != nullptr); return manifest->createApp(); - } else if (manifest->location.isExternal()) { + } else if (manifest->appLocation.isExternal()) { if (manifest->createApp != nullptr) { TT_LOG_W("", "Manifest specifies createApp, but this is not used with external apps"); } @@ -88,7 +88,7 @@ public: std::shared_ptr getParameters() const override; - std::unique_ptr getPaths() const override; + std::unique_ptr getPaths() const override; std::shared_ptr getApp() const override { return app; } }; diff --git a/Tactility/Private/Tactility/app/AppInstancePaths.h b/Tactility/Private/Tactility/app/AppInstancePaths.h deleted file mode 100644 index 46ca3b62..00000000 --- a/Tactility/Private/Tactility/app/AppInstancePaths.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "Tactility/app/AppInstance.h" - -namespace tt::app { - -class AppInstancePaths final : public Paths { - - const AppManifest& manifest; - -public: - - explicit AppInstancePaths(const AppManifest& manifest) : manifest(manifest) {} - ~AppInstancePaths() override = default; - - std::string getDataDirectory() const override; - std::string getDataDirectoryLvgl() const override; - std::string getDataPath(const std::string& childPath) const override; - std::string getDataPathLvgl(const std::string& childPath) const override; - std::string getSystemDirectory() const override; - std::string getSystemDirectoryLvgl() const override; - std::string getSystemPath(const std::string& childPath) const override; - std::string getSystemPathLvgl(const std::string& childPath) const override; -}; - -} \ No newline at end of file diff --git a/Tactility/Private/Tactility/app/AppManifestParsing.h b/Tactility/Private/Tactility/app/AppManifestParsing.h new file mode 100644 index 00000000..c2fc902b --- /dev/null +++ b/Tactility/Private/Tactility/app/AppManifestParsing.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include +#include + +namespace tt::app { + +bool isValidId(const std::string& id); + +bool parseManifest(const std::map& map, AppManifest& manifest); + +} diff --git a/Tactility/Private/Tactility/app/wifimanage/View.h b/Tactility/Private/Tactility/app/wifimanage/View.h index 475c4db3..1475a647 100644 --- a/Tactility/Private/Tactility/app/wifimanage/View.h +++ b/Tactility/Private/Tactility/app/wifimanage/View.h @@ -4,6 +4,7 @@ #include "./State.h" #include +#include #include @@ -13,7 +14,7 @@ class View final { Bindings* bindings; State* state; - std::unique_ptr paths; + std::unique_ptr paths; lv_obj_t* root = nullptr; lv_obj_t* enable_switch = nullptr; lv_obj_t* enable_on_boot_switch = nullptr; diff --git a/Tactility/Private/Tactility/service/ServiceInstance.h b/Tactility/Private/Tactility/service/ServiceInstance.h index 5d4da957..29628ffb 100644 --- a/Tactility/Private/Tactility/service/ServiceInstance.h +++ b/Tactility/Private/Tactility/service/ServiceInstance.h @@ -1,7 +1,10 @@ #pragma once -#include "Tactility/service/ServiceContext.h" -#include "Tactility/service/Service.h" +#include +#include +#include + +#include namespace tt::service { @@ -21,7 +24,7 @@ public: const ServiceManifest& getManifest() const override; /** Retrieve the paths that are relevant to this service */ - std::unique_ptr getPaths() const override; + std::unique_ptr getPaths() const override; std::shared_ptr getService() const { return service; } diff --git a/Tactility/Private/Tactility/service/ServiceInstancePaths.h b/Tactility/Private/Tactility/service/ServiceInstancePaths.h deleted file mode 100644 index a491a285..00000000 --- a/Tactility/Private/Tactility/service/ServiceInstancePaths.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Tactility/service/ServiceInstance.h" - -namespace tt::service { - -class ServiceInstancePaths final : public Paths { - -private: - - std::shared_ptr manifest; - -public: - - explicit ServiceInstancePaths(std::shared_ptr manifest) : manifest(std::move(manifest)) {} - ~ServiceInstancePaths() final = default; - - std::string getDataDirectory() const final; - std::string getDataDirectoryLvgl() const final; - std::string getDataPath(const std::string& childPath) const final; - std::string getDataPathLvgl(const std::string& childPath) const final; - std::string getSystemDirectory() const final; - std::string getSystemDirectoryLvgl() const final; - std::string getSystemPath(const std::string& childPath) const final; - std::string getSystemPathLvgl(const std::string& childPath) const final; -}; - -} \ No newline at end of file diff --git a/Tactility/Source/Paths.cpp b/Tactility/Source/Paths.cpp new file mode 100644 index 00000000..b35a847b --- /dev/null +++ b/Tactility/Source/Paths.cpp @@ -0,0 +1,56 @@ +#include + +#include +#include +#include + +#include + +namespace tt { + +bool findFirstMountedSdCardPath(std::string& path) { + // const auto sdcards = hal::findDevices(hal::Device::Type::SdCard); + bool is_set = false; + hal::findDevices(hal::Device::Type::SdCard, [&is_set, &path](const auto& device) { + if (device->isMounted()) { + path = device->getMountPath(); + is_set = true; + return false; // stop iterating + } else { + return true; + } + }); + return is_set; +} + +std::string getSystemRootPath() { + std::string root_path; + if (!findFirstMountedSdCardPath(root_path)) { + root_path = file::MOUNT_POINT_DATA; + } + return root_path; +} + +std::string getTempPath() { + return getSystemRootPath() + "/tmp"; +} + +std::string getAppInstallPath() { + return getSystemRootPath() + "/app"; +} + +std::string getUserPath() { + return getSystemRootPath() + "/user"; +} + +std::string getAppInstallPath(const std::string& appId) { + assert(app::isValidId(appId)); + return std::format("{}/{}", getAppInstallPath(), appId); +} + +std::string getAppUserPath(const std::string& appId) { + assert(app::isValidId(appId)); + return std::format("{}/app/{}", getUserPath(), appId); +} + +} \ No newline at end of file diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index f56decf7..0161f762 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -1,3 +1,5 @@ +#include "Tactility/app/AppManifestParsing.h" + #include #include #include @@ -158,29 +160,22 @@ static void registerInstalledApp(std::string path) { return; } - std::map manifest; - if (!file::loadPropertiesFile(manifest_path, manifest)) { + std::map properties; + if (!file::loadPropertiesFile(manifest_path, properties)) { TT_LOG_E(TAG, "Failed to load manifest at %s", manifest_path.c_str()); - } - - auto app_id_entry = manifest.find("[app]id"); - if (app_id_entry == manifest.end()) { - TT_LOG_E(TAG, "Failed to find app id in manifest"); return; } - auto app_name_entry = manifest.find("[app]name"); - if (app_name_entry == manifest.end()) { - TT_LOG_E(TAG, "Failed to find app name in manifest"); + app::AppManifest manifest; + if (!app::parseManifest(properties, manifest)) { + TT_LOG_E(TAG, "Failed to parse manifest at %s", manifest_path.c_str()); return; } - app::addApp({ - .id = app_id_entry->second, - .name = app_name_entry->second, - .category = app::Category::User, - .location = app::Location::external(path) - }); + manifest.appCategory = app::Category::User; + manifest.appLocation = app::Location::external(path); + + app::addApp(manifest); } static void registerInstalledApps(const std::string& path) { @@ -194,7 +189,7 @@ static void registerInstalledApps(const std::string& path) { static void registerInstalledAppsFromSdCard(const std::shared_ptr& sdcard) { auto sdcard_root_path = sdcard->getMountPath(); - auto app_path = std::format("{}/apps", sdcard_root_path); + auto app_path = std::format("{}/app", sdcard_root_path); sdcard->getLock()->lock(); if (file::isDirectory(app_path)) { registerInstalledApps(app_path); @@ -289,7 +284,7 @@ void run(const Configuration& config) { TT_LOG_I(TAG, "Starting boot app"); // The boot app takes care of registering system apps, user services and user apps addApp(app::boot::manifest); - service::loader::startApp(app::boot::manifest.id); + service::loader::startApp(app::boot::manifest.appId); TT_LOG_I(TAG, "Main dispatcher ready"); while (true) { diff --git a/Tactility/Source/app/AppInstall.cpp b/Tactility/Source/app/AppInstall.cpp index 61ee3f33..a0b9e2ff 100644 --- a/Tactility/Source/app/AppInstall.cpp +++ b/Tactility/Source/app/AppInstall.cpp @@ -1,6 +1,8 @@ -#include +#include "Tactility/Paths.h" + +#include +#include -#include #include #include #include @@ -103,130 +105,105 @@ static bool untar(const std::string& tarPath, const std::string& destinationPath return success; } -bool findFirstMountedSdCardPath(std::string& path) { - // const auto sdcards = hal::findDevices(hal::Device::Type::SdCard); - bool is_set = false; - hal::findDevices(hal::Device::Type::SdCard, [&is_set, &path](const auto& device) { - if (device->isMounted()) { - path = device->getMountPath(); - is_set = true; - return false; // stop iterating - } else { - return true; - } - }); - return is_set; -} - -std::string getTempPath() { - std::string root_path; - if (!findFirstMountedSdCardPath(root_path)) { - root_path = file::MOUNT_POINT_DATA; +void cleanupInstallDirectory(const std::string& path) { + const auto lock = file::getLock(path); + lock->lock(); + if (!file::deleteRecursively(path)) { + TT_LOG_W(TAG, "Failed to delete existing installation at %s", path.c_str()); } - return root_path + "/tmp"; -} - -std::string getInstallPath() { - std::string root_path; - if (!findFirstMountedSdCardPath(root_path)) { - root_path = file::MOUNT_POINT_DATA; - } - return root_path + "/apps"; + lock->unlock(); } bool install(const std::string& path) { - // TODO: Make better: lock for each path type properly (source vs target) - // We lock and unlock frequently because SPI SD card devices share // the lock with the display. We don't want to lock the display for very long. - auto app_parent_path = getInstallPath(); + auto app_parent_path = getAppInstallPath(); TT_LOG_I(TAG, "Installing app %s to %s", path.c_str(), app_parent_path.c_str()); - auto lock = file::getLock(app_parent_path)->asScopedLock(); + auto target_path_lock = file::getLock(app_parent_path)->asScopedLock(); - lock.lock(); + target_path_lock.lock(); auto filename = file::getLastPathSegment(path); const std::string app_target_path = std::format("{}/{}", app_parent_path, filename); if (file::isDirectory(app_target_path) && !file::deleteRecursively(app_target_path)) { TT_LOG_W(TAG, "Failed to delete %s", app_target_path.c_str()); } - lock.unlock(); + target_path_lock.unlock(); - lock.lock(); + target_path_lock.lock(); if (!file::findOrCreateDirectory(app_target_path, 0777)) { TT_LOG_I(TAG, "Failed to create directory %s", app_target_path.c_str()); return false; } - lock.unlock(); + target_path_lock.unlock(); - lock.lock(); + auto source_path_lock = file::getLock(path)->asScopedLock(); + target_path_lock.lock(); + source_path_lock.lock(); TT_LOG_I(TAG, "Extracting app from %s to %s", path.c_str(), app_target_path.c_str()); if (!untar(path, app_target_path)) { TT_LOG_E(TAG, "Failed to extract"); return false; } - lock.unlock(); + source_path_lock.unlock(); + target_path_lock.unlock(); - lock.lock(); + target_path_lock.lock(); auto manifest_path = app_target_path + "/manifest.properties"; if (!file::isFile(manifest_path)) { TT_LOG_E(TAG, "Manifest not found at %s", manifest_path.c_str()); + cleanupInstallDirectory(app_target_path); return false; } - lock.unlock(); + target_path_lock.unlock(); - lock.lock(); + target_path_lock.lock(); std::map properties; if (!file::loadPropertiesFile(manifest_path, properties)) { TT_LOG_E(TAG, "Failed to load manifest at %s", manifest_path.c_str()); + cleanupInstallDirectory(app_target_path); return false; } - lock.unlock(); + target_path_lock.unlock(); - auto app_id_iterator = properties.find("[app]id"); - if (app_id_iterator == properties.end()) { - TT_LOG_E(TAG, "Failed to find app id in manifest"); + AppManifest manifest; + if (!parseManifest(properties, manifest)) { + TT_LOG_W(TAG, "Invalid manifest"); + cleanupInstallDirectory(app_target_path); return false; } - auto app_name_entry = properties.find("[app]name"); - if (app_name_entry == properties.end()) { - TT_LOG_E(TAG, "Failed to find app name in manifest"); - return false; - } - - lock.lock(); - const std::string renamed_target_path = std::format("{}/{}", app_parent_path, app_id_iterator->second); + target_path_lock.lock(); + const std::string renamed_target_path = std::format("{}/{}", app_parent_path, manifest.appId); if (file::isDirectory(renamed_target_path)) { if (!file::deleteRecursively(renamed_target_path)) { TT_LOG_W(TAG, "Failed to delete existing installation at %s", renamed_target_path.c_str()); + cleanupInstallDirectory(app_target_path); return false; } } - lock.unlock(); + target_path_lock.unlock(); - lock.lock(); + target_path_lock.lock(); if (rename(app_target_path.c_str(), renamed_target_path.c_str()) != 0) { - TT_LOG_E(TAG, "Failed to rename %s to %s", app_target_path.c_str(), app_id_iterator->second.c_str()); + TT_LOG_E(TAG, "Failed to rename \"%s\" to \"%s\"", app_target_path.c_str(), manifest.appId.c_str()); + cleanupInstallDirectory(app_target_path); return false; } - lock.unlock(); + target_path_lock.unlock(); - addApp({ - .id = app_id_iterator->second, - .name = app_name_entry->second, - .category = Category::User, - .location = Location::external(renamed_target_path) - }); + manifest.appLocation = Location::external(renamed_target_path); + + addApp(manifest); return true; } bool uninstall(const std::string& appId) { TT_LOG_I(TAG, "Uninstalling app %s", appId.c_str()); - auto app_path = getInstallPath() + "/" + appId; - return file::withLock(app_path, [&app_path, &appId]() { + auto app_path = getAppInstallPath(appId); + return file::withLock(app_path, [&app_path, &appId] { if (!file::isDirectory(app_path)) { TT_LOG_E(TAG, "App %s not found at ", app_path.c_str()); return false; diff --git a/Tactility/Source/app/AppInstance.cpp b/Tactility/Source/app/AppInstance.cpp index 8989f32a..d3d00c54 100644 --- a/Tactility/Source/app/AppInstance.cpp +++ b/Tactility/Source/app/AppInstance.cpp @@ -1,5 +1,5 @@ -#include "Tactility/app/AppInstance.h" -#include "Tactility/app/AppInstancePaths.h" +#include +#include namespace tt::app { @@ -49,9 +49,9 @@ std::shared_ptr AppInstance::getParameters() const { return result; } -std::unique_ptr AppInstance::getPaths() const { +std::unique_ptr AppInstance::getPaths() const { assert(manifest != nullptr); - return std::make_unique(*manifest); + return std::make_unique(*manifest); } } // namespace diff --git a/Tactility/Source/app/AppInstancePaths.cpp b/Tactility/Source/app/AppInstancePaths.cpp deleted file mode 100644 index 26c073e2..00000000 --- a/Tactility/Source/app/AppInstancePaths.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "Tactility/app/AppInstancePaths.h" - -#include - -#define LVGL_PATH_PREFIX std::string("A:/") -#ifdef ESP_PLATFORM -#define PARTITION_PREFIX std::string("/") -#else -#define PARTITION_PREFIX std::string("") -#endif - -namespace tt::app { - -std::string AppInstancePaths::getDataDirectory() const { - return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/app/" + manifest.id; -} - -std::string AppInstancePaths::getDataDirectoryLvgl() const { - return LVGL_PATH_PREFIX + file::DATA_PARTITION_NAME + "/app/" + manifest.id; -} - -std::string AppInstancePaths::getDataPath(const std::string& childPath) const { - assert(!childPath.starts_with('/')); - return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/app/" + manifest.id + '/' + childPath; -} - -std::string AppInstancePaths::getDataPathLvgl(const std::string& childPath) const { - assert(!childPath.starts_with('/')); - return LVGL_PATH_PREFIX + file::DATA_PARTITION_NAME + "/app/" + manifest.id + '/' + childPath; -} - -std::string AppInstancePaths::getSystemDirectory() const { - return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/app/" + manifest.id; -} - -std::string AppInstancePaths::getSystemDirectoryLvgl() const { - return LVGL_PATH_PREFIX + file::SYSTEM_PARTITION_NAME + "/app/" + manifest.id; -} - -std::string AppInstancePaths::getSystemPath(const std::string& childPath) const { - assert(!childPath.starts_with('/')); - return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/app/" + manifest.id + '/' + childPath; -} - -std::string AppInstancePaths::getSystemPathLvgl(const std::string& childPath) const { - return LVGL_PATH_PREFIX + file::SYSTEM_PARTITION_NAME + "/app/" + manifest.id + '/' + childPath; -} - -} diff --git a/Tactility/Source/app/AppManifestParsing.cpp b/Tactility/Source/app/AppManifestParsing.cpp new file mode 100644 index 00000000..448869d1 --- /dev/null +++ b/Tactility/Source/app/AppManifestParsing.cpp @@ -0,0 +1,131 @@ +#include + +#include + +namespace tt::app { + +constexpr auto* TAG = "App"; + +static bool validateString(const std::string& value, const std::function& isValidChar) { + for (const auto& c : value) { + if (!isValidChar(c)) { + return false; + } + } + return true; +} + +static bool getValueFromManifest(const std::map& map, const std::string& key, std::string& output) { + const auto iterator = map.find(key); + if (iterator == map.end()) { + TT_LOG_E(TAG, "Failed to find %s in manifest", key.c_str()); + return false; + } + output = iterator->second; + return true; +} + +bool isValidId(const std::string& id) { + return id.size() >= 5 && validateString(id, [](const char c) { + return std::isalnum(c) != 0 || c == '.'; + }); +} + +static bool isValidManifestVersion(const std::string& version) { + return version.size() > 0 && validateString(version, [](const char c) { + return std::isalnum(c) != 0 || c == '.'; + }); +} + +static bool isValidAppVersionName(const std::string& version) { + return version.size() > 0 && validateString(version, [](const char c) { + return std::isalnum(c) != 0 || c == '.' || c == '-' || c == '_'; + }); +} + +static bool isValidAppVersionCode(const std::string& version) { + return version.size() > 0 && validateString(version, [](const char c) { + return std::isdigit(c) != 0; + }); +} + +static bool isValidName(const std::string& name) { + return name.size() >= 2 && validateString(name, [](const char c) { + return std::isalnum(c) != 0 || c == ' ' || c == '-'; + }); +} + +bool parseManifest(const std::map& map, AppManifest& manifest) { + TT_LOG_I(TAG, "Parsing manifest"); + + // [manifest] + + if (!getValueFromManifest(map, "[manifest]version", manifest.manifestVersion)) { + return false; + } + + if (!isValidManifestVersion(manifest.manifestVersion)) { + TT_LOG_E(TAG, "Invalid version"); + return false; + } + + // [app] + + if (!getValueFromManifest(map, "[app]id", manifest.appId)) { + return false; + } + + if (!isValidId(manifest.appId)) { + TT_LOG_E(TAG, "Invalid app id"); + return false; + } + + if (!getValueFromManifest(map, "[app]name", manifest.appName)) { + return false; + } + + if (!isValidName(manifest.appName)) { + TT_LOG_I(TAG, "Invalid app name"); + return false; + } + + if (!getValueFromManifest(map, "[app]versionName", manifest.appVersionName)) { + return false; + } + + if (!isValidAppVersionName(manifest.appVersionName)) { + TT_LOG_E(TAG, "Invalid app version name"); + return false; + } + + std::string version_code_string; + if (!getValueFromManifest(map, "[app]versionCode", version_code_string)) { + return false; + } + + if (!isValidAppVersionCode(version_code_string)) { + TT_LOG_E(TAG, "Invalid app version code"); + return false; + } + + manifest.appVersionCode = std::stoull(version_code_string); + + // [target] + + if (!getValueFromManifest(map, "[target]sdk", manifest.targetSdk)) { + return false; + } + + if (!getValueFromManifest(map, "[target]platforms", manifest.targetPlatforms)) { + return false; + } + + // Defaults + + manifest.appCategory = Category::User; + manifest.appLocation = Location::external(""); + + return true; +} + +} diff --git a/Tactility/Source/app/AppPaths.cpp b/Tactility/Source/app/AppPaths.cpp new file mode 100644 index 00000000..79b761f8 --- /dev/null +++ b/Tactility/Source/app/AppPaths.cpp @@ -0,0 +1,44 @@ +#include + +#include +#include +#include + +#include + +#ifdef ESP_PLATFORM +constexpr auto PARTITION_PREFIX = std::string("/"); +#else +constexpr auto PARTITION_PREFIX = std::string(""); +#endif + +namespace tt::app { + +std::string AppPaths::getUserDataPath() const { + if (manifest.appLocation.isInternal()) { + return std::format("{}{}/user/app/{}", PARTITION_PREFIX, file::DATA_PARTITION_NAME, manifest.appId); + } else { + return std::format("{}/user/app/{}", file::getFirstPathSegment(manifest.appLocation.getPath()), manifest.appId); + } +} + +std::string AppPaths::getUserDataPath(const std::string& childPath) const { + assert(!childPath.starts_with('/')); + return std::format("{}/{}", getUserDataPath(), childPath); +} + + +std::string AppPaths::getAssetsDirectory() const { + if (manifest.appLocation.isInternal()) { + return std::format("{}{}/app/{}/assets", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, manifest.appId); + } else { + return std::format("{}/assets", manifest.appLocation.getPath()); + } +} + +std::string AppPaths::getAssetsPath(const std::string& childPath) const { + assert(!childPath.starts_with('/')); + return std::format("{}/{}", getAssetsDirectory(), childPath); +} + +} diff --git a/Tactility/Source/app/AppRegistration.cpp b/Tactility/Source/app/AppRegistration.cpp index 697dfa7d..44baf640 100644 --- a/Tactility/Source/app/AppRegistration.cpp +++ b/Tactility/Source/app/AppRegistration.cpp @@ -16,15 +16,15 @@ static AppManifestMap app_manifest_map; static Mutex hash_mutex(Mutex::Type::Normal); void addApp(const AppManifest& manifest) { - TT_LOG_I(TAG, "Registering manifest %s", manifest.id.c_str()); + TT_LOG_I(TAG, "Registering manifest %s", manifest.appId.c_str()); hash_mutex.lock(); - if (app_manifest_map.contains(manifest.id)) { - TT_LOG_W(TAG, "Overwriting existing manifest for %s", manifest.id.c_str()); + if (app_manifest_map.contains(manifest.appId)) { + TT_LOG_W(TAG, "Overwriting existing manifest for %s", manifest.appId.c_str()); } - app_manifest_map[manifest.id] = std::make_shared(manifest); + app_manifest_map[manifest.appId] = std::make_shared(manifest); hash_mutex.unlock(); } diff --git a/Tactility/Source/app/ElfApp.cpp b/Tactility/Source/app/ElfApp.cpp index 4f32e60d..cae0cf4a 100644 --- a/Tactility/Source/app/ElfApp.cpp +++ b/Tactility/Source/app/ElfApp.cpp @@ -223,8 +223,8 @@ void setElfAppParameters( std::shared_ptr createElfApp(const std::shared_ptr& manifest) { TT_LOG_I(TAG, "createElfApp"); assert(manifest != nullptr); - assert(manifest->location.isExternal()); - return std::make_shared(manifest->location.getPath()); + assert(manifest->appLocation.isExternal()); + return std::make_shared(manifest->appLocation.getPath()); } } // namespace diff --git a/Tactility/Source/app/addgps/AddGps.cpp b/Tactility/Source/app/addgps/AddGps.cpp index 235bfb64..bd165f22 100644 --- a/Tactility/Source/app/addgps/AddGps.cpp +++ b/Tactility/Source/app/addgps/AddGps.cpp @@ -172,16 +172,16 @@ public: }; extern const AppManifest manifest = { - .id = "AddGps", - .name = "Add GPS", - .icon = LV_SYMBOL_GPS, - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "AddGps", + .appName = "Add GPS", + .appIcon = LV_SYMBOL_GPS, + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; void start() { - app::start(manifest.id); + app::start(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/alertdialog/AlertDialog.cpp b/Tactility/Source/app/alertdialog/AlertDialog.cpp index fabf86fa..42d92aac 100644 --- a/Tactility/Source/app/alertdialog/AlertDialog.cpp +++ b/Tactility/Source/app/alertdialog/AlertDialog.cpp @@ -28,7 +28,7 @@ LaunchId start(const std::string& title, const std::string& message, const std:: bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title); bundle->putString(PARAMETER_BUNDLE_KEY_MESSAGE, message); bundle->putString(PARAMETER_BUNDLE_KEY_BUTTON_LABELS, items_joined); - return service::loader::startApp(manifest.id, bundle); + return service::loader::startApp(manifest.appId, bundle); } LaunchId start(const std::string& title, const std::string& message) { @@ -36,7 +36,7 @@ LaunchId start(const std::string& title, const std::string& message) { bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title); bundle->putString(PARAMETER_BUNDLE_KEY_MESSAGE, message); bundle->putString(PARAMETER_BUNDLE_KEY_BUTTON_LABELS, "OK"); - return service::loader::startApp(manifest.id, bundle); + return service::loader::startApp(manifest.appId, bundle); } int32_t getResultIndex(const Bundle& bundle) { @@ -126,10 +126,10 @@ public: }; extern const AppManifest manifest = { - .id = "AlertDialog", - .name = "Alert Dialog", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "AlertDialog", + .appName = "Alert Dialog", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; diff --git a/Tactility/Source/app/applist/AppList.cpp b/Tactility/Source/app/applist/AppList.cpp index 9c232bc6..9643db1d 100644 --- a/Tactility/Source/app/applist/AppList.cpp +++ b/Tactility/Source/app/applist/AppList.cpp @@ -13,12 +13,12 @@ class AppListApp : public App { static void onAppPressed(lv_event_t* e) { const auto* manifest = static_cast(lv_event_get_user_data(e)); - service::loader::startApp(manifest->id); + service::loader::startApp(manifest->appId); } static void createAppWidget(const std::shared_ptr& manifest, lv_obj_t* list) { - const void* icon = !manifest->icon.empty() ? manifest->icon.c_str() : TT_ASSETS_APP_ICON_FALLBACK; - lv_obj_t* btn = lv_list_add_button(list, icon, manifest->name.c_str()); + const void* icon = !manifest->appIcon.empty() ? manifest->appIcon.c_str() : TT_ASSETS_APP_ICON_FALLBACK; + lv_obj_t* btn = lv_list_add_button(list, icon, manifest->appName.c_str()); lv_obj_add_event_cb(btn, &onAppPressed, LV_EVENT_SHORT_CLICKED, manifest.get()); } @@ -40,8 +40,8 @@ public: std::ranges::sort(manifests, SortAppManifestByName); for (const auto& manifest: manifests) { - bool is_valid_category = (manifest->category == Category::User) || (manifest->category == Category::System); - bool is_visible = (manifest->flags & AppManifest::Flags::Hidden) == 0u; + bool is_valid_category = (manifest->appCategory == Category::User) || (manifest->appCategory == Category::System); + bool is_visible = (manifest->appFlags & AppManifest::Flags::Hidden) == 0u; if (is_valid_category && is_visible) { createAppWidget(manifest, list); } @@ -50,10 +50,10 @@ public: }; extern const AppManifest manifest = { - .id = "AppList", - .name = "Apps", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "AppList", + .appName = "Apps", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create, }; diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 0736f90b..cfff1a46 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -163,21 +164,21 @@ public: const char* logo; // TODO: Replace with automatic asset buckets like on Android if (getSmallestDimension() < 150) { // e.g. Cardputer - logo = hal::usb::isUsbBootMode() ? "assets/logo_usb.png" : "assets/logo_small.png"; + logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo_small.png"; } else { - logo = hal::usb::isUsbBootMode() ? "assets/logo_usb.png" : "assets/logo.png"; + logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo.png"; } - const auto logo_path = paths->getSystemPathLvgl(logo); + const auto logo_path = "A:" + paths->getAssetsPath(logo); TT_LOG_I(TAG, "%s", logo_path.c_str()); lv_image_set_src(image, logo_path.c_str()); } }; extern const AppManifest manifest = { - .id = "Boot", - .name = "Boot", - .category = Category::System, - .flags = AppManifest::Flags::HideStatusBar | AppManifest::Flags::Hidden, + .appId = "Boot", + .appName = "Boot", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::HideStatusBar | AppManifest::Flags::Hidden, .createApp = create }; diff --git a/Tactility/Source/app/calculator/Calculator.cpp b/Tactility/Source/app/calculator/Calculator.cpp index 431332d8..6324474e 100644 --- a/Tactility/Source/app/calculator/Calculator.cpp +++ b/Tactility/Source/app/calculator/Calculator.cpp @@ -224,9 +224,9 @@ class CalculatorApp : public App { }; extern const AppManifest manifest = { - .id = "Calculator", - .name = "Calculator", - .icon = TT_ASSETS_APP_ICON_CALCULATOR, + .appId = "Calculator", + .appName = "Calculator", + .appIcon = TT_ASSETS_APP_ICON_CALCULATOR, .createApp = create }; diff --git a/Tactility/Source/app/chat/ChatApp.cpp b/Tactility/Source/app/chat/ChatApp.cpp index 5bd2d1ed..7a5ca044 100644 --- a/Tactility/Source/app/chat/ChatApp.cpp +++ b/Tactility/Source/app/chat/ChatApp.cpp @@ -136,9 +136,9 @@ public: }; extern const AppManifest manifest = { - .id = "Chat", - .name = "Chat", - .icon = TT_ASSETS_APP_ICON_CHAT, + .appId = "Chat", + .appName = "Chat", + .appIcon = TT_ASSETS_APP_ICON_CHAT, .createApp = create }; diff --git a/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp b/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp index 30d84169..d487e700 100644 --- a/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp +++ b/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp @@ -122,15 +122,15 @@ public: }; extern const AppManifest manifest = { - .id = "CrashDiagnostics", - .name = "Crash Diagnostics", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "CrashDiagnostics", + .appName = "Crash Diagnostics", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/development/Development.cpp b/Tactility/Source/app/development/Development.cpp index 7914e58c..28e97cff 100644 --- a/Tactility/Source/app/development/Development.cpp +++ b/Tactility/Source/app/development/Development.cpp @@ -160,14 +160,14 @@ public: }; extern const AppManifest manifest = { - .id = "Development", - .name = "Development", - .category = Category::Settings, + .appId = "Development", + .appName = "Development", + .appCategory = Category::Settings, .createApp = create }; void start() { - app::start(manifest.id); + app::start(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/display/Display.cpp b/Tactility/Source/app/display/Display.cpp index edf62f4f..21cd26f9 100644 --- a/Tactility/Source/app/display/Display.cpp +++ b/Tactility/Source/app/display/Display.cpp @@ -164,10 +164,10 @@ public: }; extern const AppManifest manifest = { - .id = "Display", - .name = "Display", - .icon = TT_ASSETS_APP_ICON_DISPLAY_SETTINGS, - .category = Category::Settings, + .appId = "Display", + .appName = "Display", + .appIcon = TT_ASSETS_APP_ICON_DISPLAY_SETTINGS, + .appCategory = Category::Settings, .createApp = create }; diff --git a/Tactility/Source/app/files/FilesApp.cpp b/Tactility/Source/app/files/FilesApp.cpp index f2dd3415..27fecd26 100644 --- a/Tactility/Source/app/files/FilesApp.cpp +++ b/Tactility/Source/app/files/FilesApp.cpp @@ -33,16 +33,16 @@ public: }; extern const AppManifest manifest = { - .id = "Files", - .name = "Files", - .icon = TT_ASSETS_APP_ICON_FILES, - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "Files", + .appName = "Files", + .appIcon = TT_ASSETS_APP_ICON_FILES, + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/fileselection/FileSelection.cpp b/Tactility/Source/app/fileselection/FileSelection.cpp index 3403a062..9f1d467d 100644 --- a/Tactility/Source/app/fileselection/FileSelection.cpp +++ b/Tactility/Source/app/fileselection/FileSelection.cpp @@ -56,24 +56,24 @@ public: }; extern const AppManifest manifest = { - .id = "FileSelection", - .name = "File Selection", - .icon = TT_ASSETS_APP_ICON_FILES, - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "FileSelection", + .appName = "File Selection", + .appIcon = TT_ASSETS_APP_ICON_FILES, + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; LaunchId startForExistingFile() { auto bundle = std::make_shared(); setMode(*bundle, Mode::Existing); - return service::loader::startApp(manifest.id, bundle); + return service::loader::startApp(manifest.appId, bundle); } LaunchId startForExistingOrNewFile() { auto bundle = std::make_shared(); setMode(*bundle, Mode::ExistingOrNew); - return service::loader::startApp(manifest.id, bundle); + return service::loader::startApp(manifest.appId, bundle); } } // namespace diff --git a/Tactility/Source/app/gpio/Gpio.cpp b/Tactility/Source/app/gpio/Gpio.cpp index b27139e3..0cda0b9a 100644 --- a/Tactility/Source/app/gpio/Gpio.cpp +++ b/Tactility/Source/app/gpio/Gpio.cpp @@ -188,10 +188,10 @@ void GpioApp::onHide(AppContext& app) { } extern const AppManifest manifest = { - .id = "Gpio", - .name = "GPIO", - .icon = TT_ASSETS_APP_ICON_GPIO, - .category = Category::System, + .appId = "Gpio", + .appName = "GPIO", + .appIcon = TT_ASSETS_APP_ICON_GPIO, + .appCategory = Category::System, .createApp = create }; diff --git a/Tactility/Source/app/gpssettings/GpsSettings.cpp b/Tactility/Source/app/gpssettings/GpsSettings.cpp index b55be040..aadeff91 100644 --- a/Tactility/Source/app/gpssettings/GpsSettings.cpp +++ b/Tactility/Source/app/gpssettings/GpsSettings.cpp @@ -58,7 +58,7 @@ class GpsSettingsApp final : public App { } void onAddGps() { - app::start(addgps::manifest.id); + app::start(addgps::manifest.appId); } void startReceivingUpdates() { @@ -344,15 +344,15 @@ public: }; extern const AppManifest manifest = { - .id = "GpsSettings", - .name = "GPS", - .icon = LV_SYMBOL_GPS, - .category = Category::Settings, + .appId = "GpsSettings", + .appName = "GPS", + .appIcon = LV_SYMBOL_GPS, + .appCategory = Category::Settings, .createApp = create }; void start() { - app::start(manifest.id); + app::start(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/i2cscanner/I2cScanner.cpp b/Tactility/Source/app/i2cscanner/I2cScanner.cpp index 28c47dbf..1063f6a3 100644 --- a/Tactility/Source/app/i2cscanner/I2cScanner.cpp +++ b/Tactility/Source/app/i2cscanner/I2cScanner.cpp @@ -69,7 +69,7 @@ public: /** Returns the app data if the app is active. Note that this could clash if the same app is started twice and a background thread is slow. */ std::shared_ptr _Nullable optApp() { auto appContext = getCurrentAppContext(); - if (appContext != nullptr && appContext->getManifest().id == manifest.id) { + if (appContext != nullptr && appContext->getManifest().appId == manifest.appId) { return std::static_pointer_cast(appContext->getApp()); } else { return nullptr; @@ -403,15 +403,15 @@ void I2cScannerApp::onScanTimerFinished() { } extern const AppManifest manifest = { - .id = "I2cScanner", - .name = "I2C Scanner", - .icon = TT_ASSETS_APP_ICON_I2C_SETTINGS, - .category = Category::System, + .appId = "I2cScanner", + .appName = "I2C Scanner", + .appIcon = TT_ASSETS_APP_ICON_I2C_SETTINGS, + .appCategory = Category::System, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/i2csettings/I2cSettings.cpp b/Tactility/Source/app/i2csettings/I2cSettings.cpp index f83491fc..bd1690fb 100644 --- a/Tactility/Source/app/i2csettings/I2cSettings.cpp +++ b/Tactility/Source/app/i2csettings/I2cSettings.cpp @@ -93,10 +93,10 @@ class I2cSettingsApp : public App { }; extern const AppManifest manifest = { - .id = "I2cSettings", - .name = "I2C", - .icon = TT_ASSETS_APP_ICON_I2C_SETTINGS, - .category = Category::Settings, + .appId = "I2cSettings", + .appName = "I2C", + .appIcon = TT_ASSETS_APP_ICON_I2C_SETTINGS, + .appCategory = Category::Settings, .createApp = create }; diff --git a/Tactility/Source/app/imageviewer/ImageViewer.cpp b/Tactility/Source/app/imageviewer/ImageViewer.cpp index 511891db..6aca9c83 100644 --- a/Tactility/Source/app/imageviewer/ImageViewer.cpp +++ b/Tactility/Source/app/imageviewer/ImageViewer.cpp @@ -60,17 +60,17 @@ class ImageViewerApp : public App { }; extern const AppManifest manifest = { - .id = "ImageViewer", - .name = "Image Viewer", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "ImageViewer", + .appName = "Image Viewer", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; void start(const std::string& file) { auto parameters = std::make_shared(); parameters->putString(IMAGE_VIEWER_FILE_ARGUMENT, file); - service::loader::startApp(manifest.id, parameters); + service::loader::startApp(manifest.appId, parameters); } } // namespace diff --git a/Tactility/Source/app/inputdialog/InputDialog.cpp b/Tactility/Source/app/inputdialog/InputDialog.cpp index 7f453120..7206fa62 100644 --- a/Tactility/Source/app/inputdialog/InputDialog.cpp +++ b/Tactility/Source/app/inputdialog/InputDialog.cpp @@ -26,7 +26,7 @@ void start(const std::string& title, const std::string& message, const std::stri bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title); bundle->putString(PARAMETER_BUNDLE_KEY_MESSAGE, message); bundle->putString(PARAMETER_BUNDLE_KEY_PREFILLED, prefilled); - service::loader::startApp(manifest.id, bundle); + service::loader::startApp(manifest.appId, bundle); } std::string getResult(const Bundle& bundle) { @@ -118,10 +118,10 @@ public: }; extern const AppManifest manifest = { - .id = "InputDialog", - .name = "Input Dialog", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "InputDialog", + .appName = "Input Dialog", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; diff --git a/Tactility/Source/app/launcher/Launcher.cpp b/Tactility/Source/app/launcher/Launcher.cpp index a9ba137a..ec4a0f8d 100644 --- a/Tactility/Source/app/launcher/Launcher.cpp +++ b/Tactility/Source/app/launcher/Launcher.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -112,9 +113,9 @@ public: const int32_t margin = is_landscape_display ? std::min(available_width / 16, button_size) : 0; const auto paths = app.getPaths(); - const auto apps_icon_path = paths->getSystemPathLvgl("assets/icon_apps.png"); - const auto files_icon_path = paths->getSystemPathLvgl("assets/icon_files.png"); - const auto settings_icon_path = paths->getSystemPathLvgl("assets/icon_settings.png"); + const auto apps_icon_path = "A:" + paths->getAssetsPath("icon_apps.png"); + const auto files_icon_path = "A:" + paths->getAssetsPath("icon_files.png"); + const auto settings_icon_path = "A:" + paths->getAssetsPath("icon_settings.png"); createAppButton(buttons_wrapper, ui_scale, apps_icon_path.c_str(), "AppList", margin); createAppButton(buttons_wrapper, ui_scale, files_icon_path.c_str(), "Files", margin); @@ -136,14 +137,15 @@ public: }; extern const AppManifest manifest = { - .id = "Launcher", - .name = "Launcher", - .category = Category::System, + .appId = "Launcher", + .appName = "Launcher", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/localesettings/LocaleSettings.cpp b/Tactility/Source/app/localesettings/LocaleSettings.cpp index bbedddc7..6234e0de 100644 --- a/Tactility/Source/app/localesettings/LocaleSettings.cpp +++ b/Tactility/Source/app/localesettings/LocaleSettings.cpp @@ -162,15 +162,15 @@ public: }; extern const AppManifest manifest = { - .id = "LocaleSettings", - .name = "Region & Language", - .icon = TT_ASSETS_APP_ICON_TIME_DATE_SETTINGS, - .category = Category::Settings, + .appId = "LocaleSettings", + .appName = "Region & Language", + .appIcon = TT_ASSETS_APP_ICON_TIME_DATE_SETTINGS, + .appCategory = Category::Settings, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/log/Log.cpp b/Tactility/Source/app/log/Log.cpp index d3815f08..14d666ab 100644 --- a/Tactility/Source/app/log/Log.cpp +++ b/Tactility/Source/app/log/Log.cpp @@ -120,10 +120,10 @@ public: }; extern const AppManifest manifest = { - .id = "Log", - .name = "Log", - .icon = LV_SYMBOL_LIST, - .category = Category::System, + .appId = "Log", + .appName = "Log", + .appIcon = LV_SYMBOL_LIST, + .appCategory = Category::System, .createApp = create }; diff --git a/Tactility/Source/app/notes/Notes.cpp b/Tactility/Source/app/notes/Notes.cpp index 949e7cd8..54fdd576 100644 --- a/Tactility/Source/app/notes/Notes.cpp +++ b/Tactility/Source/app/notes/Notes.cpp @@ -207,15 +207,15 @@ class NotesApp : public App { }; extern const AppManifest manifest = { - .id = "Notes", - .name = "Notes", - .icon = TT_ASSETS_APP_ICON_NOTES, + .appId = "Notes", + .appName = "Notes", + .appIcon = TT_ASSETS_APP_ICON_NOTES, .createApp = create }; void start(const std::string& filePath) { auto parameters = std::make_shared(); parameters->putString(NOTES_FILE_ARGUMENT, filePath); - service::loader::startApp(manifest.id, parameters); + service::loader::startApp(manifest.appId, parameters); } } // namespace tt::app::notes \ No newline at end of file diff --git a/Tactility/Source/app/power/Power.cpp b/Tactility/Source/app/power/Power.cpp index 7116da80..ea4d3eee 100644 --- a/Tactility/Source/app/power/Power.cpp +++ b/Tactility/Source/app/power/Power.cpp @@ -22,7 +22,7 @@ class PowerApp; /** Returns the app data if the app is active. Note that this could clash if the same app is started twice and a background thread is slow. */ std::shared_ptr _Nullable optApp() { auto appContext = getCurrentAppContext(); - if (appContext != nullptr && appContext->getManifest().id == manifest.id) { + if (appContext != nullptr && appContext->getManifest().appId == manifest.appId) { return std::static_pointer_cast(appContext->getApp()); } else { return nullptr; @@ -189,10 +189,10 @@ public: }; extern const AppManifest manifest = { - .id = "Power", - .name = "Power", - .icon = TT_ASSETS_APP_ICON_POWER_SETTINGS, - .category = Category::Settings, + .appId = "Power", + .appName = "Power", + .appIcon = TT_ASSETS_APP_ICON_POWER_SETTINGS, + .appCategory = Category::Settings, .createApp = create }; diff --git a/Tactility/Source/app/screenshot/Screenshot.cpp b/Tactility/Source/app/screenshot/Screenshot.cpp index b826ef07..a2068b2b 100644 --- a/Tactility/Source/app/screenshot/Screenshot.cpp +++ b/Tactility/Source/app/screenshot/Screenshot.cpp @@ -48,7 +48,7 @@ public: /** Returns the app data if the app is active. Note that this could clash if the same app is started twice and a background thread is slow. */ std::shared_ptr _Nullable optApp() { auto appContext = getCurrentAppContext(); - if (appContext != nullptr && appContext->getManifest().id == manifest.id) { + if (appContext != nullptr && appContext->getManifest().appId == manifest.appId) { return std::static_pointer_cast(appContext->getApp()); } else { return nullptr; @@ -278,10 +278,10 @@ void ScreenshotApp::onShow(AppContext& appContext, lv_obj_t* parent) { } extern const AppManifest manifest = { - .id = "Screenshot", - .name = "Screenshot", - .icon = LV_SYMBOL_IMAGE, - .category = Category::System, + .appId = "Screenshot", + .appName = "Screenshot", + .appIcon = LV_SYMBOL_IMAGE, + .appCategory = Category::System, .createApp = create }; diff --git a/Tactility/Source/app/selectiondialog/SelectionDialog.cpp b/Tactility/Source/app/selectiondialog/SelectionDialog.cpp index f23ceb10..d7251551 100644 --- a/Tactility/Source/app/selectiondialog/SelectionDialog.cpp +++ b/Tactility/Source/app/selectiondialog/SelectionDialog.cpp @@ -26,7 +26,7 @@ void start(const std::string& title, const std::vector& items) { auto bundle = std::make_shared(); bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title); bundle->putString(PARAMETER_BUNDLE_KEY_ITEMS, items_joined); - service::loader::startApp(manifest.id, bundle); + service::loader::startApp(manifest.appId, bundle); } int32_t getResultIndex(const Bundle& bundle) { @@ -112,10 +112,10 @@ public: }; extern const AppManifest manifest = { - .id = "SelectionDialog", - .name = "Selection Dialog", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "SelectionDialog", + .appName = "Selection Dialog", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; diff --git a/Tactility/Source/app/serialconsole/SerialConsole.cpp b/Tactility/Source/app/serialconsole/SerialConsole.cpp index 60165577..d0ed2496 100644 --- a/Tactility/Source/app/serialconsole/SerialConsole.cpp +++ b/Tactility/Source/app/serialconsole/SerialConsole.cpp @@ -85,10 +85,10 @@ public: }; extern const AppManifest manifest = { - .id = "SerialConsole", - .name = "Serial Console", - .icon = LV_SYMBOL_LIST, - .category = Category::System, + .appId = "SerialConsole", + .appName = "Serial Console", + .appIcon = LV_SYMBOL_LIST, + .appCategory = Category::System, .createApp = create }; diff --git a/Tactility/Source/app/settings/Settings.cpp b/Tactility/Source/app/settings/Settings.cpp index 3c41dfcb..074f5a19 100644 --- a/Tactility/Source/app/settings/Settings.cpp +++ b/Tactility/Source/app/settings/Settings.cpp @@ -12,14 +12,14 @@ namespace tt::app::settings { static void onAppPressed(lv_event_t* e) { const auto* manifest = static_cast(lv_event_get_user_data(e)); - service::loader::startApp(manifest->id); + service::loader::startApp(manifest->appId); } static void createWidget(const std::shared_ptr& manifest, void* parent) { tt_check(parent); auto* list = (lv_obj_t*)parent; - const void* icon = !manifest->icon.empty() ? manifest->icon.c_str() : TT_ASSETS_APP_ICON_FALLBACK; - auto* btn = lv_list_add_button(list, icon, manifest->name.c_str()); + const void* icon = !manifest->appIcon.empty() ? manifest->appIcon.c_str() : TT_ASSETS_APP_ICON_FALLBACK; + auto* btn = lv_list_add_button(list, icon, manifest->appName.c_str()); lv_obj_add_event_cb(btn, &onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)manifest.get()); } @@ -38,7 +38,7 @@ class SettingsApp : public App { auto manifests = getApps(); std::sort(manifests.begin(), manifests.end(), SortAppManifestByName); for (const auto& manifest: manifests) { - if (manifest->category == Category::Settings) { + if (manifest->appCategory == Category::Settings) { createWidget(manifest, list); } } @@ -46,11 +46,11 @@ class SettingsApp : public App { }; extern const AppManifest manifest = { - .id = "Settings", - .name = "Settings", - .icon = TT_ASSETS_APP_ICON_SETTINGS, - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "Settings", + .appName = "Settings", + .appIcon = TT_ASSETS_APP_ICON_SETTINGS, + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; diff --git a/Tactility/Source/app/systeminfo/SystemInfo.cpp b/Tactility/Source/app/systeminfo/SystemInfo.cpp index 397790f1..e81e535b 100644 --- a/Tactility/Source/app/systeminfo/SystemInfo.cpp +++ b/Tactility/Source/app/systeminfo/SystemInfo.cpp @@ -292,10 +292,10 @@ class SystemInfoApp final : public App { }; extern const AppManifest manifest = { - .id = "SystemInfo", - .name = "System Info", - .icon = TT_ASSETS_APP_ICON_SYSTEM_INFO, - .category = Category::System, + .appId = "SystemInfo", + .appName = "System Info", + .appIcon = TT_ASSETS_APP_ICON_SYSTEM_INFO, + .appCategory = Category::System, .createApp = create }; diff --git a/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp b/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp index e61d5149..aa5be222 100644 --- a/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp +++ b/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp @@ -57,15 +57,15 @@ public: }; extern const AppManifest manifest = { - .id = "TimeDateSettings", - .name = "Time & Date", - .icon = TT_ASSETS_APP_ICON_TIME_DATE_SETTINGS, - .category = Category::Settings, + .appId = "TimeDateSettings", + .appName = "Time & Date", + .appIcon = TT_ASSETS_APP_ICON_TIME_DATE_SETTINGS, + .appCategory = Category::Settings, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/app/timezone/TimeZone.cpp b/Tactility/Source/app/timezone/TimeZone.cpp index cad696fb..33acf794 100644 --- a/Tactility/Source/app/timezone/TimeZone.cpp +++ b/Tactility/Source/app/timezone/TimeZone.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -200,7 +201,7 @@ public: lv_obj_set_style_image_recolor_opa(icon, 255, 0); lv_obj_set_style_image_recolor(icon, lv_theme_get_color_primary(parent), 0); - std::string icon_path = app.getPaths()->getSystemPathLvgl("search.png"); + std::string icon_path = "A:" + app.getPaths()->getAssetsPath("search.png"); lv_image_set_src(icon, icon_path.c_str()); lv_obj_set_style_image_recolor(icon, lv_theme_get_color_primary(parent), 0); @@ -226,15 +227,15 @@ public: }; extern const AppManifest manifest = { - .id = "TimeZone", - .name = "Select timezone", - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "TimeZone", + .appName = "Select timezone", + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } diff --git a/Tactility/Source/app/usbsettings/UsbSettings.cpp b/Tactility/Source/app/usbsettings/UsbSettings.cpp index 257b9d23..53c2fdd1 100644 --- a/Tactility/Source/app/usbsettings/UsbSettings.cpp +++ b/Tactility/Source/app/usbsettings/UsbSettings.cpp @@ -42,10 +42,10 @@ class UsbSettingsApp : public App { }; extern const AppManifest manifest = { - .id = "UsbSettings", - .name = "USB", - .icon = LV_SYMBOL_USB, - .category = Category::Settings, + .appId = "UsbSettings", + .appName = "USB", + .appIcon = LV_SYMBOL_USB, + .appCategory = Category::Settings, .createApp = create }; diff --git a/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp b/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp index 2dfd09c1..bb2e8f02 100644 --- a/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp +++ b/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp @@ -21,7 +21,7 @@ extern const AppManifest manifest; void start(const std::string& ssid) { auto bundle = std::make_shared(); bundle->putString("ssid", ssid); - app::start(manifest.id, bundle); + app::start(manifest.appId, bundle); } class WifiApSettings : public App { @@ -241,11 +241,11 @@ public: }; extern const AppManifest manifest = { - .id = "WifiApSettings", - .name = "Wi-Fi AP Settings", - .icon = LV_SYMBOL_WIFI, - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "WifiApSettings", + .appName = "Wi-Fi AP Settings", + .appIcon = LV_SYMBOL_WIFI, + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; diff --git a/Tactility/Source/app/wificonnect/WifiConnect.cpp b/Tactility/Source/app/wificonnect/WifiConnect.cpp index 4fd8d1bb..196f3e88 100644 --- a/Tactility/Source/app/wificonnect/WifiConnect.cpp +++ b/Tactility/Source/app/wificonnect/WifiConnect.cpp @@ -94,11 +94,11 @@ void WifiConnect::onHide(TT_UNUSED AppContext& app) { } extern const AppManifest manifest = { - .id = "WifiConnect", - .name = "Wi-Fi Connect", - .icon = LV_SYMBOL_WIFI, - .category = Category::System, - .flags = AppManifest::Flags::Hidden, + .appId = "WifiConnect", + .appName = "Wi-Fi Connect", + .appIcon = LV_SYMBOL_WIFI, + .appCategory = Category::System, + .appFlags = AppManifest::Flags::Hidden, .createApp = create }; @@ -106,7 +106,7 @@ void start(const std::string& ssid, const std::string& password) { auto parameters = std::make_shared(); parameters->putString(WIFI_CONNECT_PARAM_SSID, ssid); parameters->putString(WIFI_CONNECT_PARAM_PASSWORD, password); - service::loader::startApp(manifest.id, parameters); + service::loader::startApp(manifest.appId, parameters); } bool optSsidParameter(const std::shared_ptr& bundle, std::string& ssid) { diff --git a/Tactility/Source/app/wifimanage/WifiManage.cpp b/Tactility/Source/app/wifimanage/WifiManage.cpp index a132c5fa..cd85ad85 100644 --- a/Tactility/Source/app/wifimanage/WifiManage.cpp +++ b/Tactility/Source/app/wifimanage/WifiManage.cpp @@ -133,15 +133,15 @@ void WifiManage::onHide(TT_UNUSED AppContext& app) { } extern const AppManifest manifest = { - .id = "WifiManage", - .name = "Wi-Fi", - .icon = LV_SYMBOL_WIFI, - .category = Category::Settings, + .appId = "WifiManage", + .appName = "Wi-Fi", + .appIcon = LV_SYMBOL_WIFI, + .appCategory = Category::Settings, .createApp = create }; void start() { - service::loader::startApp(manifest.id); + service::loader::startApp(manifest.appId); } } // namespace diff --git a/Tactility/Source/hal/sdcard/SdCardMounting.cpp b/Tactility/Source/hal/sdcard/SdCardMounting.cpp index 1a3079e0..00bea3cb 100644 --- a/Tactility/Source/hal/sdcard/SdCardMounting.cpp +++ b/Tactility/Source/hal/sdcard/SdCardMounting.cpp @@ -1,6 +1,8 @@ #include #include +#include + namespace tt::hal::sdcard { constexpr auto* TAG = "SdCardMounting"; @@ -15,24 +17,18 @@ static void mount(const std::shared_ptr& sdcard, const std::string }); } +static std::string getMountPath(int index, int count) { + return (count == 1) ? TT_SDCARD_MOUNT_POINT : std::format("{}{}", TT_SDCARD_MOUNT_POINT, index); +} + void mountAll() { - auto sdcards = hal::findDevices(Device::Type::SdCard); - if (!sdcards.empty()) { - if (sdcards.size() == 1) { - // Fixed mount path name - auto sdcard = sdcards[0]; - if (!sdcard->isMounted()) { - mount(sdcard, TT_SDCARD_MOUNT_POINT); - } - } else { - // Numbered mount path name - for (int i = 0; i < sdcards.size(); i++) { - auto sdcard = sdcards[i]; - if (!sdcard->isMounted()) { - std::string mount_path = TT_SDCARD_MOUNT_POINT + std::to_string(i); - mount(sdcard, mount_path); - } - } + const auto sdcards = hal::findDevices(Device::Type::SdCard); + // Numbered mount path name + for (int i = 0; i < sdcards.size(); i++) { + auto sdcard = sdcards[i]; + if (!sdcard->isMounted() && sdcard->getMountBehaviour() == SdCardDevice::MountBehaviour::AtBoot) { + std::string mount_path = getMountPath(i, sdcards.size()); + mount(sdcard, mount_path); } } } diff --git a/Tactility/Source/lvgl/Toolbar.cpp b/Tactility/Source/lvgl/Toolbar.cpp index db9e6967..8ef45540 100644 --- a/Tactility/Source/lvgl/Toolbar.cpp +++ b/Tactility/Source/lvgl/Toolbar.cpp @@ -144,7 +144,7 @@ lv_obj_t* toolbar_create(lv_obj_t* parent, const std::string& title) { } lv_obj_t* toolbar_create(lv_obj_t* parent, const app::AppContext& app) { - return toolbar_create(parent, app.getManifest().name); + return toolbar_create(parent, app.getManifest().appName); } void toolbar_set_title(lv_obj_t* obj, const std::string& title) { diff --git a/Tactility/Source/service/ServiceInstance.cpp b/Tactility/Source/service/ServiceInstance.cpp index 8ecb1768..cf76beb5 100644 --- a/Tactility/Source/service/ServiceInstance.cpp +++ b/Tactility/Source/service/ServiceInstance.cpp @@ -1,17 +1,19 @@ -#include "Tactility/service/ServiceInstance.h" -#include "Tactility/service/ServiceInstancePaths.h" +#include + +#include +#include namespace tt::service { -ServiceInstance::ServiceInstance(std::shared_ptr manifest) : +ServiceInstance::ServiceInstance(std::shared_ptr manifest) : manifest(manifest), service(manifest->createService()) {} -const service::ServiceManifest& ServiceInstance::getManifest() const { return *manifest; } +const ServiceManifest& ServiceInstance::getManifest() const { return *manifest; } -std::unique_ptr ServiceInstance::getPaths() const { - return std::make_unique(manifest); +std::unique_ptr ServiceInstance::getPaths() const { + return std::make_unique(manifest); } } \ No newline at end of file diff --git a/Tactility/Source/service/ServiceInstancePaths.cpp b/Tactility/Source/service/ServiceInstancePaths.cpp deleted file mode 100644 index c60ff123..00000000 --- a/Tactility/Source/service/ServiceInstancePaths.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Tactility/service/ServiceInstancePaths.h" - -#include "Tactility/MountPoints.h" - -#define LVGL_PATH_PREFIX std::string("A:/") - -#ifdef ESP_PLATFORM -#define PARTITION_PREFIX std::string("/") -#else -#define PARTITION_PREFIX std::string("") -#endif - -namespace tt::service { - -std::string ServiceInstancePaths::getDataDirectory() const { - return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/service/" + manifest->id; -} - -std::string ServiceInstancePaths::getDataDirectoryLvgl() const { - return LVGL_PATH_PREFIX + file::DATA_PARTITION_NAME + "/service/" + manifest->id; -} - -std::string ServiceInstancePaths::getDataPath(const std::string& childPath) const { - assert(!childPath.starts_with('/')); - return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath; -} - -std::string ServiceInstancePaths::getDataPathLvgl(const std::string& childPath) const { - assert(!childPath.starts_with('/')); - return LVGL_PATH_PREFIX + file::DATA_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath; -} - -std::string ServiceInstancePaths::getSystemDirectory() const { - return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/service/" + manifest->id; -} - -std::string ServiceInstancePaths::getSystemDirectoryLvgl() const { - return LVGL_PATH_PREFIX + file::SYSTEM_PARTITION_NAME + "/service/" + manifest->id; -} - -std::string ServiceInstancePaths::getSystemPath(const std::string& childPath) const { - assert(!childPath.starts_with('/')); - return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath; -} - -std::string ServiceInstancePaths::getSystemPathLvgl(const std::string& childPath) const { - return LVGL_PATH_PREFIX + file::SYSTEM_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath; -} - -} diff --git a/Tactility/Source/service/ServicePaths.cpp b/Tactility/Source/service/ServicePaths.cpp new file mode 100644 index 00000000..eb5db903 --- /dev/null +++ b/Tactility/Source/service/ServicePaths.cpp @@ -0,0 +1,35 @@ +#include + +#include +#include + +#include +#include + +#ifdef ESP_PLATFORM +constexpr auto PARTITION_PREFIX = std::string("/"); +#else +constexpr auto PARTITION_PREFIX = std::string(""); +#endif + +namespace tt::service { + +std::string ServicePaths::getUserDataDirectory() const { + return std::format("{}{}/service/{}", PARTITION_PREFIX, file::DATA_PARTITION_NAME, manifest->id); +} + +std::string ServicePaths::getUserDataPath(const std::string& childPath) const { + assert(!childPath.starts_with('/')); + return std::format("{}/{}", getUserDataDirectory(), childPath); +} + +std::string ServicePaths::getAssetsDirectory() const { + return std::format("{}{}/service/{}/assets", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, manifest->id); +} + +std::string ServicePaths::getAssetsPath(const std::string& childPath) const { + assert(!childPath.starts_with('/')); + return std::format("{}/{}", getAssetsDirectory(), childPath); +} + +} diff --git a/Tactility/Source/service/development/DevelopmentService.cpp b/Tactility/Source/service/development/DevelopmentService.cpp index 889ad15f..ae1a22a8 100644 --- a/Tactility/Source/service/development/DevelopmentService.cpp +++ b/Tactility/Source/service/development/DevelopmentService.cpp @@ -4,10 +4,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -247,7 +247,7 @@ esp_err_t DevelopmentService::handleAppInstall(httpd_req_t* request) { } content_left -= content_read; - const std::string tmp_path = app::getTempPath(); + const std::string tmp_path = getTempPath(); auto lock = file::getLock(tmp_path)->asScopedLock(); lock.lock(); diff --git a/Tactility/Source/service/gps/GpsConfiguration.cpp b/Tactility/Source/service/gps/GpsConfiguration.cpp index 3caa65b8..e1414e54 100644 --- a/Tactility/Source/service/gps/GpsConfiguration.cpp +++ b/Tactility/Source/service/gps/GpsConfiguration.cpp @@ -1,6 +1,6 @@ -#include "Tactility/service/gps/GpsService.h" - -#include "Tactility/file/ObjectFile.h" +#include +#include +#include #include #include @@ -17,12 +17,12 @@ bool GpsService::getConfigurationFilePath(std::string& output) const { return false; } - if (!file::findOrCreateDirectory(paths->getDataDirectory(), 0777)) { - TT_LOG_E(TAG, "Failed to find or create path %s", paths->getDataDirectory().c_str()); + if (!file::findOrCreateDirectory(paths->getUserDataDirectory(), 0777)) { + TT_LOG_E(TAG, "Failed to find or create path %s", paths->getUserDataDirectory().c_str()); return false; } - output = paths->getDataPath("config.bin"); + output = paths->getUserDataPath("config.bin"); return true; } diff --git a/Tactility/Source/service/gps/GpsService.cpp b/Tactility/Source/service/gps/GpsService.cpp index 38b27bf2..eff34464 100644 --- a/Tactility/Source/service/gps/GpsService.cpp +++ b/Tactility/Source/service/gps/GpsService.cpp @@ -1,9 +1,10 @@ -#include "Tactility/service/gps/GpsService.h" -#include "Tactility/service/ServiceManifest.h" -#include "Tactility/service/ServiceRegistration.h" +#include -#include #include +#include +#include +#include +#include using tt::hal::gps::GpsDevice; diff --git a/Tactility/Source/service/gui/GuiService.cpp b/Tactility/Source/service/gui/GuiService.cpp index e2c6ca4d..f5a4803d 100644 --- a/Tactility/Source/service/gui/GuiService.cpp +++ b/Tactility/Source/service/gui/GuiService.cpp @@ -193,7 +193,7 @@ void GuiService::requestDraw() { void GuiService::showApp(std::shared_ptr app) { lock(); if (!isStarted) { - TT_LOG_W(TAG, "Failed to show app %s: GUI not started", app->getManifest().id.c_str()); + TT_LOG_W(TAG, "Failed to show app %s: GUI not started", app->getManifest().appId.c_str()); } else { // Ensure previous app triggers onHide() logic if (appToRender != nullptr) { diff --git a/Tactility/Source/service/loader/Loader.cpp b/Tactility/Source/service/loader/Loader.cpp index 3318abe1..c2ad66f7 100644 --- a/Tactility/Source/service/loader/Loader.cpp +++ b/Tactility/Source/service/loader/Loader.cpp @@ -103,7 +103,7 @@ void LoaderService::onStartAppMessage(const std::string& id, app::LaunchId launc auto previous_app = !appStack.empty() ? appStack.top() : nullptr; auto new_app = std::make_shared(app_manifest, launchId, parameters); - new_app->mutableFlags().hideStatusbar = (app_manifest->flags & app::AppManifest::Flags::HideStatusBar); + new_app->mutableFlags().hideStatusbar = (app_manifest->appFlags & app::AppManifest::Flags::HideStatusBar); appStack.push(new_app); transitionAppToState(new_app, app::State::Initial); @@ -136,12 +136,12 @@ void LoaderService::onStopAppMessage(const std::string& id) { // Stop current app auto app_to_stop = appStack.top(); - if (app_to_stop->getManifest().id != id) { - TT_LOG_E(TAG, "Stop app: id mismatch (wanted %s but found %s on top of stack)", id.c_str(), app_to_stop->getManifest().id.c_str()); + if (app_to_stop->getManifest().appId != id) { + TT_LOG_E(TAG, "Stop app: id mismatch (wanted %s but found %s on top of stack)", id.c_str(), app_to_stop->getManifest().appId.c_str()); return; } - if (original_stack_size == 1 && app_to_stop->getManifest().name != "Boot") { + if (original_stack_size == 1 && app_to_stop->getManifest().appName != "Boot") { TT_LOG_E(TAG, "Stop app: can't stop root app"); return; } @@ -162,12 +162,12 @@ void LoaderService::onStopAppMessage(const std::string& id) { // We only expect the app to be referenced within the current scope if (app_to_stop.use_count() > 1) { - TT_LOG_W(TAG, "Memory leak: Stopped %s, but use count is %ld", app_to_stop->getManifest().id.c_str(), app_to_stop.use_count() - 1); + TT_LOG_W(TAG, "Memory leak: Stopped %s, but use count is %ld", app_to_stop->getManifest().appId.c_str(), app_to_stop.use_count() - 1); } // Refcount is expected to be 2: 1 within app_to_stop and 1 within the current scope if (app_to_stop->getApp().use_count() > 2) { - TT_LOG_W(TAG, "Memory leak: Stopped %s, but use count is %ld", app_to_stop->getManifest().id.c_str(), app_to_stop->getApp().use_count() - 2); + TT_LOG_W(TAG, "Memory leak: Stopped %s, but use count is %ld", app_to_stop->getManifest().appId.c_str(), app_to_stop->getApp().use_count() - 2); } #ifdef ESP_PLATFORM @@ -224,7 +224,7 @@ void LoaderService::transitionAppToState(const std::shared_ptr TT_LOG_I( TAG, "App \"%s\" state: %s -> %s", - app_manifest.id.c_str(), + app_manifest.appId.c_str(), appStateToString(old_state), appStateToString(state) ); @@ -263,7 +263,7 @@ app::LaunchId LoaderService::startApp(const std::string& id, std::shared_ptrgetManifest().id; + auto id = getCurrentAppContext()->getManifest().appId; dispatcherThread->dispatch([this, id]() { onStopAppMessage(id); }); diff --git a/Tactility/Source/service/screenshot/ScreenshotTask.cpp b/Tactility/Source/service/screenshot/ScreenshotTask.cpp index 4780c528..51cf728d 100644 --- a/Tactility/Source/service/screenshot/ScreenshotTask.cpp +++ b/Tactility/Source/service/screenshot/ScreenshotTask.cpp @@ -84,10 +84,10 @@ void ScreenshotTask::taskMain() { auto appContext = app::getCurrentAppContext(); if (appContext != nullptr) { const app::AppManifest& manifest = appContext->getManifest(); - if (manifest.id != last_app_id) { + if (manifest.appId != last_app_id) { kernel::delayMillis(100); - last_app_id = manifest.id; - auto filename = std::format("{}/screenshot-{}.png", work.path, manifest.id); + last_app_id = manifest.appId; + auto filename = std::format("{}/screenshot-{}.png", work.path, manifest.appId); makeScreenshot(filename); } } diff --git a/Tactility/Source/service/statusbar/Statusbar.cpp b/Tactility/Source/service/statusbar/Statusbar.cpp index 3f430f77..2130f320 100644 --- a/Tactility/Source/service/statusbar/Statusbar.cpp +++ b/Tactility/Source/service/statusbar/Statusbar.cpp @@ -1,16 +1,16 @@ #include -#include #include #include #include -#include +#include #include -#include -#include +#include #include +#include #include #include +#include namespace tt::service::statusbar { @@ -148,7 +148,7 @@ class StatusbarService final : public Service { int8_t power_icon_id; const char* power_last_icon = nullptr; - std::unique_ptr paths; + std::unique_ptr paths; void lock() const { mutex.lock(); @@ -163,7 +163,7 @@ class StatusbarService final : public Service { bool show_icon = (gps_state == gps::State::OnPending) || (gps_state == gps::State::On); if (gps_last_state != show_icon) { if (show_icon) { - auto icon_path = paths->getSystemPathLvgl(STATUSBAR_ICON_GPS); + auto icon_path = "A:" + paths->getAssetsPath(STATUSBAR_ICON_GPS); lvgl::statusbar_icon_set_image(gps_icon_id, icon_path); lvgl::statusbar_icon_set_visibility(gps_icon_id, true); } else { @@ -179,7 +179,7 @@ class StatusbarService final : public Service { const char* desired_icon = getWifiStatusIcon(radio_state, is_secure); if (wifi_last_icon != desired_icon) { if (desired_icon != nullptr) { - auto icon_path = paths->getSystemPathLvgl(desired_icon); + auto icon_path = "A:" + paths->getAssetsPath(desired_icon); lvgl::statusbar_icon_set_image(wifi_icon_id, icon_path); lvgl::statusbar_icon_set_visibility(wifi_icon_id, true); } else { @@ -193,7 +193,7 @@ class StatusbarService final : public Service { const char* desired_icon = getPowerStatusIcon(); if (power_last_icon != desired_icon) { if (desired_icon != nullptr) { - auto icon_path = paths->getSystemPathLvgl(desired_icon); + auto icon_path = "A:" + paths->getAssetsPath(desired_icon); lvgl::statusbar_icon_set_image(power_icon_id, icon_path); lvgl::statusbar_icon_set_visibility(power_icon_id, true); } else { @@ -212,7 +212,7 @@ class StatusbarService final : public Service { if (state != hal::sdcard::SdCardDevice::State::Timeout) { auto* desired_icon = getSdCardStatusIcon(state); if (sdcard_last_icon != desired_icon) { - auto icon_path = paths->getSystemPathLvgl(desired_icon); + auto icon_path = "A:" + paths->getAssetsPath(desired_icon); lvgl::statusbar_icon_set_image(sdcard_icon_id, icon_path); lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true); sdcard_last_icon = desired_icon; diff --git a/Tactility/Source/service/wifi/WifiMock.cpp b/Tactility/Source/service/wifi/WifiMock.cpp index ceaba01f..1e45277c 100644 --- a/Tactility/Source/service/wifi/WifiMock.cpp +++ b/Tactility/Source/service/wifi/WifiMock.cpp @@ -1,24 +1,19 @@ -#include "Tactility/service/wifi/Wifi.h" - #ifndef ESP_PLATFORM -#include "Tactility/service/ServiceContext.h" +#include #include #include #include #include +#include +#include namespace tt::service::wifi { -#define TAG "wifi" -#define WIFI_CONNECTED_BIT BIT0 -#define WIFI_FAIL_BIT BIT1 +constexpr auto* TAG = "Wifi"; struct Wifi { - Wifi() = default; - ~Wifi() = default; - /** @brief Locking mechanism for modifying the Wifi instance */ Mutex mutex = Mutex(Mutex::Type::Recursive); /** @brief The public event bus */ @@ -144,13 +139,13 @@ class WifiService final : public Service { public: - bool onStart(TT_UNUSED ServiceContext& service) final { + bool onStart(TT_UNUSED ServiceContext& service) override { tt_check(wifi == nullptr); wifi = new Wifi(); return true; } - void onStop(TT_UNUSED ServiceContext& service) final { + void onStop(TT_UNUSED ServiceContext& service) override { tt_check(wifi != nullptr); delete wifi; wifi = nullptr; diff --git a/TactilityC/Include/tt_app.h b/TactilityC/Include/tt_app.h index 371dd529..6c0c840d 100644 --- a/TactilityC/Include/tt_app.h +++ b/TactilityC/Include/tt_app.h @@ -31,14 +31,6 @@ bool tt_app_has_result(AppHandle handle); */ void tt_app_get_data_directory(AppPathsHandle handle, char* buffer, size_t* size); -/** Get the path to the data directory of this app, with LVGL drive letter prefix applied. - * The recommended buffer size is 256 bytes. - * @param[in] handle the app handle - * @param[out] buffer the output buffer (recommended size is 256 bytes) - * @param[inout] size used as input for maximum buffer size (including null terminator) and is set with the path string length by this function - */ -void tt_app_get_data_directory_lvgl(AppPathsHandle handle, char* buffer, size_t* size); - /** * Start an app by id. * @param[in] appId the app manifest id diff --git a/TactilityC/Source/tt_app.cpp b/TactilityC/Source/tt_app.cpp index 26bed03a..09471f9f 100644 --- a/TactilityC/Source/tt_app.cpp +++ b/TactilityC/Source/tt_app.cpp @@ -1,5 +1,6 @@ #include "tt_app.h" #include +#include #include extern "C" { @@ -38,25 +39,7 @@ void tt_app_get_data_directory(AppPathsHandle handle, char* buffer, size_t* size assert(size != nullptr); assert(*size > 0); auto paths = HANDLE_AS_APP_CONTEXT(handle)->getPaths(); - auto data_path = paths->getDataDirectory(); - auto expected_length = data_path.length() + 1; - if (*size < expected_length) { - TT_LOG_E(TAG, "Path buffer not large enough (%d < %d)", *size, expected_length); - *size = 0; - buffer[0] = 0; - return; - } - - strcpy(buffer, data_path.c_str()); - *size = data_path.length(); -} - -void tt_app_get_data_directory_lvgl(AppPathsHandle handle, char* buffer, size_t* size) { - assert(buffer != nullptr); - assert(size != nullptr); - assert(*size > 0); - auto paths = HANDLE_AS_APP_CONTEXT(handle)->getPaths(); - auto data_path = paths->getDataDirectoryLvgl(); + auto data_path = paths->getUserDataPath(); auto expected_length = data_path.length() + 1; if (*size < expected_length) { TT_LOG_E(TAG, "Path buffer not large enough (%d < %d)", *size, expected_length); diff --git a/TactilityC/Source/tt_init.cpp b/TactilityC/Source/tt_init.cpp index 32b6c2e8..34d5dfdc 100644 --- a/TactilityC/Source/tt_init.cpp +++ b/TactilityC/Source/tt_init.cpp @@ -185,7 +185,6 @@ const esp_elfsym elf_symbols[] { ESP_ELFSYM_EXPORT(tt_app_alertdialog_start), ESP_ELFSYM_EXPORT(tt_app_alertdialog_get_result_index), ESP_ELFSYM_EXPORT(tt_app_get_data_directory), - ESP_ELFSYM_EXPORT(tt_app_get_data_directory_lvgl), ESP_ELFSYM_EXPORT(tt_bundle_alloc), ESP_ELFSYM_EXPORT(tt_bundle_free), ESP_ELFSYM_EXPORT(tt_bundle_opt_bool), diff --git a/TactilityCore/Include/Tactility/Lock.h b/TactilityCore/Include/Tactility/Lock.h index fdba4680..c81411a0 100644 --- a/TactilityCore/Include/Tactility/Lock.h +++ b/TactilityCore/Include/Tactility/Lock.h @@ -43,9 +43,6 @@ public: void withLock(const std::function& onLockAcquired, const std::function& onLockFailed) const { withLock(portMAX_DELAY, onLockAcquired, onLockFailed); } - [[deprecated("use asScopedLock()")]] - std::unique_ptr scoped() const; - ScopedLock asScopedLock() const; }; diff --git a/TactilityCore/Include/Tactility/file/File.h b/TactilityCore/Include/Tactility/file/File.h index dd84ffc1..e3bb94a3 100644 --- a/TactilityCore/Include/Tactility/file/File.h +++ b/TactilityCore/Include/Tactility/file/File.h @@ -83,6 +83,8 @@ std::string getChildPath(const std::string& basePath, const std::string& childPa std::string getLastPathSegment(const std::string& path); +std::string getFirstPathSegment(const std::string& path); + typedef int (*ScandirFilter)(const dirent*); typedef bool (*ScandirSort)(const dirent&, const dirent&); diff --git a/TactilityCore/Source/Lock.cpp b/TactilityCore/Source/Lock.cpp index afd38a1a..0bce6712 100644 --- a/TactilityCore/Source/Lock.cpp +++ b/TactilityCore/Source/Lock.cpp @@ -2,10 +2,6 @@ namespace tt { -std::unique_ptr Lock::scoped() const { - return std::make_unique(*this); -} - ScopedLock Lock::asScopedLock() const { return ScopedLock(*this); } diff --git a/TactilityCore/Source/file/File.cpp b/TactilityCore/Source/file/File.cpp index 1fb5bf76..ce15e5bc 100644 --- a/TactilityCore/Source/file/File.cpp +++ b/TactilityCore/Source/file/File.cpp @@ -216,6 +216,19 @@ std::string getLastPathSegment(const std::string& path) { } } +std::string getFirstPathSegment(const std::string& path) { + if (path.empty()) { + return path; + } + auto start_index = path[0] == SEPARATOR ? 1 : 0; + auto index = path.find_first_of(SEPARATOR, start_index); + if (index != std::string::npos) { + return path.substr(0, index); + } else { + return path; + } +} + bool findOrCreateDirectory(const std::string& path, mode_t mode) { if (path.empty()) { return true;