Merge develop into main (#327)

## New features
- Implemented support for app packaging in firmware and `tactility.py`: load `.app` files instead of `.elf` files. Install apps remotely or via `FileBrowser`.
- Ensure headless mode works: all services that require LVGL can deal with the absence of a display
- Service `onStart()` is now allowed to fail (return `bool` result)
- Added and improved various file-related helper functions

## Improvements
- Completely revamped the SystemInfo app UI
- Improved Calculator UI of internal and external variant
- Fix Chat UI and removed the emoji buttons for now
- Fix for toolbar bottom padding issue in all apps

## Fixes
- Fix for allowing recursive locking for certain SPI SD cards
& more
This commit is contained in:
Ken Van Hoeylandt
2025-09-12 16:24:22 +02:00
committed by GitHub
parent 068600f98c
commit 84049658db
87 changed files with 1490 additions and 537 deletions
+6 -21
View File
@@ -38,7 +38,7 @@ static std::shared_ptr<Lock> elfManifestLock = std::make_shared<Mutex>();
class ElfApp : public App {
const std::string filePath;
const std::string appPath;
std::unique_ptr<uint8_t[]> elfFileData;
esp_elf_t elf {
.psegment = nullptr,
@@ -54,12 +54,13 @@ class ElfApp : public App {
std::string lastError = "";
bool startElf() {
TT_LOG_I(TAG, "Starting ELF %s", filePath.c_str());
const std::string elf_path = std::format("{}/elf/{}.elf", appPath, CONFIG_IDF_TARGET);
TT_LOG_I(TAG, "Starting ELF %s", elf_path.c_str());
assert(elfFileData == nullptr);
size_t size = 0;
file::withLock<void>(filePath, [this, &size]{
elfFileData = file::readBinary(filePath, size);
file::withLock<void>(elf_path, [this, &elf_path, &size]{
elfFileData = file::readBinary(elf_path, size);
});
if (elfFileData == nullptr) {
@@ -111,7 +112,7 @@ class ElfApp : public App {
public:
explicit ElfApp(std::string filePath) : filePath(std::move(filePath)) {}
explicit ElfApp(std::string appPath) : appPath(std::move(appPath)) {}
void onCreate(AppContext& appContext) override {
// Because we use global variables, we have to ensure that we are not starting 2 apps in parallel
@@ -205,22 +206,6 @@ void setElfAppManifest(
elfManifestSetCount++;
}
std::string getElfAppId(const std::string& filePath) {
return filePath;
}
void registerElfApp(const std::string& filePath) {
if (findAppById(filePath) == nullptr) {
auto manifest = AppManifest {
.id = getElfAppId(filePath),
.name = string::removeFileExtension(string::getLastPathSegment(filePath)),
.type = Type::User,
.location = Location::external(filePath)
};
addApp(manifest);
}
}
std::shared_ptr<App> createElfApp(const std::shared_ptr<AppManifest>& manifest) {
TT_LOG_I(TAG, "createElfApp");
assert(manifest != nullptr);