New kernel drivers, filesystem API, and more (#513)
* **New Features** * BMI270 6-axis IMU driver added; new unified filesystem abstraction for mounted filesystems. * Public Wi‑Fi API surface (no implementation yet) * SDMMC driver added (kernel drive$) * expanded GPIO interrupt/callback support * **Improvements** * M5Stack Tab5: revamped GPIO/power initialization and IMU integration. * LVGL updates including device fontSize configuration. * Updated all code related to SD card device/fs handling * Rename LilyGO T-HMI S3 to LilyGO T-HMI * **Bug Fixes** * Simplified and consolidated SD card handling and mount discovery.
This commit is contained in:
committed by
GitHub
parent
2de35b2d2d
commit
aa7530e515
@@ -2,56 +2,36 @@
|
||||
|
||||
#include "Tactility/TactilityConfig.h"
|
||||
#include <tactility/hal/Device.h>
|
||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
||||
|
||||
#include <Tactility/file/File.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <dirent.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
#include <vector>
|
||||
|
||||
namespace tt::file {
|
||||
|
||||
std::vector<dirent> getMountPoints() {
|
||||
std::vector<dirent> getFileSystemDirents() {
|
||||
std::vector<dirent> dir_entries;
|
||||
dir_entries.clear();
|
||||
|
||||
// Data partition
|
||||
auto data_dirent = dirent{
|
||||
.d_ino = 1,
|
||||
.d_type = TT_DT_DIR,
|
||||
.d_name = { 0 }
|
||||
};
|
||||
strcpy(data_dirent.d_name, DATA_PARTITION_NAME);
|
||||
dir_entries.push_back(data_dirent);
|
||||
|
||||
// SD card partitions
|
||||
auto sdcards = tt::hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (auto& sdcard : sdcards) {
|
||||
auto state = sdcard->getState();
|
||||
if (state == hal::sdcard::SdCardDevice::State::Mounted) {
|
||||
auto mount_name = sdcard->getMountPath().substr(1);
|
||||
auto dir_entry = dirent {
|
||||
.d_ino = 2,
|
||||
.d_type = TT_DT_DIR,
|
||||
.d_name = { 0 }
|
||||
};
|
||||
assert(mount_name.length() < sizeof(dirent::d_name));
|
||||
strcpy(dir_entry.d_name, mount_name.c_str());
|
||||
dir_entries.push_back(dir_entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (config::SHOW_SYSTEM_PARTITION) {
|
||||
// System partition
|
||||
auto system_dirent = dirent{
|
||||
.d_ino = 0,
|
||||
file_system_for_each(&dir_entries, [](auto* fs, void* context) {
|
||||
if (!file_system_is_mounted(fs)) return true;
|
||||
char path[128];
|
||||
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||
auto mount_name = std::string(path).substr(1);
|
||||
if (!config::SHOW_SYSTEM_PARTITION && mount_name.starts_with(SYSTEM_PARTITION_NAME)) return true;
|
||||
auto dir_entry = dirent {
|
||||
.d_ino = 2,
|
||||
.d_type = TT_DT_DIR,
|
||||
.d_name = { 0 }
|
||||
};
|
||||
strcpy(system_dirent.d_name, SYSTEM_PARTITION_NAME);
|
||||
dir_entries.push_back(system_dirent);
|
||||
}
|
||||
auto& dir_entries = *static_cast<std::vector<dirent>*>(context);
|
||||
strcpy(dir_entry.d_name, mount_name.c_str());
|
||||
dir_entries.push_back(dir_entry);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return dir_entries;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,47 @@
|
||||
|
||||
#include <esp_vfs_fat.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
namespace tt {
|
||||
|
||||
static const auto LOGGER = Logger("Partitions");
|
||||
|
||||
// region file_system stub
|
||||
|
||||
struct PartitionFsData {
|
||||
const char* path;
|
||||
};
|
||||
|
||||
static error_t mount(void* data) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static error_t unmount(void* data) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static bool is_mounted(void* data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||
auto* fs_data = static_cast<PartitionFsData*>(data);
|
||||
if (strlen(fs_data->path) >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||
strncpy(out_path, fs_data->path, out_path_size);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
FileSystemApi partition_fs_api = {
|
||||
.mount = mount,
|
||||
.unmount = unmount,
|
||||
.is_mounted = is_mounted,
|
||||
.get_path = get_path
|
||||
};
|
||||
|
||||
// endregion file_system stub
|
||||
|
||||
static esp_err_t initNvsFlashSafely() {
|
||||
esp_err_t result = nvs_flash_init();
|
||||
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
@@ -56,6 +92,8 @@ esp_err_t initPartitionsEsp() {
|
||||
LOGGER.error("Failed to mount /system ({})", esp_err_to_name(system_result));
|
||||
} else {
|
||||
LOGGER.info("Mounted /system");
|
||||
static auto system_fs_data = PartitionFsData("/system");
|
||||
file_system_add(&partition_fs_api, &system_fs_data);
|
||||
}
|
||||
|
||||
auto data_result = esp_vfs_fat_spiflash_mount_rw_wl("/data", "data", &mount_config, &data_wl_handle);
|
||||
@@ -63,6 +101,8 @@ esp_err_t initPartitionsEsp() {
|
||||
LOGGER.error("Failed to mount /data ({})", esp_err_to_name(data_result));
|
||||
} else {
|
||||
LOGGER.info("Mounted /data");
|
||||
static auto data_fs_data = PartitionFsData("/data");
|
||||
file_system_add(&partition_fs_api, &data_fs_data);
|
||||
}
|
||||
|
||||
return system_result == ESP_OK && data_result == ESP_OK;
|
||||
|
||||
+23
-11
@@ -2,25 +2,37 @@
|
||||
|
||||
#include <Tactility/app/AppManifestParsing.h>
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
|
||||
#include <format>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
namespace tt {
|
||||
|
||||
bool findFirstMountedSdCardPath(std::string& path) {
|
||||
// const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
bool is_set = false;
|
||||
hal::findDevices<hal::sdcard::SdCardDevice>(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;
|
||||
auto* fs = findSdcardFileSystem(true);
|
||||
if (fs == nullptr) return false;
|
||||
char found_path[128];
|
||||
if (file_system_get_path(fs, found_path, sizeof(found_path)) != ERROR_NONE) return false;
|
||||
path = found_path;
|
||||
return true;
|
||||
}
|
||||
|
||||
FileSystem* findSdcardFileSystem(bool mustBeMounted) {
|
||||
FileSystem* found = nullptr;
|
||||
file_system_for_each(&found, [](auto* fs, void* context) {
|
||||
char path[128];
|
||||
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||
// TODO: Find a better way to identify SD card paths
|
||||
if (std::string(path).starts_with("/sdcard")) {
|
||||
*static_cast<FileSystem**>(context) = fs;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return is_set;
|
||||
if (found && mustBeMounted && !file_system_is_mounted(found)) {
|
||||
return nullptr;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
std::string getSystemRootPath() {
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/TactilityConfig.h>
|
||||
|
||||
#include <Tactility/app/AppManifestParsing.h>
|
||||
#include <Tactility/app/AppRegistration.h>
|
||||
#include <Tactility/CpuAffinity.h>
|
||||
#include <Tactility/DispatcherThread.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/Paths.h>
|
||||
#include <Tactility/app/AppManifestParsing.h>
|
||||
#include <Tactility/app/AppRegistration.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/FileLock.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
#include <Tactility/hal/HalPrivate.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <Tactility/lvgl/LvglPrivate.h>
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/network/NtpPrivate.h>
|
||||
#include <Tactility/service/ServiceManifest.h>
|
||||
#include <Tactility/service/ServiceRegistration.h>
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <tactility/concurrent/thread.h>
|
||||
#include <tactility/drivers/uart_controller.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
#include <tactility/hal_device_module.h>
|
||||
#include <tactility/kernel_init.h>
|
||||
#include <tactility/lvgl_module.h>
|
||||
@@ -49,7 +50,6 @@ namespace service {
|
||||
// Primary
|
||||
namespace gps { extern const ServiceManifest manifest; }
|
||||
namespace wifi { extern const ServiceManifest manifest; }
|
||||
namespace sdcard { extern const ServiceManifest manifest; }
|
||||
#ifdef ESP_PLATFORM
|
||||
namespace development { extern const ServiceManifest manifest; }
|
||||
#endif
|
||||
@@ -228,22 +228,18 @@ static void registerInstalledApps(const std::string& path) {
|
||||
});
|
||||
}
|
||||
|
||||
static void registerInstalledAppsFromSdCard(const std::shared_ptr<hal::sdcard::SdCardDevice>& sdcard) {
|
||||
auto sdcard_root_path = sdcard->getMountPath();
|
||||
auto app_path = std::format("{}/app", sdcard_root_path);
|
||||
if (file::isDirectory(app_path)) {
|
||||
registerInstalledApps(app_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void registerInstalledAppsFromSdCards() {
|
||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted()) {
|
||||
LOGGER.info("Registering apps from {}", sdcard->getMountPath());
|
||||
registerInstalledAppsFromSdCard(sdcard);
|
||||
static void registerInstalledAppsFromFileSystems() {
|
||||
file_system_for_each(nullptr, [](auto* fs, void* context) {
|
||||
if (!file_system_is_mounted(fs)) return true;
|
||||
char path[128];
|
||||
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||
const auto app_path = std::format("{}/app", path);
|
||||
if (!app_path.starts_with(file::MOUNT_POINT_SYSTEM) && file::isDirectory(app_path)) {
|
||||
LOGGER.info("Registering apps from {}", app_path);
|
||||
registerInstalledApps(app_path);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
static void registerAndStartSecondaryServices() {
|
||||
@@ -266,9 +262,6 @@ static void registerAndStartSecondaryServices() {
|
||||
static void registerAndStartPrimaryServices() {
|
||||
LOGGER.info("Registering and starting primary system services");
|
||||
addService(service::gps::manifest);
|
||||
if (hal::hasDevice(hal::Device::Type::SdCard)) {
|
||||
addService(service::sdcard::manifest);
|
||||
}
|
||||
addService(service::wifi::manifest);
|
||||
#ifdef ESP_PLATFORM
|
||||
addService(service::development::manifest);
|
||||
@@ -301,26 +294,19 @@ void createTempDirectory(const std::string& rootPath) {
|
||||
}
|
||||
|
||||
void prepareFileSystems() {
|
||||
// Temporary directories for SD cards
|
||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted()) {
|
||||
createTempDirectory(sdcard->getMountPath());
|
||||
}
|
||||
}
|
||||
// Temporary directory for /data
|
||||
if (file::isDirectory(file::MOUNT_POINT_DATA)) {
|
||||
createTempDirectory(file::MOUNT_POINT_DATA);
|
||||
}
|
||||
file_system_for_each(nullptr, [](auto* fs, void* context) {
|
||||
if (!file_system_is_mounted(fs)) return true;
|
||||
char path[128];
|
||||
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||
if (std::string(path) == file::MOUNT_POINT_SYSTEM) return true;
|
||||
createTempDirectory(path);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void registerApps() {
|
||||
registerInternalApps();
|
||||
auto data_apps_path = std::format("{}/app", file::MOUNT_POINT_DATA);
|
||||
if (file::isDirectory(data_apps_path)) {
|
||||
registerInstalledApps(data_apps_path);
|
||||
}
|
||||
registerInstalledAppsFromSdCards();
|
||||
registerInstalledAppsFromFileSystems();
|
||||
}
|
||||
|
||||
void run(const Configuration& config, Module* dtsModules[], DtsDevice dtsDevices[]) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <Tactility/app/files/State.h>
|
||||
#include <Tactility/app/AppContext.h>
|
||||
|
||||
#include <Tactility/Assets.h>
|
||||
#include <Tactility/service/loader/Loader.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -51,7 +51,7 @@ bool State::setEntriesForPath(const std::string& path) {
|
||||
bool get_mount_points = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
||||
if (get_mount_points) {
|
||||
LOGGER.info("Setting custom root");
|
||||
dir_entries = file::getMountPoints();
|
||||
dir_entries = file::getFileSystemDirents();
|
||||
current_path = path;
|
||||
selected_child_entry = "";
|
||||
action = ActionNone;
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/kernel/Platform.h>
|
||||
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <dirent.h>
|
||||
|
||||
namespace tt::app::fileselection {
|
||||
|
||||
@@ -36,6 +37,12 @@ std::string State::getSelectedChildPath() const {
|
||||
bool State::setEntriesForPath(const std::string& path) {
|
||||
LOGGER.info("Changing path: {} -> {}", current_path, path);
|
||||
|
||||
auto lock = mutex.asScopedLock();
|
||||
if (!lock.lock(100)) {
|
||||
LOGGER.error(LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "setEntriesForPath");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ESP32 does not have a root directory, so we have to create it manually.
|
||||
* We'll add the NVS Flash partitions and the binding for the sdcard.
|
||||
@@ -43,7 +50,7 @@ bool State::setEntriesForPath(const std::string& path) {
|
||||
bool show_custom_root = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
||||
if (show_custom_root) {
|
||||
LOGGER.info("Setting custom root");
|
||||
dir_entries = file::getMountPoints();
|
||||
dir_entries = file::getFileSystemDirents();
|
||||
current_path = path;
|
||||
selected_child_entry = "";
|
||||
return true;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/TactilityConfig.h>
|
||||
|
||||
|
||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <Tactility/app/AppManifest.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/kernel/Platform.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/lvgl/Lvgl.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/lvgl/Toolbar.h>
|
||||
#include <Tactility/service/screenshot/Screenshot.h>
|
||||
|
||||
#include <Tactility/Paths.h>
|
||||
#include <Tactility/Timer.h>
|
||||
|
||||
#include <tactility/lvgl_icon_shared.h>
|
||||
@@ -204,12 +204,9 @@ void ScreenshotApp::createFilePathWidgets(lv_obj_t* parent) {
|
||||
lv_textarea_set_one_line(pathTextArea, true);
|
||||
lv_obj_set_flex_grow(pathTextArea, 1);
|
||||
if (kernel::getPlatform() == kernel::PlatformEsp) {
|
||||
auto sdcard_devices = tt::hal::findDevices<tt::hal::sdcard::SdCardDevice>(tt::hal::Device::Type::SdCard);
|
||||
if (sdcard_devices.size() > 1) {
|
||||
LOGGER.warn("Found multiple SD card devices - picking first");
|
||||
}
|
||||
if (!sdcard_devices.empty() && sdcard_devices.front()->isMounted()) {
|
||||
std::string lvgl_mount_path = lvgl::PATH_PREFIX + sdcard_devices.front()->getMountPath();
|
||||
std::string sdcard_path;
|
||||
if (findFirstMountedSdCardPath(sdcard_path)) {
|
||||
std::string lvgl_mount_path = lvgl::PATH_PREFIX + sdcard_path + "/screenshots";
|
||||
lv_textarea_set_text(pathTextArea, lvgl_mount_path.c_str());
|
||||
} else {
|
||||
lv_textarea_set_text(pathTextArea, "Error: no SD card");
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <Tactility/TactilityConfig.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/lvgl/Toolbar.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/Timer.h>
|
||||
|
||||
#include <Tactility/Paths.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
@@ -321,7 +321,6 @@ class SystemInfoApp final : public App {
|
||||
|
||||
bool hasExternalMem = false;
|
||||
bool hasDataStorage = false;
|
||||
bool hasSdcardStorage = false;
|
||||
bool hasSystemStorage = false;
|
||||
|
||||
void updateMemory() {
|
||||
@@ -343,14 +342,9 @@ class SystemInfoApp final : public App {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSdcardStorage) {
|
||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||
updateMemoryBar(sdcardStorageBar, storage_free, storage_total);
|
||||
break; // Only update first SD card
|
||||
}
|
||||
}
|
||||
std::string sdcard_path;
|
||||
if (findFirstMountedSdCardPath(sdcard_path) && esp_vfs_fat_info(sdcard_path.c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||
updateMemoryBar(sdcardStorageBar, storage_free, storage_total);
|
||||
}
|
||||
|
||||
if (hasSystemStorage) {
|
||||
@@ -624,13 +618,9 @@ class SystemInfoApp final : public App {
|
||||
dataStorageBar = createMemoryBar(storage_tab, file::MOUNT_POINT_DATA);
|
||||
}
|
||||
|
||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||
hasSdcardStorage = true;
|
||||
sdcardStorageBar = createMemoryBar(storage_tab, sdcard->getMountPath().c_str());
|
||||
break; // Only show first SD card
|
||||
}
|
||||
std::string sdcard_path;
|
||||
if (findFirstMountedSdCardPath(sdcard_path) && esp_vfs_fat_info(sdcard_path.c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||
sdcardStorageBar = createMemoryBar(storage_tab, sdcard_path.c_str());
|
||||
}
|
||||
|
||||
if (config::SHOW_SYSTEM_PARTITION) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace tt::hal::sdcard {
|
||||
|
||||
static error_t mount(void* data) {
|
||||
auto* device = static_cast<SdCardDevice*>(data);
|
||||
auto path = device->getMountPath();
|
||||
if (!device->mount(path)) return ERROR_UNDEFINED;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t unmount(void* data) {
|
||||
auto* device = static_cast<SdCardDevice*>(data);
|
||||
if (!device->unmount()) return ERROR_UNDEFINED;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static bool is_mounted(void* data) {
|
||||
auto* device = static_cast<SdCardDevice*>(data);
|
||||
return device->isMounted();
|
||||
}
|
||||
|
||||
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||
auto* device = static_cast<SdCardDevice*>(data);
|
||||
const auto mount_path = device->getMountPath();
|
||||
if (mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||
if (mount_path.empty()) return ERROR_INVALID_STATE;
|
||||
strncpy(out_path, mount_path.c_str(), out_path_size);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
FileSystemApi sdCardDeviceApi = {
|
||||
.mount = mount,
|
||||
.unmount = unmount,
|
||||
.is_mounted = is_mounted,
|
||||
.get_path = get_path
|
||||
};
|
||||
|
||||
SdCardDevice::SdCardDevice(MountBehaviour mountBehaviour) : mountBehaviour(mountBehaviour) {
|
||||
fileSystem = file_system_add(&sdCardDeviceApi, this);
|
||||
check(fileSystem != nullptr);
|
||||
}
|
||||
|
||||
SdCardDevice::~SdCardDevice() {
|
||||
file_system_remove(fileSystem);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <soc/soc_caps.h>
|
||||
#endif
|
||||
|
||||
#if defined(ESP_PLATFORM) && defined(SOC_SDMMC_HOST_SUPPORTED)
|
||||
|
||||
#include <Tactility/hal/sdcard/SdmmcDevice.h>
|
||||
#include <Tactility/Logger.h>
|
||||
|
||||
#include <esp_vfs_fat.h>
|
||||
#include <sdmmc_cmd.h>
|
||||
#include <driver/sdmmc_host.h>
|
||||
|
||||
namespace tt::hal::sdcard {
|
||||
|
||||
static const auto LOGGER = Logger("SdmmcDevice");
|
||||
|
||||
bool SdmmcDevice::mountInternal(const std::string& newMountPath) {
|
||||
LOGGER.info("Mounting {}", newMountPath);
|
||||
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = config->formatOnMountFailed,
|
||||
.max_files = config->maxOpenFiles,
|
||||
.allocation_unit_size = config->allocUnitSize,
|
||||
.disk_status_check_enable = config->statusCheckEnabled,
|
||||
.use_one_fat = false
|
||||
};
|
||||
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
|
||||
sdmmc_slot_config_t slot_config = {
|
||||
.clk = config->pinClock,
|
||||
.cmd = config->pinCmd,
|
||||
.d0 = config->pinD0,
|
||||
.d1 = config->pinD1,
|
||||
.d2 = config->pinD2,
|
||||
.d3 = config->pinD3,
|
||||
.d4 = static_cast<gpio_num_t>(0),
|
||||
.d5 = static_cast<gpio_num_t>(0),
|
||||
.d6 = static_cast<gpio_num_t>(0),
|
||||
.d7 = static_cast<gpio_num_t>(0),
|
||||
.cd = GPIO_NUM_NC,
|
||||
.wp = GPIO_NUM_NC,
|
||||
.width = config->busWidth,
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
esp_err_t result = esp_vfs_fat_sdmmc_mount(newMountPath.c_str(), &host, &slot_config, &mount_config, &card);
|
||||
|
||||
if (result != ESP_OK || card == nullptr) {
|
||||
if (result == ESP_FAIL) {
|
||||
LOGGER.error("Mounting failed. Ensure the card is formatted with FAT.");
|
||||
} else {
|
||||
LOGGER.error("Mounting failed ({})", esp_err_to_name(result));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mountPath = newMountPath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdmmcDevice::mount(const std::string& newMountPath) {
|
||||
auto lock = getLock()->asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
if (mountInternal(newMountPath)) {
|
||||
LOGGER.info("Mounted at {}", newMountPath);
|
||||
sdmmc_card_print_info(stdout, card);
|
||||
return true;
|
||||
} else {
|
||||
LOGGER.error("Mount failed for {}", newMountPath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SdmmcDevice::unmount() {
|
||||
auto lock = getLock()->asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
if (card == nullptr) {
|
||||
LOGGER.error("Can't unmount: not mounted");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_vfs_fat_sdcard_unmount(mountPath.c_str(), card) != ESP_OK) {
|
||||
LOGGER.error("Unmount failed for {}", mountPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGGER.info("Unmounted {}", mountPath);
|
||||
mountPath = "";
|
||||
card = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
SdmmcDevice::State SdmmcDevice::getState(TickType_t timeout) const {
|
||||
if (card == nullptr) {
|
||||
return State::Unmounted;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SD card and the screen are on the same SPI bus.
|
||||
* Writing and reading to the bus from 2 devices at the same time causes crashes.
|
||||
* This work-around ensures that this check is only happening when LVGL isn't rendering.
|
||||
*/
|
||||
auto lock = getLock()->asScopedLock();
|
||||
bool locked = lock.lock(timeout);
|
||||
if (!locked) {
|
||||
return State::Timeout;
|
||||
}
|
||||
|
||||
if (sdmmc_get_status(card) != ESP_OK) {
|
||||
return State::Error;
|
||||
}
|
||||
|
||||
return State::Mounted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,10 +1,13 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include <soc/soc_caps.h>
|
||||
|
||||
#include <Tactility/hal/usb/Usb.h>
|
||||
#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
|
||||
#include <Tactility/hal/usb/UsbTusb.h>
|
||||
|
||||
#include <Tactility/Logger.h>
|
||||
#include <tactility/drivers/esp32_sdmmc.h>
|
||||
|
||||
namespace tt::hal::usb {
|
||||
|
||||
@@ -21,29 +24,41 @@ static Mode currentMode = Mode::Default;
|
||||
static RTC_NOINIT_ATTR BootModeData bootModeData;
|
||||
|
||||
sdmmc_card_t* getCard() {
|
||||
auto sdcards = findDevices<sdcard::SpiSdCardDevice>(Device::Type::SdCard);
|
||||
sdmmc_card_t* sdcard = nullptr;
|
||||
|
||||
std::shared_ptr<sdcard::SpiSdCardDevice> usable_sdcard;
|
||||
for (auto& sdcard : sdcards) {
|
||||
auto sdcard_candidate = std::static_pointer_cast<sdcard::SpiSdCardDevice>(sdcard);
|
||||
if (sdcard_candidate != nullptr && sdcard_candidate->isMounted() && sdcard_candidate->getCard() != nullptr) {
|
||||
usable_sdcard = sdcard_candidate;
|
||||
// Find old HAL SD card device:
|
||||
auto sdcards = findDevices<sdcard::SpiSdCardDevice>(Device::Type::SdCard);
|
||||
for (auto& device : sdcards) {
|
||||
auto sdcard_device= std::static_pointer_cast<sdcard::SpiSdCardDevice>(device);
|
||||
if (sdcard_device != nullptr && sdcard_device->isMounted() && sdcard_device->getCard() != nullptr) {
|
||||
sdcard = sdcard_device->getCard();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (usable_sdcard == nullptr) {
|
||||
LOGGER.warn("Couldn't find a mounted SpiSdCard");
|
||||
return nullptr;
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
// Find ESP32 SDMMC device:
|
||||
if (sdcard == nullptr) {
|
||||
device_for_each(&sdcard, [](auto* device, void* context) {
|
||||
if (device_is_ready(device) && device_is_compatible(device, "espressif,esp32-sdmmc")) {
|
||||
auto** sdcard = static_cast<sdmmc_card_t**>(context);
|
||||
auto* sdmmc_card = esp32_sdmmc_get_card(device);
|
||||
if (sdmmc_card) {
|
||||
*sdcard = sdmmc_card;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sdcard == nullptr) {
|
||||
LOGGER.warn("Couldn't find a mounted SD card");
|
||||
}
|
||||
|
||||
auto* sdmmc_card = usable_sdcard->getCard();
|
||||
if (sdmmc_card == nullptr) {
|
||||
LOGGER.warn("SD card has no card object available");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sdmmc_card;
|
||||
return sdcard;
|
||||
}
|
||||
|
||||
static bool canStartNewMode() {
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
#include <Tactility/service/ServiceContext.h>
|
||||
#include <Tactility/service/ServiceRegistration.h>
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/Timer.h>
|
||||
|
||||
namespace tt::service::sdcard {
|
||||
|
||||
static const auto LOGGER = Logger("SdcardService");
|
||||
|
||||
extern const ServiceManifest manifest;
|
||||
|
||||
class SdCardService final : public Service {
|
||||
|
||||
Mutex mutex;
|
||||
std::unique_ptr<Timer> updateTimer;
|
||||
hal::sdcard::SdCardDevice::State lastState = hal::sdcard::SdCardDevice::State::Unmounted;
|
||||
|
||||
bool lock(TickType_t timeout) const {
|
||||
return mutex.lock(timeout);
|
||||
}
|
||||
|
||||
void unlock() const {
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void update() {
|
||||
// TODO: Support multiple SD cards
|
||||
auto sdcard = hal::findFirstDevice<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
if (sdcard == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lock(50)) {
|
||||
auto new_state = sdcard->getState();
|
||||
|
||||
if (new_state == hal::sdcard::SdCardDevice::State::Error) {
|
||||
LOGGER.error("Sdcard error - unmounting. Did you eject the card in an unsafe manner?");
|
||||
sdcard->unmount();
|
||||
}
|
||||
|
||||
if (new_state != lastState) {
|
||||
lastState = new_state;
|
||||
}
|
||||
|
||||
unlock();
|
||||
} else {
|
||||
LOGGER.warn(LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool onStart(ServiceContext& serviceContext) override {
|
||||
if (hal::findFirstDevice<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard) == nullptr) {
|
||||
LOGGER.warn("No SD card device found - not starting Service");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto service = findServiceById<SdCardService>(manifest.id);
|
||||
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, 1000, [service] {
|
||||
service->update();
|
||||
});
|
||||
|
||||
// We want to try and scan more often in case of startup or scan lock failure
|
||||
updateTimer->start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onStop(ServiceContext& serviceContext) override {
|
||||
if (updateTimer != nullptr) {
|
||||
// Stop thread
|
||||
updateTimer->stop();
|
||||
updateTimer = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern const ServiceManifest manifest = {
|
||||
.id = "sdcard",
|
||||
.createService = create<SdCardService>
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
#include <Tactility/Paths.h>
|
||||
#include <Tactility/Timer.h>
|
||||
#include <tactility/check.h>
|
||||
#include <Tactility/hal/power/PowerDevice.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/lvgl/Lvgl.h>
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <Tactility/service/ServiceRegistration.h>
|
||||
#include <Tactility/service/gps/GpsService.h>
|
||||
#include <Tactility/service/wifi/Wifi.h>
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <tactility/lvgl_icon_statusbar.h>
|
||||
|
||||
@@ -56,18 +57,9 @@ static const char* getWifiStatusIcon(wifi::RadioState state) {
|
||||
}
|
||||
}
|
||||
|
||||
static const char* getSdCardStatusIcon(hal::sdcard::SdCardDevice::State state) {
|
||||
switch (state) {
|
||||
using enum hal::sdcard::SdCardDevice::State;
|
||||
case Mounted:
|
||||
return LVGL_ICON_STATUSBAR_SD_CARD;
|
||||
case Error:
|
||||
case Unmounted:
|
||||
case Timeout:
|
||||
return LVGL_ICON_STATUSBAR_SD_CARD_ALERT;
|
||||
default:
|
||||
check(false, "Unhandled SdCard state");
|
||||
}
|
||||
static const char* getSdCardStatusIcon(bool mounted) {
|
||||
if (mounted) return LVGL_ICON_STATUSBAR_SD_CARD;
|
||||
return LVGL_ICON_STATUSBAR_SD_CARD_ALERT;
|
||||
}
|
||||
|
||||
static const char* getPowerStatusIcon() {
|
||||
@@ -172,20 +164,21 @@ class StatusbarService final : public Service {
|
||||
}
|
||||
|
||||
void updateSdCardIcon() {
|
||||
auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
auto* sdcard_fs = findSdcardFileSystem(false);
|
||||
// TODO: Support multiple SD cards
|
||||
auto sdcard = sdcards.empty() ? nullptr : sdcards[0];
|
||||
if (sdcard != nullptr) {
|
||||
auto state = sdcard->getState(50 / portTICK_PERIOD_MS);
|
||||
if (state != hal::sdcard::SdCardDevice::State::Timeout) {
|
||||
auto* desired_icon = getSdCardStatusIcon(state);
|
||||
if (sdcard_last_icon != desired_icon) {
|
||||
lvgl::statusbar_icon_set_image(sdcard_icon_id, desired_icon);
|
||||
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
||||
sdcard_last_icon = desired_icon;
|
||||
}
|
||||
if (sdcard_fs != nullptr) {
|
||||
auto mounted = file_system_is_mounted(sdcard_fs);
|
||||
auto* desired_icon = getSdCardStatusIcon(mounted);
|
||||
if (sdcard_last_icon != desired_icon) {
|
||||
lvgl::statusbar_icon_set_image(sdcard_icon_id, desired_icon);
|
||||
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
||||
sdcard_last_icon = desired_icon;
|
||||
}
|
||||
} else {
|
||||
if (sdcard_last_icon != nullptr) {
|
||||
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, false);
|
||||
sdcard_last_icon = nullptr;
|
||||
}
|
||||
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <Tactility/StringUtils.h>
|
||||
|
||||
#include <ranges>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||
#include <lv_screenshot.h>
|
||||
@@ -764,20 +765,24 @@ esp_err_t WebServerService::handleFsList(httpd_req_t* request) {
|
||||
|
||||
std::ostringstream json;
|
||||
json << "{\"path\":\"" << norm << "\",\"entries\":[";
|
||||
|
||||
struct FsIterContext {
|
||||
std::ostringstream& json;
|
||||
uint16_t count = 0;
|
||||
};
|
||||
FsIterContext fs_iter_context { json };
|
||||
// Special handling for root: show available mount points
|
||||
if (norm == "/") {
|
||||
// Always show /data
|
||||
json << "{\"name\":\"data\",\"type\":\"dir\",\"size\":0}";
|
||||
|
||||
// Show /sdcard if mounted
|
||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted()) {
|
||||
json << ",{\"name\":\"sdcard\",\"type\":\"dir\",\"size\":0}";
|
||||
break;
|
||||
file_system_for_each(&fs_iter_context, [] (auto* fs, void* context) {
|
||||
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
||||
char path[128];
|
||||
if (file_system_is_mounted(fs) && file_system_get_path(fs, path, sizeof(path)) == ERROR_NONE && strcmp(path, "/system") != 0) {
|
||||
fs_iter_context->count++;
|
||||
if (fs_iter_context->count != 1) fs_iter_context->json << ","; // add separator between json array entries
|
||||
fs_iter_context->json << "{\"name\":\"" << path << "\",\"type\":\"dir\",\"size\":0}";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
json << "]}";
|
||||
} else {
|
||||
std::vector<dirent> entries;
|
||||
@@ -1160,34 +1165,38 @@ esp_err_t WebServerService::handleApiSysinfo(httpd_req_t* request) {
|
||||
json << "\"storage\":{";
|
||||
uint64_t storage_total = 0, storage_free = 0;
|
||||
|
||||
// Data partition
|
||||
json << "\"data\":{";
|
||||
if (esp_vfs_fat_info(file::MOUNT_POINT_DATA, &storage_total, &storage_free) == ESP_OK) {
|
||||
json << "\"free\":" << storage_free << ",";
|
||||
json << "\"total\":" << storage_total << ",";
|
||||
json << "\"mounted\":true";
|
||||
} else {
|
||||
json << "\"mounted\":false";
|
||||
}
|
||||
json << "},";
|
||||
struct FsIterContext {
|
||||
std::ostringstream& json;
|
||||
uint16_t count = 0;
|
||||
};
|
||||
FsIterContext fs_iter_context { json };
|
||||
file_system_for_each(&fs_iter_context, [] (auto* fs, void* context) {
|
||||
char mount_path[128] = "";
|
||||
if (file_system_get_path(fs, mount_path, sizeof(mount_path)) != ERROR_NONE) return true;
|
||||
if (strcmp(mount_path, "/system") == 0) return true; // Hide system partition
|
||||
|
||||
// SD card - check all sdcard devices
|
||||
json << "\"sdcard\":{";
|
||||
bool sdcard_found = false;
|
||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||
json << "\"free\":" << storage_free << ",";
|
||||
json << "\"total\":" << storage_total << ",";
|
||||
json << "\"mounted\":true";
|
||||
sdcard_found = true;
|
||||
break;
|
||||
bool mounted = file_system_is_mounted(fs);
|
||||
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
||||
auto& json_context = fs_iter_context->json;
|
||||
std::string mount_path_cpp = mount_path;
|
||||
|
||||
fs_iter_context->count++;
|
||||
if (fs_iter_context->count != 1) json_context << ","; // add separator between json array entries
|
||||
json_context << "\"" << mount_path_cpp.substr(1) << "\":{";
|
||||
|
||||
uint64_t storage_total = 0, storage_free = 0;
|
||||
if (esp_vfs_fat_info(mount_path, &storage_total, &storage_free) == ESP_OK) {
|
||||
json_context << "\"free\":" << storage_free << ",";
|
||||
json_context << "\"total\":" << storage_total << ",";
|
||||
} else {
|
||||
json_context << "\"free\":0,";
|
||||
json_context << "\"total\":0,";
|
||||
}
|
||||
}
|
||||
if (!sdcard_found) {
|
||||
json << "\"mounted\":false";
|
||||
}
|
||||
json << "}";
|
||||
|
||||
json_context << "\"mounted\":" << (mounted ? "true" : "false") << "";
|
||||
json_context << "}";
|
||||
return true;
|
||||
});
|
||||
|
||||
json << "},"; // end storage
|
||||
|
||||
@@ -1459,14 +1468,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||
// Determine save location: prefer SD card root if mounted, otherwise /data
|
||||
std::string save_path;
|
||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (const auto& sdcard : sdcard_devices) {
|
||||
if (sdcard->isMounted()) {
|
||||
save_path = sdcard->getMountPath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (save_path.empty()) {
|
||||
if (!findFirstMountedSdCardPath(save_path)) {
|
||||
save_path = file::MOUNT_POINT_DATA;
|
||||
}
|
||||
|
||||
@@ -1543,7 +1545,7 @@ esp_err_t WebServerService::handleFsTree(httpd_req_t* request) {
|
||||
std::ostringstream json;
|
||||
json << "{";
|
||||
// Gather mount points
|
||||
auto mounts = file::getMountPoints();
|
||||
auto mounts = file::getFileSystemDirents();
|
||||
json << "\"mounts\": [";
|
||||
bool firstMount = true;
|
||||
for (auto& m : mounts) {
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/service/wifi/WifiApSettings.h>
|
||||
|
||||
#include <Tactility/Paths.h>
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <dirent.h>
|
||||
#include <format>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
|
||||
namespace tt::service::wifi {
|
||||
|
||||
@@ -118,18 +119,14 @@ static void importWifiApSettingsFromDir(const std::string& path) {
|
||||
void bootSplashInit() {
|
||||
getMainDispatcher().dispatch([] {
|
||||
// First import any provisioning files placed on the system data partition.
|
||||
const std::string settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings");
|
||||
importWifiApSettingsFromDir(settings_path);
|
||||
const std::string data_settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings");
|
||||
importWifiApSettingsFromDir(data_settings_path);
|
||||
|
||||
// Then scan attached SD cards as before.
|
||||
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (auto& sdcard : sdcards) {
|
||||
if (sdcard->isMounted()) {
|
||||
const std::string settings_path = file::getChildPath(sdcard->getMountPath(), "settings");
|
||||
importWifiApSettingsFromDir(settings_path);
|
||||
} else {
|
||||
LOGGER.warn("Skipping unmounted SD card {}", sdcard->getMountPath());
|
||||
}
|
||||
std::string sdcard_path;
|
||||
if (findFirstMountedSdCardPath((sdcard_path))) {
|
||||
const std::string sd_settings_path = file::getChildPath(sdcard_path, "settings");
|
||||
importWifiApSettingsFromDir(sd_settings_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/settings/BootSettings.h>
|
||||
|
||||
#include <Tactility/Paths.h>
|
||||
#include <format>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -18,9 +19,9 @@ constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId";
|
||||
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
||||
|
||||
static std::string getPropertiesFilePath() {
|
||||
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
||||
for (auto& sdcard : sdcards) {
|
||||
std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard->getMountPath());
|
||||
std::string sdcard_path;
|
||||
if (findFirstMountedSdCardPath(sdcard_path)) {
|
||||
std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard_path);
|
||||
if (file::isFile(path)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user