Thread+locking improvements and more (#386)

This commit is contained in:
Ken Van Hoeylandt 2025-10-25 18:08:46 +02:00 committed by GitHub
parent d0d05c67ca
commit c139300a58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 75 additions and 56 deletions

View File

@ -2,14 +2,13 @@
## Before release ## Before release
- App Hub
- Fix Wi-Fi password(less) decryption crash - Fix Wi-Fi password(less) decryption crash
- Make better esp_lcd driver (and test all devices) - Make better esp_lcd driver (and test all devices)
## Higher Priority ## Higher Priority
- Calculator bugs (see GitHub issue) - Calculator bugs (see GitHub issue)
- Store last synced timestamp in NVS (see how HTTPS client example app) - Expose http::download() and main dispatcher to TactiltyC.
- External app loading: Check the version of Tactility and check ESP target hardware to check for compatibility - External app loading: Check the version of Tactility and check ESP target hardware to check for compatibility
Check during installation process, but also when starting (SD card might have old app install from before Tactility OS update) Check during installation process, but also when starting (SD card might have old app install from before Tactility OS update)
- Make a URL handler. Use it for handling local files. Match file types with apps. - Make a URL handler. Use it for handling local files. Match file types with apps.

View File

@ -6,6 +6,11 @@
namespace tt::hal::sdcard { namespace tt::hal::sdcard {
/**
* Warning: getLock() does not have to be used when calling any of the functions of this class.
* The lock is only used for file access on the path where the SD card is mounted.
* This is mainly used when accessing the SD card on a shared SPI bus.
*/
class SdCardDevice : public Device { class SdCardDevice : public Device {
public: public:
@ -33,15 +38,28 @@ public:
Type getType() const final { return Type::SdCard; }; Type getType() const final { return Type::SdCard; };
/**
* Mount the device.
* @param mountPath the path to mount at
* @return true on successful mount
*/
virtual bool mount(const std::string& mountPath) = 0; virtual bool mount(const std::string& mountPath) = 0;
/**
* Unmount the device.
* @return true on successful unmount
*/
virtual bool unmount() = 0; virtual bool unmount() = 0;
virtual State getState(TickType_t timeout = portMAX_DELAY) const = 0; virtual State getState(TickType_t timeout = portMAX_DELAY) const = 0;
/** Return empty string when not mounted or the mount path if mounted */
/** @return empty string when not mounted or the mount path if mounted */
virtual std::string getMountPath() const = 0; virtual std::string getMountPath() const = 0;
/** Non-null lock */ /** @return non-null lock, used by code that wants to access files on the mount path of this SD card */
virtual std::shared_ptr<Lock> getLock() const = 0; virtual std::shared_ptr<Lock> getLock() const = 0;
/** @return the MountBehaviour of this device */
virtual MountBehaviour getMountBehaviour() const { return mountBehaviour; } virtual MountBehaviour getMountBehaviour() const { return mountBehaviour; }
/** @return true if the SD card was mounted, returns false when it was not or when a timeout happened. */ /** @return true if the SD card was mounted, returns false when it was not or when a timeout happened. */

View File

@ -101,6 +101,8 @@ namespace app {
// List of all apps excluding Boot app (as Boot app calls this function indirectly) // List of all apps excluding Boot app (as Boot app calls this function indirectly)
static void registerInternalApps() { static void registerInternalApps() {
TT_LOG_I(TAG, "Registering internal apps");
addAppManifest(app::alertdialog::manifest); addAppManifest(app::alertdialog::manifest);
addAppManifest(app::appdetails::manifest); addAppManifest(app::appdetails::manifest);
addAppManifest(app::apphub::manifest); addAppManifest(app::apphub::manifest);
@ -180,6 +182,8 @@ static void registerInstalledApp(std::string path) {
} }
static void registerInstalledApps(const std::string& path) { static void registerInstalledApps(const std::string& path) {
TT_LOG_I(TAG, "Registering apps from %s", path.c_str());
file::listDirectory(path, [&path](const auto& entry) { file::listDirectory(path, [&path](const auto& entry) {
auto absolute_path = std::format("{}/{}", path, entry.d_name); auto absolute_path = std::format("{}/{}", path, entry.d_name);
if (file::isDirectory(absolute_path)) { if (file::isDirectory(absolute_path)) {
@ -200,18 +204,12 @@ static void registerInstalledAppsFromSdCards() {
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard); auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
for (const auto& sdcard : sdcard_devices) { for (const auto& sdcard : sdcard_devices) {
if (sdcard->isMounted()) { if (sdcard->isMounted()) {
TT_LOG_I(TAG, "Registering apps from %s", sdcard->getMountPath().c_str());
registerInstalledAppsFromSdCard(sdcard); registerInstalledAppsFromSdCard(sdcard);
} }
} }
} }
static void registerInstalledAppsFromData() {
auto app_path = "/data/app";
if (file::isDirectory(app_path)) {
registerInstalledApps(app_path);
}
}
static void registerAndStartSecondaryServices() { static void registerAndStartSecondaryServices() {
TT_LOG_I(TAG, "Registering and starting system services"); TT_LOG_I(TAG, "Registering and starting system services");
addService(service::loader::manifest); addService(service::loader::manifest);
@ -242,7 +240,6 @@ void registerApps() {
registerInstalledApps(data_apps_path); registerInstalledApps(data_apps_path);
} }
registerInstalledAppsFromSdCards(); registerInstalledAppsFromSdCards();
registerInstalledAppsFromData();
} }
void run(const Configuration& config) { void run(const Configuration& config) {

View File

@ -9,12 +9,10 @@ constexpr auto* TAG = "SdCardMounting";
constexpr auto* TT_SDCARD_MOUNT_POINT = "/sdcard"; constexpr auto* TT_SDCARD_MOUNT_POINT = "/sdcard";
static void mount(const std::shared_ptr<SdCardDevice>& sdcard, const std::string& path) { static void mount(const std::shared_ptr<SdCardDevice>& sdcard, const std::string& path) {
sdcard->getLock()->withLock([&sdcard, &path] {
TT_LOG_I(TAG, "Mounting sdcard at %s", path.c_str()); TT_LOG_I(TAG, "Mounting sdcard at %s", path.c_str());
if (!sdcard->mount(path)) { if (!sdcard->mount(path)) {
TT_LOG_W(TAG, "SD card mount failed for %s (init can continue)", path.c_str()); TT_LOG_W(TAG, "SD card mount failed for %s (init can continue)", path.c_str());
} }
});
} }
static std::string getMountPath(int index, int count) { static std::string getMountPath(int index, int count) {

View File

@ -58,6 +58,9 @@ bool SdmmcDevice::mountInternal(const std::string& newMountPath) {
} }
bool SdmmcDevice::mount(const std::string& newMountPath) { bool SdmmcDevice::mount(const std::string& newMountPath) {
auto lock = getLock()->asScopedLock();
lock.lock();
if (mountInternal(newMountPath)) { if (mountInternal(newMountPath)) {
TT_LOG_I(TAG, "Mounted at %s", newMountPath.c_str()); TT_LOG_I(TAG, "Mounted at %s", newMountPath.c_str());
sdmmc_card_print_info(stdout, card); sdmmc_card_print_info(stdout, card);
@ -69,6 +72,9 @@ bool SdmmcDevice::mount(const std::string& newMountPath) {
} }
bool SdmmcDevice::unmount() { bool SdmmcDevice::unmount() {
auto lock = getLock()->asScopedLock();
lock.lock();
if (card == nullptr) { if (card == nullptr) {
TT_LOG_E(TAG, "Can't unmount: not mounted"); TT_LOG_E(TAG, "Can't unmount: not mounted");
return false; return false;

View File

@ -84,6 +84,9 @@ bool SpiSdCardDevice::mountInternal(const std::string& newMountPath) {
} }
bool SpiSdCardDevice::mount(const std::string& newMountPath) { bool SpiSdCardDevice::mount(const std::string& newMountPath) {
auto lock = getLock()->asScopedLock();
lock.lock();
if (!applyGpioWorkAround()) { if (!applyGpioWorkAround()) {
TT_LOG_E(TAG, "Failed to apply GPIO work-around"); TT_LOG_E(TAG, "Failed to apply GPIO work-around");
return false; return false;
@ -100,6 +103,9 @@ bool SpiSdCardDevice::mount(const std::string& newMountPath) {
} }
bool SpiSdCardDevice::unmount() { bool SpiSdCardDevice::unmount() {
auto lock = getLock()->asScopedLock();
lock.lock();
if (card == nullptr) { if (card == nullptr) {
TT_LOG_E(TAG, "Can't unmount: not mounted"); TT_LOG_E(TAG, "Can't unmount: not mounted");
return false; return false;

View File

@ -48,14 +48,6 @@ typedef struct {
PubSub<void*>::SubscriptionHandle pubsub_subscription; PubSub<void*>::SubscriptionHandle pubsub_subscription;
} Statusbar; } Statusbar;
static bool statusbar_lock(TickType_t timeoutTicks = portMAX_DELAY) {
return statusbar_data.mutex.lock(timeoutTicks);
}
static bool statusbar_unlock() {
return statusbar_data.mutex.unlock();
}
static void statusbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj); static void statusbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static void statusbar_destructor(const lv_obj_class_t* class_p, lv_obj_t* obj); static void statusbar_destructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static void statusbar_event(const lv_obj_class_t* class_p, lv_event_t* event); static void statusbar_event(const lv_obj_class_t* class_p, lv_event_t* event);
@ -111,10 +103,12 @@ static const lv_obj_class_t statusbar_class = {
static void statusbar_pubsub_event(Statusbar* statusbar) { static void statusbar_pubsub_event(Statusbar* statusbar) {
TT_LOG_D(TAG, "Update event"); TT_LOG_D(TAG, "Update event");
if (lock(portMAX_DELAY)) { if (lock(defaultLockTime)) {
update_main(statusbar); update_main(statusbar);
lv_obj_invalidate(&statusbar->obj); lv_obj_invalidate(&statusbar->obj);
unlock(); unlock();
} else {
TT_LOG_W(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "Statusbar");
} }
} }
@ -184,7 +178,7 @@ lv_obj_t* statusbar_create(lv_obj_t* parent) {
obj_set_style_bg_invisible(left_spacer); obj_set_style_bg_invisible(left_spacer);
lv_obj_set_flex_grow(left_spacer, 1); lv_obj_set_flex_grow(left_spacer, 1);
statusbar_lock(portMAX_DELAY); statusbar_data.mutex.lock(portMAX_DELAY);
for (int i = 0; i < STATUSBAR_ICON_LIMIT; ++i) { for (int i = 0; i < STATUSBAR_ICON_LIMIT; ++i) {
auto* image = lv_image_create(obj); auto* image = lv_image_create(obj);
lv_obj_set_size(image, STATUSBAR_ICON_SIZE, STATUSBAR_ICON_SIZE); lv_obj_set_size(image, STATUSBAR_ICON_SIZE, STATUSBAR_ICON_SIZE);
@ -194,7 +188,7 @@ lv_obj_t* statusbar_create(lv_obj_t* parent) {
update_icon(image, &(statusbar_data.icons[i])); update_icon(image, &(statusbar_data.icons[i]));
} }
statusbar_unlock(); statusbar_data.mutex.unlock();
return obj; return obj;
} }
@ -212,11 +206,11 @@ static void update_time(Statusbar* statusbar) {
static void update_main(Statusbar* statusbar) { static void update_main(Statusbar* statusbar) {
update_time(statusbar); update_time(statusbar);
if (statusbar_lock(200 / portTICK_PERIOD_MS)) { if (statusbar_data.mutex.lock(200 / portTICK_PERIOD_MS)) {
for (int i = 0; i < STATUSBAR_ICON_LIMIT; ++i) { for (int i = 0; i < STATUSBAR_ICON_LIMIT; ++i) {
update_icon(statusbar->icons[i], &(statusbar_data.icons[i])); update_icon(statusbar->icons[i], &(statusbar_data.icons[i]));
} }
statusbar_unlock(); statusbar_data.mutex.unlock();
} }
} }
@ -236,7 +230,7 @@ static void statusbar_event(TT_UNUSED const lv_obj_class_t* class_p, lv_event_t*
} }
int8_t statusbar_icon_add(const std::string& image) { int8_t statusbar_icon_add(const std::string& image) {
statusbar_lock(); statusbar_data.mutex.lock();
int8_t result = -1; int8_t result = -1;
for (int8_t i = 0; i < STATUSBAR_ICON_LIMIT; ++i) { for (int8_t i = 0; i < STATUSBAR_ICON_LIMIT; ++i) {
if (!statusbar_data.icons[i].claimed) { if (!statusbar_data.icons[i].claimed) {
@ -248,8 +242,8 @@ int8_t statusbar_icon_add(const std::string& image) {
break; break;
} }
} }
statusbar_data.mutex.unlock();
statusbar_data.pubsub->publish(nullptr); statusbar_data.pubsub->publish(nullptr);
statusbar_unlock();
return result; return result;
} }
@ -260,37 +254,35 @@ int8_t statusbar_icon_add() {
void statusbar_icon_remove(int8_t id) { void statusbar_icon_remove(int8_t id) {
TT_LOG_D(TAG, "id %d: remove", id); TT_LOG_D(TAG, "id %d: remove", id);
tt_check(id >= 0 && id < STATUSBAR_ICON_LIMIT); tt_check(id >= 0 && id < STATUSBAR_ICON_LIMIT);
statusbar_lock(); statusbar_data.mutex.lock();
StatusbarIcon* icon = &statusbar_data.icons[id]; StatusbarIcon* icon = &statusbar_data.icons[id];
icon->claimed = false; icon->claimed = false;
icon->visible = false; icon->visible = false;
icon->image = ""; icon->image = "";
statusbar_data.mutex.unlock();
statusbar_data.pubsub->publish(nullptr); statusbar_data.pubsub->publish(nullptr);
statusbar_unlock();
} }
void statusbar_icon_set_image(int8_t id, const std::string& image) { void statusbar_icon_set_image(int8_t id, const std::string& image) {
TT_LOG_D(TAG, "id %d: set image %s", id, image.empty() ? "(none)" : image.c_str()); TT_LOG_D(TAG, "id %d: set image %s", id, image.empty() ? "(none)" : image.c_str());
tt_check(id >= 0 && id < STATUSBAR_ICON_LIMIT); tt_check(id >= 0 && id < STATUSBAR_ICON_LIMIT);
if (statusbar_lock()) { statusbar_data.mutex.lock();
StatusbarIcon* icon = &statusbar_data.icons[id]; StatusbarIcon* icon = &statusbar_data.icons[id];
tt_check(icon->claimed); tt_check(icon->claimed);
icon->image = image; icon->image = image;
statusbar_data.mutex.unlock();
statusbar_data.pubsub->publish(nullptr); statusbar_data.pubsub->publish(nullptr);
statusbar_unlock();
}
} }
void statusbar_icon_set_visibility(int8_t id, bool visible) { void statusbar_icon_set_visibility(int8_t id, bool visible) {
TT_LOG_D(TAG, "id %d: set visibility %d", id, visible); TT_LOG_D(TAG, "id %d: set visibility %d", id, visible);
tt_check(id >= 0 && id < STATUSBAR_ICON_LIMIT); tt_check(id >= 0 && id < STATUSBAR_ICON_LIMIT);
if (statusbar_lock()) { statusbar_data.mutex.lock();
StatusbarIcon* icon = &statusbar_data.icons[id]; StatusbarIcon* icon = &statusbar_data.icons[id];
tt_check(icon->claimed); tt_check(icon->claimed);
icon->visible = visible; icon->visible = visible;
statusbar_data.mutex.unlock();
statusbar_data.pubsub->publish(nullptr); statusbar_data.pubsub->publish(nullptr);
statusbar_unlock();
}
} }
} // namespace } // namespace

View File

@ -10,6 +10,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <Tactility/Tactility.h>
#include <Tactility/hal/sdcard/SdCardDevice.h> #include <Tactility/hal/sdcard/SdCardDevice.h>
namespace tt::service::wifi { namespace tt::service::wifi {
@ -115,6 +116,7 @@ static void importWifiApSettings(std::shared_ptr<hal::sdcard::SdCardDevice> sdca
} }
void bootSplashInit() { void bootSplashInit() {
getMainDispatcher().dispatch([] {
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard); const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
for (auto& sdcard : sdcards) { for (auto& sdcard : sdcards) {
if (sdcard->isMounted()) { if (sdcard->isMounted()) {
@ -123,6 +125,7 @@ void bootSplashInit() {
TT_LOG_W(TAG, "Skipping unmounted SD card %s", sdcard->getMountPath().c_str()); TT_LOG_W(TAG, "Skipping unmounted SD card %s", sdcard->getMountPath().c_str());
} }
} }
});
} }
} }