mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
Merge develop into main (#150)
- Update `Configuration` to use C++ vector instead of C arrays - Rename `Desktop` app to `Launcher` - Fix for hard-coded app start of `Launcher` and `CrashDiagnostics` apps. - Ensure `Launcher` icons are clickable, even if they're not loading. - Don't show error scenario for SD card in statusbar when SD card status is unknown (this happens during Mutex timeout due to LVGL rendering delays) - Cleanup deprecated `Mutex` methods. - `hal::getConfiguration()` now returns a pointer instead of a reference, just like `tt:getConfiguration()`
This commit is contained in:
parent
415096c3b2
commit
4f360741a1
|
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 724 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@ -10,16 +10,12 @@
|
|||||||
- Show error in WiFi screen (e.g. AlertDialog when SPI is not enabled and available memory is below a certain amount)
|
- Show error in WiFi screen (e.g. AlertDialog when SPI is not enabled and available memory is below a certain amount)
|
||||||
- Clean up static_cast when casting to base class.
|
- Clean up static_cast when casting to base class.
|
||||||
- M5Stack CoreS3 SD card mounts, but cannot be read. There is currently a notice about it [here](https://github.com/espressif/esp-bsp/blob/master/bsp/m5stack_core_s3/README.md).
|
- M5Stack CoreS3 SD card mounts, but cannot be read. There is currently a notice about it [here](https://github.com/espressif/esp-bsp/blob/master/bsp/m5stack_core_s3/README.md).
|
||||||
- SD card statusbar icon shows error when there's a read timeout on the SD card status. Don't show the error icon in this scenario.
|
|
||||||
- EventFlag: Fix return value of set/get/wait (the errors are weirdly mixed in)
|
- EventFlag: Fix return value of set/get/wait (the errors are weirdly mixed in)
|
||||||
- getConfiguration() in TT headless is a reference, while in TT main project it's a pointer. Make it a pointer for headless too.
|
- Consistently use either ESP_TARGET or ESP_PLATFORM
|
||||||
|
|
||||||
# TODOs
|
# TODOs
|
||||||
- Tactility.h config: List of apps and services can be a std::vector (get rid of TT_CONFIG_SERVICES_LIMIT and TT_CONFIG_APPS_LIMIT)
|
|
||||||
- Boot hooks instead of a single boot method in config. Define different boot phases/levels in enum.
|
- Boot hooks instead of a single boot method in config. Define different boot phases/levels in enum.
|
||||||
- Rename "Desktop" to "Launcher" because it more clearly communicates its purpose
|
|
||||||
- Add toggle to Display app for sysmon overlay: https://docs.lvgl.io/master/API/others/sysmon/index.html
|
- Add toggle to Display app for sysmon overlay: https://docs.lvgl.io/master/API/others/sysmon/index.html
|
||||||
- Mutex: Cleanup deprecated methods
|
|
||||||
- CrashHandler: use "corrupted" flag
|
- CrashHandler: use "corrupted" flag
|
||||||
- CrashHandler: process other types of crashes (WDT?)
|
- CrashHandler: process other types of crashes (WDT?)
|
||||||
- Call tt::lvgl::isSyncSet after HAL init and show error (and crash?) when it is not set.
|
- Call tt::lvgl::isSyncSet after HAL init and show error (and crash?) when it is not set.
|
||||||
@ -30,7 +26,6 @@
|
|||||||
- Audio player app
|
- Audio player app
|
||||||
- Audio recording app
|
- Audio recording app
|
||||||
- T-Deck: Use knob for UI selection
|
- T-Deck: Use knob for UI selection
|
||||||
- Logging to disk/etc.
|
|
||||||
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
||||||
- AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
- AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
||||||
- Loader: Use main dispatcher instead of Thread
|
- Loader: Use main dispatcher instead of Thread
|
||||||
@ -39,7 +34,6 @@
|
|||||||
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
|
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
|
||||||
- Localisation of texts (load in boot app from sd?)
|
- Localisation of texts (load in boot app from sd?)
|
||||||
- Explore LVGL9's FreeRTOS functionality
|
- Explore LVGL9's FreeRTOS functionality
|
||||||
- Replace M5Unified and M5GFX with custom drivers (so we can fix the Core2 SD card mounting bug, and so we regain some firmware space)
|
|
||||||
- External app loading: Check version of Tactility and check ESP target hardware, to check for compatibility.
|
- External app loading: Check version of Tactility and check ESP target hardware, to check for compatibility.
|
||||||
- Scanning SD card for external apps and auto-register them (in a temporary register?)
|
- Scanning SD card for external apps and auto-register them (in a temporary register?)
|
||||||
- tt::app::start() and similar functions as proxies for Loader app start/stop/etc.
|
- tt::app::start() and similar functions as proxies for Loader app start/stop/etc.
|
||||||
@ -57,6 +51,7 @@
|
|||||||
- Wrapper for Slider that shows "+" and "-" buttons, and also the value in a label.
|
- Wrapper for Slider that shows "+" and "-" buttons, and also the value in a label.
|
||||||
- Display app: Add toggle to display performance measurement overlay (consider showing FPS in statusbar!)
|
- Display app: Add toggle to display performance measurement overlay (consider showing FPS in statusbar!)
|
||||||
- Files app: copy/paste actions
|
- Files app: copy/paste actions
|
||||||
|
- On crash, try to save current log to flash or SD card? (this is risky, though, so ask in Discord first)
|
||||||
|
|
||||||
# App Ideas
|
# App Ideas
|
||||||
- USB implementation to make device act as mass storage device.
|
- USB implementation to make device act as mass storage device.
|
||||||
|
|||||||
@ -40,7 +40,6 @@ namespace app {
|
|||||||
namespace alertdialog { extern const AppManifest manifest; }
|
namespace alertdialog { extern const AppManifest manifest; }
|
||||||
namespace applist { extern const AppManifest manifest; }
|
namespace applist { extern const AppManifest manifest; }
|
||||||
namespace boot { extern const AppManifest manifest; }
|
namespace boot { extern const AppManifest manifest; }
|
||||||
namespace desktop { extern const AppManifest manifest; }
|
|
||||||
namespace files { extern const AppManifest manifest; }
|
namespace files { extern const AppManifest manifest; }
|
||||||
namespace gpio { extern const AppManifest manifest; }
|
namespace gpio { extern const AppManifest manifest; }
|
||||||
namespace display { extern const AppManifest manifest; }
|
namespace display { extern const AppManifest manifest; }
|
||||||
@ -48,6 +47,7 @@ namespace app {
|
|||||||
namespace i2csettings { extern const AppManifest manifest; }
|
namespace i2csettings { extern const AppManifest manifest; }
|
||||||
namespace imageviewer { extern const AppManifest manifest; }
|
namespace imageviewer { extern const AppManifest manifest; }
|
||||||
namespace inputdialog { extern const AppManifest manifest; }
|
namespace inputdialog { extern const AppManifest manifest; }
|
||||||
|
namespace launcher { extern const AppManifest manifest; }
|
||||||
namespace log { extern const AppManifest manifest; }
|
namespace log { extern const AppManifest manifest; }
|
||||||
namespace power { extern const AppManifest manifest; }
|
namespace power { extern const AppManifest manifest; }
|
||||||
namespace selectiondialog { extern const AppManifest manifest; }
|
namespace selectiondialog { extern const AppManifest manifest; }
|
||||||
@ -74,7 +74,6 @@ static const std::vector<const app::AppManifest*> system_apps = {
|
|||||||
&app::alertdialog::manifest,
|
&app::alertdialog::manifest,
|
||||||
&app::applist::manifest,
|
&app::applist::manifest,
|
||||||
&app::boot::manifest,
|
&app::boot::manifest,
|
||||||
&app::desktop::manifest,
|
|
||||||
&app::display::manifest,
|
&app::display::manifest,
|
||||||
&app::files::manifest,
|
&app::files::manifest,
|
||||||
&app::gpio::manifest,
|
&app::gpio::manifest,
|
||||||
@ -82,6 +81,7 @@ static const std::vector<const app::AppManifest*> system_apps = {
|
|||||||
&app::i2csettings::manifest,
|
&app::i2csettings::manifest,
|
||||||
&app::imageviewer::manifest,
|
&app::imageviewer::manifest,
|
||||||
&app::inputdialog::manifest,
|
&app::inputdialog::manifest,
|
||||||
|
&app::launcher::manifest,
|
||||||
&app::log::manifest,
|
&app::log::manifest,
|
||||||
&app::settings::manifest,
|
&app::settings::manifest,
|
||||||
&app::selectiondialog::manifest,
|
&app::selectiondialog::manifest,
|
||||||
@ -104,7 +104,7 @@ static const std::vector<const app::AppManifest*> system_apps = {
|
|||||||
|
|
||||||
static void register_system_apps() {
|
static void register_system_apps() {
|
||||||
TT_LOG_I(TAG, "Registering default apps");
|
TT_LOG_I(TAG, "Registering default apps");
|
||||||
for (const auto& app_manifest: system_apps) {
|
for (const auto* app_manifest: system_apps) {
|
||||||
addApp(app_manifest);
|
addApp(app_manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,16 +113,11 @@ static void register_system_apps() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_user_apps(const app::AppManifest* const apps[TT_CONFIG_APPS_LIMIT]) {
|
static void register_user_apps(const std::vector<const app::AppManifest*>& apps) {
|
||||||
TT_LOG_I(TAG, "Registering user apps");
|
TT_LOG_I(TAG, "Registering user apps");
|
||||||
for (size_t i = 0; i < TT_CONFIG_APPS_LIMIT; i++) {
|
for (auto* manifest : apps) {
|
||||||
const app::AppManifest* manifest = apps[i];
|
assert(manifest != nullptr);
|
||||||
if (manifest != nullptr) {
|
addApp(manifest);
|
||||||
addApp(manifest);
|
|
||||||
} else {
|
|
||||||
// reached end of list
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,17 +129,12 @@ static void register_and_start_system_services() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_and_start_user_services(const service::ServiceManifest* const services[TT_CONFIG_SERVICES_LIMIT]) {
|
static void register_and_start_user_services(const std::vector<const service::ServiceManifest*>& services) {
|
||||||
TT_LOG_I(TAG, "Registering and starting user services");
|
TT_LOG_I(TAG, "Registering and starting user services");
|
||||||
for (size_t i = 0; i < TT_CONFIG_SERVICES_LIMIT; i++) {
|
for (auto* manifest : services) {
|
||||||
const service::ServiceManifest* manifest = services[i];
|
assert(manifest != nullptr);
|
||||||
if (manifest != nullptr) {
|
addService(manifest);
|
||||||
addService(manifest);
|
tt_check(service::startService(manifest->id));
|
||||||
tt_check(service::startService(manifest->id));
|
|
||||||
} else {
|
|
||||||
// reached end of list
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,9 +14,9 @@ struct Configuration {
|
|||||||
/** HAL configuration (drivers) */
|
/** HAL configuration (drivers) */
|
||||||
const hal::Configuration* hardware;
|
const hal::Configuration* hardware;
|
||||||
/** List of user applications */
|
/** List of user applications */
|
||||||
const app::AppManifest* const apps[TT_CONFIG_APPS_LIMIT] = {};
|
const std::vector<const app::AppManifest*> apps;
|
||||||
/** List of user services */
|
/** List of user services */
|
||||||
const service::ServiceManifest* const services[TT_CONFIG_SERVICES_LIMIT] = {};
|
const std::vector<const service::ServiceManifest*> services;
|
||||||
/** Optional app to start automatically after the splash screen. */
|
/** Optional app to start automatically after the splash screen. */
|
||||||
const char* _Nullable autoStartAppId = nullptr;
|
const char* _Nullable autoStartAppId = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,9 +4,6 @@
|
|||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "TactilityHeadlessConfig.h"
|
|
||||||
|
|
||||||
#define TT_CONFIG_APPS_LIMIT 32
|
|
||||||
#define TT_CONFIG_FORCE_ONSCREEN_KEYBOARD false // for development/debug purposes
|
#define TT_CONFIG_FORCE_ONSCREEN_KEYBOARD false // for development/debug purposes
|
||||||
#define TT_SCREENSHOT_MODE false // for taking screenshots (e.g. forces SD card presence and Files tree on simulator)
|
#define TT_SCREENSHOT_MODE false // for taking screenshots (e.g. forces SD card presence and Files tree on simulator)
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,8 @@ class AppContext;
|
|||||||
enum Type {
|
enum Type {
|
||||||
/** Boot screen, shown before desktop is launched. */
|
/** Boot screen, shown before desktop is launched. */
|
||||||
TypeBoot,
|
TypeBoot,
|
||||||
/** A desktop app sits at the root of the app stack managed by the Loader service */
|
/** A launcher app sits at the root of the app stack after the boot splash is finished */
|
||||||
TypeDesktop,
|
TypeLauncher,
|
||||||
/** Apps that generally aren't started from the desktop (e.g. image viewer) */
|
/** Apps that generally aren't started from the desktop (e.g. image viewer) */
|
||||||
TypeHidden,
|
TypeHidden,
|
||||||
/** Standard apps, provided by the system. */
|
/** Standard apps, provided by the system. */
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include "Assets.h"
|
|
||||||
#include "TactilityCore.h"
|
#include "TactilityCore.h"
|
||||||
|
|
||||||
#include "app/AppContext.h"
|
#include "app/AppContext.h"
|
||||||
#include "app/display/DisplaySettings.h"
|
#include "app/display/DisplaySettings.h"
|
||||||
|
#include "app/launcher/Launcher.h"
|
||||||
#include "hal/Display.h"
|
#include "hal/Display.h"
|
||||||
#include "service/loader/Loader.h"
|
#include "service/loader/Loader.h"
|
||||||
#include "lvgl/Style.h"
|
#include "lvgl/Style.h"
|
||||||
@ -14,6 +14,7 @@
|
|||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include "kernel/PanicHandler.h"
|
#include "kernel/PanicHandler.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#include "app/crashdiagnostics/CrashDiagnostics.h"
|
||||||
#else
|
#else
|
||||||
#define CONFIG_TT_SPLASH_DURATION 0
|
#define CONFIG_TT_SPLASH_DURATION 0
|
||||||
#endif
|
#endif
|
||||||
@ -62,32 +63,29 @@ static int32_t bootThreadCallback(TT_UNUSED void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void startNextApp() {
|
|
||||||
auto config = tt::getConfiguration();
|
|
||||||
std::string next_app;
|
|
||||||
if (config->autoStartAppId) {
|
|
||||||
TT_LOG_I(TAG, "init auto-starting %s", config->autoStartAppId);
|
|
||||||
next_app = config->autoStartAppId;
|
|
||||||
} else {
|
|
||||||
next_app = "Desktop";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static void startNextApp() {
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
esp_reset_reason_t reason = esp_reset_reason();
|
esp_reset_reason_t reason = esp_reset_reason();
|
||||||
if (reason == ESP_RST_PANIC) {
|
if (reason == ESP_RST_PANIC) {
|
||||||
tt::service::loader::startApp("CrashDiagnostics");
|
app::crashdiagnostics::start();
|
||||||
} else {
|
return;
|
||||||
tt::service::loader::startApp(next_app);
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
tt::service::loader::startApp(next_app);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto* config = tt::getConfiguration();
|
||||||
|
if (config->autoStartAppId) {
|
||||||
|
TT_LOG_I(TAG, "init auto-starting %s", config->autoStartAppId);
|
||||||
|
tt::service::loader::startApp(config->autoStartAppId);
|
||||||
|
} else {
|
||||||
|
app::launcher::start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) {
|
static void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) {
|
||||||
auto data = std::static_pointer_cast<Data>(app.getData());
|
auto data = std::static_pointer_cast<Data>(app.getData());
|
||||||
|
|
||||||
lv_obj_t* image = lv_image_create(parent);
|
auto* image = lv_image_create(parent);
|
||||||
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
|
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
|
||||||
|
|
||||||
auto paths = app.getPaths();
|
auto paths = app.getPaths();
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#include <esp_private/panic_internal.h>
|
|
||||||
#include "lvgl.h"
|
#include "lvgl.h"
|
||||||
#include "lvgl/Statusbar.h"
|
#include "lvgl/Statusbar.h"
|
||||||
#include "service/loader/Loader.h"
|
#include "app/launcher/Launcher.h"
|
||||||
#include "qrcode.h"
|
#include "qrcode.h"
|
||||||
#include "QrHelpers.h"
|
#include "QrHelpers.h"
|
||||||
#include "QrUrl.h"
|
#include "QrUrl.h"
|
||||||
|
#include "service/loader/Loader.h"
|
||||||
|
|
||||||
#define TAG "crash_diagnostics"
|
#define TAG "crash_diagnostics"
|
||||||
|
|
||||||
@ -14,10 +14,10 @@ namespace tt::app::crashdiagnostics {
|
|||||||
|
|
||||||
void onContinuePressed(TT_UNUSED lv_event_t* event) {
|
void onContinuePressed(TT_UNUSED lv_event_t* event) {
|
||||||
tt::service::loader::stopApp();
|
tt::service::loader::stopApp();
|
||||||
tt::service::loader::startApp("Desktop");
|
tt::app::launcher::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) {
|
static void onShow(AppContext& app, lv_obj_t* parent) {
|
||||||
auto* display = lv_obj_get_display(parent);
|
auto* display = lv_obj_get_display(parent);
|
||||||
int32_t parent_height = lv_display_get_vertical_resolution(display) - STATUSBAR_HEIGHT;
|
int32_t parent_height = lv_display_get_vertical_resolution(display) - STATUSBAR_HEIGHT;
|
||||||
|
|
||||||
@ -116,6 +116,10 @@ extern const AppManifest manifest = {
|
|||||||
.onShow = onShow
|
.onShow = onShow
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
service::loader::startApp(manifest.id);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
11
Tactility/Source/app/crashdiagnostics/CrashDiagnostics.h
Normal file
11
Tactility/Source/app/crashdiagnostics/CrashDiagnostics.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
|
namespace tt::app::crashdiagnostics {
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -5,7 +5,7 @@
|
|||||||
#include "service/loader/Loader.h"
|
#include "service/loader/Loader.h"
|
||||||
#include "Assets.h"
|
#include "Assets.h"
|
||||||
|
|
||||||
namespace tt::app::desktop {
|
namespace tt::app::launcher {
|
||||||
|
|
||||||
static void onAppPressed(TT_UNUSED lv_event_t* e) {
|
static void onAppPressed(TT_UNUSED lv_event_t* e) {
|
||||||
auto* appId = (const char*)lv_event_get_user_data(e);
|
auto* appId = (const char*)lv_event_get_user_data(e);
|
||||||
@ -33,6 +33,8 @@ static lv_obj_t* createAppButton(lv_obj_t* parent, const char* title, const char
|
|||||||
lv_obj_add_event_cb(apps_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)appId);
|
lv_obj_add_event_cb(apps_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)appId);
|
||||||
lv_obj_set_style_image_recolor(button_image, lv_theme_get_color_primary(parent), 0);
|
lv_obj_set_style_image_recolor(button_image, lv_theme_get_color_primary(parent), 0);
|
||||||
lv_obj_set_style_image_recolor_opa(button_image, LV_OPA_COVER, 0);
|
lv_obj_set_style_image_recolor_opa(button_image, LV_OPA_COVER, 0);
|
||||||
|
// Ensure buttons are still tappable when asset fails to load
|
||||||
|
lv_obj_set_size(button_image, 64, 64);
|
||||||
|
|
||||||
auto* label = lv_label_create(wrapper);
|
auto* label = lv_label_create(wrapper);
|
||||||
lv_label_set_text(label, title);
|
lv_label_set_text(label, title);
|
||||||
@ -73,10 +75,14 @@ static void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern const AppManifest manifest = {
|
extern const AppManifest manifest = {
|
||||||
.id = "Desktop",
|
.id = "Launcher",
|
||||||
.name = "Desktop",
|
.name = "Launcher",
|
||||||
.type = TypeDesktop,
|
.type = TypeLauncher,
|
||||||
.onShow = onShow,
|
.onShow = onShow,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
service::loader::startApp(manifest.id);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
7
Tactility/Source/app/launcher/Launcher.h
Normal file
7
Tactility/Source/app/launcher/Launcher.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace tt::app::launcher {
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
}
|
||||||
@ -176,7 +176,7 @@ void ScreenshotUi::createFilePathWidgets(lv_obj_t* parent) {
|
|||||||
lv_textarea_set_one_line(pathTextArea, true);
|
lv_textarea_set_one_line(pathTextArea, true);
|
||||||
lv_obj_set_flex_grow(pathTextArea, 1);
|
lv_obj_set_flex_grow(pathTextArea, 1);
|
||||||
if (kernel::getPlatform() == kernel::PlatformEsp) {
|
if (kernel::getPlatform() == kernel::PlatformEsp) {
|
||||||
auto sdcard = tt::hal::getConfiguration().sdcard;
|
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
||||||
if (sdcard != nullptr && sdcard->getState() == hal::SdCard::StateMounted) {
|
if (sdcard != nullptr && sdcard->getState() == hal::SdCard::StateMounted) {
|
||||||
lv_textarea_set_text(pathTextArea, "A:/sdcard");
|
lv_textarea_set_text(pathTextArea, "A:/sdcard");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -132,20 +132,19 @@ static const char* getSdCardStatusIcon(hal::SdCard::State state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void updateSdCardIcon(const service::Paths* paths, const std::shared_ptr<ServiceData>& data) {
|
static void updateSdCardIcon(const service::Paths* paths, const std::shared_ptr<ServiceData>& data) {
|
||||||
auto sdcard = tt::hal::getConfiguration().sdcard;
|
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
||||||
if (sdcard != nullptr) {
|
if (sdcard != nullptr) {
|
||||||
auto state = sdcard->getState();
|
auto state = sdcard->getState();
|
||||||
const char* desired_icon = getSdCardStatusIcon(state);
|
if (state != hal::SdCard::StateUnknown) {
|
||||||
if (data->sdcard_last_icon != desired_icon) {
|
auto* desired_icon = getSdCardStatusIcon(state);
|
||||||
if (desired_icon != nullptr) {
|
if (data->sdcard_last_icon != desired_icon) {
|
||||||
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
||||||
lvgl::statusbar_icon_set_image(data->sdcard_icon_id, icon_path);
|
lvgl::statusbar_icon_set_image(data->sdcard_icon_id, icon_path);
|
||||||
lvgl::statusbar_icon_set_visibility(data->sdcard_icon_id, true);
|
lvgl::statusbar_icon_set_visibility(data->sdcard_icon_id, true);
|
||||||
} else {
|
data->sdcard_last_icon = desired_icon;
|
||||||
lvgl::statusbar_icon_set_visibility(data->sdcard_icon_id, false);
|
|
||||||
}
|
}
|
||||||
data->sdcard_last_icon = desired_icon;
|
|
||||||
}
|
}
|
||||||
|
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -106,24 +106,4 @@ ThreadId Mutex::getOwner() const {
|
|||||||
return (ThreadId)xSemaphoreGetMutexHolder(semaphore);
|
return (ThreadId)xSemaphoreGetMutexHolder(semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex* tt_mutex_alloc(Mutex::Type type) {
|
|
||||||
return new Mutex(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_mutex_free(Mutex* mutex) {
|
|
||||||
delete mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
TtStatus tt_mutex_acquire(Mutex* mutex, TickType_t timeout) {
|
|
||||||
return mutex-> acquire(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
TtStatus tt_mutex_release(Mutex* mutex) {
|
|
||||||
return mutex->release();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadId tt_mutex_get_owner(Mutex* mutex) {
|
|
||||||
return mutex->getOwner();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -62,40 +62,4 @@ public:
|
|||||||
ThreadId getOwner() const;
|
ThreadId getOwner() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Allocate Mutex
|
|
||||||
* @param[in] type The mutex type
|
|
||||||
* @return pointer to Mutex instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
[[deprecated("use class")]]
|
|
||||||
Mutex* tt_mutex_alloc(Mutex::Type type);
|
|
||||||
|
|
||||||
/** Free Mutex
|
|
||||||
* @param[in] mutex The Mutex instance
|
|
||||||
*/
|
|
||||||
[[deprecated("use class")]]
|
|
||||||
void tt_mutex_free(Mutex* mutex);
|
|
||||||
|
|
||||||
/** Acquire mutex
|
|
||||||
* @param[in] mutex
|
|
||||||
* @param[in] timeout
|
|
||||||
* @return the status result
|
|
||||||
*/
|
|
||||||
[[deprecated("use class")]]
|
|
||||||
TtStatus tt_mutex_acquire(Mutex* mutex, TickType_t timeout);
|
|
||||||
|
|
||||||
/** Release mutex
|
|
||||||
* @param[in] mutex The Mutex instance
|
|
||||||
* @return the status result
|
|
||||||
*/
|
|
||||||
[[deprecated("use class")]]
|
|
||||||
TtStatus tt_mutex_release(Mutex* mutex);
|
|
||||||
|
|
||||||
/** Get mutex owner thread id
|
|
||||||
* @param[in] mutex The Mutex instance
|
|
||||||
* @return The thread identifier.
|
|
||||||
*/
|
|
||||||
[[deprecated("use class")]]
|
|
||||||
ThreadId tt_mutex_get_owner(Mutex* mutex);
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -50,9 +50,8 @@ Dispatcher& getMainDispatcher() {
|
|||||||
|
|
||||||
namespace hal {
|
namespace hal {
|
||||||
|
|
||||||
const Configuration& getConfiguration() {
|
const Configuration* getConfiguration() {
|
||||||
tt_assert(hardwareConfig != nullptr);
|
return hardwareConfig;
|
||||||
return *hardwareConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "TactilityCore.h"
|
#include "TactilityCore.h"
|
||||||
#include "hal/Configuration.h"
|
#include "hal/Configuration.h"
|
||||||
#include "TactilityHeadlessConfig.h"
|
|
||||||
#include "Dispatcher.h"
|
#include "Dispatcher.h"
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
@ -20,7 +19,7 @@ Dispatcher& getMainDispatcher();
|
|||||||
|
|
||||||
namespace tt::hal {
|
namespace tt::hal {
|
||||||
|
|
||||||
/** Can be called after initHeadless() is called. Will crash otherwise. */
|
/** While technically this configuration is nullable, it's never null after initHeadless() is called. */
|
||||||
const Configuration& getConfiguration();
|
const Configuration* _Nullable getConfiguration();
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define TT_CONFIG_SERVICES_LIMIT 32
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
#ifdef ESP_TARGET
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#include "TactilityCore.h"
|
#include "TactilityCore.h"
|
||||||
#include "EspPartitions_i.h"
|
#include "EspPartitions_i.h"
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ static Mode currentMode = ModeDefault;
|
|||||||
static RTC_NOINIT_ATTR BootMode bootMode;
|
static RTC_NOINIT_ATTR BootMode bootMode;
|
||||||
|
|
||||||
sdmmc_card_t* _Nullable getCard() {
|
sdmmc_card_t* _Nullable getCard() {
|
||||||
auto sdcard = getConfiguration().sdcard;
|
auto sdcard = getConfiguration()->sdcard;
|
||||||
if (sdcard == nullptr) {
|
if (sdcard == nullptr) {
|
||||||
TT_LOG_W(TAG, "No SD card configuration found");
|
TT_LOG_W(TAG, "No SD card configuration found");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ struct ServiceData {
|
|||||||
|
|
||||||
|
|
||||||
static void onUpdate(std::shared_ptr<void> context) {
|
static void onUpdate(std::shared_ptr<void> context) {
|
||||||
auto sdcard = tt::hal::getConfiguration().sdcard;
|
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
||||||
if (sdcard == nullptr) {
|
if (sdcard == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ static void onUpdate(std::shared_ptr<void> context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void onStart(ServiceContext& service) {
|
static void onStart(ServiceContext& service) {
|
||||||
if (hal::getConfiguration().sdcard != nullptr) {
|
if (hal::getConfiguration()->sdcard != nullptr) {
|
||||||
auto data = std::make_shared<ServiceData>();
|
auto data = std::make_shared<ServiceData>();
|
||||||
service.setData(data);
|
service.setData(data);
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
#include "Pubsub.h"
|
#include "Pubsub.h"
|
||||||
#include "service/ServiceContext.h"
|
#include "service/ServiceContext.h"
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
namespace tt::service::wifi {
|
||||||
|
|
||||||
@ -17,25 +15,23 @@ namespace tt::service::wifi {
|
|||||||
#define WIFI_CONNECTED_BIT BIT0
|
#define WIFI_CONNECTED_BIT BIT0
|
||||||
#define WIFI_FAIL_BIT BIT1
|
#define WIFI_FAIL_BIT BIT1
|
||||||
|
|
||||||
typedef struct {
|
struct Wifi {
|
||||||
|
Wifi() = default;
|
||||||
|
~Wifi() = default;
|
||||||
|
|
||||||
/** @brief Locking mechanism for modifying the Wifi instance */
|
/** @brief Locking mechanism for modifying the Wifi instance */
|
||||||
Mutex* mutex;
|
Mutex mutex = Mutex(Mutex::TypeRecursive);
|
||||||
/** @brief The public event bus */
|
/** @brief The public event bus */
|
||||||
std::shared_ptr<PubSub> pubsub;
|
std::shared_ptr<PubSub> pubsub = std::make_shared<PubSub>();
|
||||||
/** @brief The internal message queue */
|
/** @brief The internal message queue */
|
||||||
MessageQueue queue;
|
bool scan_active = false;
|
||||||
bool scan_active;
|
bool secure_connection = false;
|
||||||
bool secure_connection;
|
WifiRadioState radio_state = WIFI_RADIO_CONNECTION_ACTIVE;
|
||||||
WifiRadioState radio_state;
|
};
|
||||||
} Wifi;
|
|
||||||
|
|
||||||
|
|
||||||
static Wifi* wifi = nullptr;
|
static Wifi* wifi = nullptr;
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
static void wifi_lock(Wifi* wifi);
|
|
||||||
static void wifi_unlock(Wifi* wifi);
|
|
||||||
|
|
||||||
// region Static
|
// region Static
|
||||||
|
|
||||||
static void publish_event_simple(Wifi* wifi, WifiEventType type) {
|
static void publish_event_simple(Wifi* wifi, WifiEventType type) {
|
||||||
@ -45,25 +41,6 @@ static void publish_event_simple(Wifi* wifi, WifiEventType type) {
|
|||||||
|
|
||||||
// endregion Static
|
// endregion Static
|
||||||
|
|
||||||
// region Alloc
|
|
||||||
|
|
||||||
static Wifi* wifi_alloc() {
|
|
||||||
auto* instance = static_cast<Wifi*>(malloc(sizeof(Wifi)));
|
|
||||||
instance->mutex = tt_mutex_alloc(Mutex::TypeRecursive);
|
|
||||||
instance->pubsub = std::make_shared<PubSub>();
|
|
||||||
instance->scan_active = false;
|
|
||||||
instance->radio_state = WIFI_RADIO_CONNECTION_ACTIVE;
|
|
||||||
instance->secure_connection = false;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wifi_free(Wifi* instance) {
|
|
||||||
tt_mutex_free(instance->mutex);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion Alloc
|
|
||||||
|
|
||||||
// region Public functions
|
// region Public functions
|
||||||
|
|
||||||
std::shared_ptr<PubSub> getPubsub() {
|
std::shared_ptr<PubSub> getPubsub() {
|
||||||
@ -160,29 +137,14 @@ int getRssi() {
|
|||||||
|
|
||||||
// endregion Public functions
|
// endregion Public functions
|
||||||
|
|
||||||
static void lock(Wifi* wifi) {
|
|
||||||
tt_crash("this fails for now");
|
|
||||||
tt_assert(wifi);
|
|
||||||
tt_assert(wifi->mutex);
|
|
||||||
tt_mutex_acquire(wifi->mutex, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unlock(Wifi* wifi) {
|
|
||||||
tt_assert(wifi);
|
|
||||||
tt_assert(wifi->mutex);
|
|
||||||
tt_mutex_release(wifi->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void service_start(TT_UNUSED ServiceContext& service) {
|
static void service_start(TT_UNUSED ServiceContext& service) {
|
||||||
tt_check(wifi == nullptr);
|
tt_check(wifi == nullptr);
|
||||||
wifi = wifi_alloc();
|
wifi = new Wifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_stop(TT_UNUSED ServiceContext& service) {
|
static void service_stop(TT_UNUSED ServiceContext& service) {
|
||||||
tt_check(wifi != nullptr);
|
tt_check(wifi != nullptr);
|
||||||
|
delete wifi;
|
||||||
wifi_free(wifi);
|
|
||||||
wifi = nullptr;
|
wifi = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,33 +4,31 @@
|
|||||||
|
|
||||||
using namespace tt;
|
using namespace tt;
|
||||||
|
|
||||||
static int thread_with_mutex_parameter(void* parameter) {
|
static int32_t thread_with_mutex_parameter(void* parameter) {
|
||||||
auto* mutex = (Mutex*)parameter;
|
auto* mutex = (Mutex*)parameter;
|
||||||
tt_mutex_acquire(mutex, TtWaitForever);
|
mutex->lock(portMAX_DELAY);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("a mutex can block a thread") {
|
TEST_CASE("a mutex can block a thread") {
|
||||||
auto* mutex = tt_mutex_alloc(Mutex::TypeNormal);
|
auto mutex = Mutex(Mutex::TypeNormal);
|
||||||
tt_mutex_acquire(mutex, TtWaitForever);
|
mutex.lock(portMAX_DELAY);
|
||||||
|
|
||||||
Thread* thread = new Thread(
|
Thread thread = Thread(
|
||||||
"thread",
|
"thread",
|
||||||
1024,
|
1024,
|
||||||
&thread_with_mutex_parameter,
|
&thread_with_mutex_parameter,
|
||||||
mutex
|
&mutex
|
||||||
);
|
);
|
||||||
thread->start();
|
thread.start();
|
||||||
|
|
||||||
kernel::delayMillis(5);
|
kernel::delayMillis(5);
|
||||||
CHECK_EQ(thread->getState(), Thread::StateRunning);
|
CHECK_EQ(thread.getState(), Thread::StateRunning);
|
||||||
|
|
||||||
tt_mutex_release(mutex);
|
mutex.unlock();
|
||||||
|
|
||||||
kernel::delayMillis(5);
|
kernel::delayMillis(5);
|
||||||
CHECK_EQ(thread->getState(), Thread::StateStopped);
|
CHECK_EQ(thread.getState(), Thread::StateStopped);
|
||||||
|
|
||||||
thread->join();
|
thread.join();
|
||||||
delete thread;
|
|
||||||
tt_mutex_free(mutex);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user