mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-04-18 09:25:06 +00:00
Refactor all SD card path usages
This commit is contained in:
parent
e4cf91aa18
commit
6f7ed252ea
@ -1,9 +1,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <tactility/drivers/gpio.h>
|
#include <sd_protocol_types.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <tactility/drivers/gpio.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -27,6 +28,8 @@ struct Esp32SdmmcConfig {
|
|||||||
bool enable_uhs;
|
bool enable_uhs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sdmmc_card_t* esp32_sdmmc_get_card(struct Device* device);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Esp32SdmmcConfig;
|
||||||
|
typedef void* Esp32SdmmcHandle;
|
||||||
|
|
||||||
|
extern Esp32SdmmcHandle esp32_sdmmc_fs_alloc(const struct Esp32SdmmcConfig* config, const char* mount_path);
|
||||||
|
|
||||||
|
extern void esp32_sdmmc_fs_free(Esp32SdmmcHandle handle);
|
||||||
|
|
||||||
|
extern sdmmc_card_t* esp32_sdmmc_fs_get_card(Esp32SdmmcHandle handle);
|
||||||
|
|
||||||
|
extern const FileSystemApi esp32_sdmmc_fs_api;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -1,12 +1,14 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/drivers/esp32_sdmmc.h>
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||||
#include <tactility/concurrent/recursive_mutex.h>
|
#include <tactility/concurrent/recursive_mutex.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
#include "tactility/drivers/gpio_descriptor.h"
|
#include "tactility/drivers/gpio_descriptor.h"
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <tactility/drivers/esp32_gpio_helpers.h>
|
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
#define TAG "esp32_sdmmc"
|
#define TAG "esp32_sdmmc"
|
||||||
|
|
||||||
@ -18,13 +20,8 @@ extern "C" {
|
|||||||
struct Esp32SdmmcInternal {
|
struct Esp32SdmmcInternal {
|
||||||
RecursiveMutex mutex = {};
|
RecursiveMutex mutex = {};
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
char fs_device_name[16] = "esp32_sdmmc_fs0";
|
Esp32SdmmcHandle esp32_sdmmc_fs_handle = nullptr;
|
||||||
Device fs_device = {
|
FileSystem* file_system = nullptr;
|
||||||
.name = fs_device_name,
|
|
||||||
.config = nullptr,
|
|
||||||
.parent = nullptr,
|
|
||||||
.internal = nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pin descriptors
|
// Pin descriptors
|
||||||
GpioDescriptor* pin_clk_descriptor = nullptr;
|
GpioDescriptor* pin_clk_descriptor = nullptr;
|
||||||
@ -47,6 +44,7 @@ struct Esp32SdmmcInternal {
|
|||||||
~Esp32SdmmcInternal() {
|
~Esp32SdmmcInternal() {
|
||||||
cleanup_pins();
|
cleanup_pins();
|
||||||
recursive_mutex_destruct(&mutex);
|
recursive_mutex_destruct(&mutex);
|
||||||
|
if (esp32_sdmmc_fs_handle) free(esp32_sdmmc_fs_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_pins() {
|
void cleanup_pins() {
|
||||||
@ -96,7 +94,6 @@ static error_t start(Device* device) {
|
|||||||
acquire_pin_or_set_null(sdmmc_config->pin_cd, &data->pin_cd_descriptor) &&
|
acquire_pin_or_set_null(sdmmc_config->pin_cd, &data->pin_cd_descriptor) &&
|
||||||
acquire_pin_or_set_null(sdmmc_config->pin_wp, &data->pin_wp_descriptor);
|
acquire_pin_or_set_null(sdmmc_config->pin_wp, &data->pin_wp_descriptor);
|
||||||
|
|
||||||
|
|
||||||
if (!pins_ok) {
|
if (!pins_ok) {
|
||||||
LOG_E(TAG, "Failed to acquire required one or more pins");
|
LOG_E(TAG, "Failed to acquire required one or more pins");
|
||||||
data->cleanup_pins();
|
data->cleanup_pins();
|
||||||
@ -105,11 +102,13 @@ static error_t start(Device* device) {
|
|||||||
return ERROR_RESOURCE;
|
return ERROR_RESOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create filesystem child device
|
data->esp32_sdmmc_fs_handle = esp32_sdmmc_fs_alloc(sdmmc_config, "/sdcard");
|
||||||
auto* fs_device = &data->fs_device;
|
data->file_system = file_system_add(&esp32_sdmmc_fs_api, data->esp32_sdmmc_fs_handle);
|
||||||
fs_device->parent = device;
|
if (file_system_mount(data->file_system) != ERROR_NONE) {
|
||||||
fs_device->config = sdmmc_config;
|
// Error is not recoverable at the time, but it might be recoverable later,
|
||||||
check(device_construct_add_start(fs_device, "espressif,esp32-sdmmc-fs") == ERROR_NONE);
|
// so we don't return start() failure.
|
||||||
|
LOG_E(TAG, "Failed to mount SD card filesystem");
|
||||||
|
}
|
||||||
|
|
||||||
data->initialized = true;
|
data->initialized = true;
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
@ -120,11 +119,19 @@ static error_t stop(Device* device) {
|
|||||||
auto* data = GET_DATA(device);
|
auto* data = GET_DATA(device);
|
||||||
auto* dts_config = GET_CONFIG(device);
|
auto* dts_config = GET_CONFIG(device);
|
||||||
|
|
||||||
// Create filesystem child device
|
if (file_system_is_mounted(data->file_system)) {
|
||||||
auto* fs_device = &data->fs_device;
|
if (file_system_unmount(data->file_system) != ERROR_NONE) {
|
||||||
check(device_stop(fs_device) == ERROR_NONE);
|
LOG_E(TAG, "Failed to unmount SD card filesystem");
|
||||||
check(device_remove(fs_device) == ERROR_NONE);
|
return ERROR_RESOURCE;
|
||||||
check(device_destruct(fs_device) == ERROR_NONE);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free file system
|
||||||
|
file_system_remove(data->file_system);
|
||||||
|
data->file_system = nullptr;
|
||||||
|
// Free file system data
|
||||||
|
esp32_sdmmc_fs_free(data->esp32_sdmmc_fs_handle);
|
||||||
|
data->esp32_sdmmc_fs_handle = nullptr;
|
||||||
|
|
||||||
data->cleanup_pins();
|
data->cleanup_pins();
|
||||||
device_set_driver_data(device, nullptr);
|
device_set_driver_data(device, nullptr);
|
||||||
@ -132,6 +139,12 @@ static error_t stop(Device* device) {
|
|||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdmmc_card_t* esp32_sdmmc_get_card(Device* device) {
|
||||||
|
if (!device_is_ready(device)) return nullptr;
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
return esp32_sdmmc_fs_get_card(data->esp32_sdmmc_fs_handle);
|
||||||
|
}
|
||||||
|
|
||||||
extern Module platform_esp32_module;
|
extern Module platform_esp32_module;
|
||||||
|
|
||||||
Driver esp32_sdmmc_driver = {
|
Driver esp32_sdmmc_driver = {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/drivers/esp32_sdmmc.h>
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
#include <tactility/drivers/file_system.h>
|
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/drivers/gpio_descriptor.h>
|
#include <tactility/drivers/gpio_descriptor.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
#include <driver/sdmmc_host.h>
|
#include <driver/sdmmc_host.h>
|
||||||
#include <esp_vfs_fat.h>
|
#include <esp_vfs_fat.h>
|
||||||
#include <new>
|
|
||||||
#include <sdmmc_cmd.h>
|
#include <sdmmc_cmd.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -17,16 +17,24 @@
|
|||||||
|
|
||||||
#define TAG "esp32_sdmmc_fs"
|
#define TAG "esp32_sdmmc_fs"
|
||||||
|
|
||||||
#define GET_DATA(device) ((struct Esp32SdmmcFsInternal*)device_get_driver_data(device))
|
#define GET_DATA(data) static_cast<Esp32SdmmcFsData*>(data)
|
||||||
// We re-use the config from the parent device
|
|
||||||
#define GET_CONFIG(device) ((const struct Esp32SdmmcConfig*)device->config)
|
|
||||||
|
|
||||||
struct Esp32SdmmcFsInternal {
|
struct Esp32SdmmcFsData {
|
||||||
std::string mount_path {};
|
const std::string mount_path;
|
||||||
sdmmc_card_t* card = nullptr;
|
const Esp32SdmmcConfig* config;
|
||||||
|
sdmmc_card_t* card;
|
||||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
sd_pwr_ctrl_handle_t pwr_ctrl_handle = nullptr;
|
sd_pwr_ctrl_handle_t pwr_ctrl_handle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Esp32SdmmcFsData(const Esp32SdmmcConfig* config, const std::string& mount_path) :
|
||||||
|
mount_path(mount_path),
|
||||||
|
config(config),
|
||||||
|
card(nullptr)
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
,pwr_ctrl_handle(nullptr)
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
static gpio_num_t to_native_pin(GpioPinSpec pin_spec) {
|
static gpio_num_t to_native_pin(GpioPinSpec pin_spec) {
|
||||||
@ -36,11 +44,26 @@ static gpio_num_t to_native_pin(GpioPinSpec pin_spec) {
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
error_t mount(Device* device, const char* mount_path) {
|
static error_t get_path(void* data, char* out_path, size_t out_path_size);
|
||||||
LOG_I(TAG, "Mounting %s", mount_path);
|
|
||||||
|
|
||||||
auto* data = GET_DATA(device);
|
Esp32SdmmcHandle esp32_sdmmc_fs_alloc(const Esp32SdmmcConfig* config, const char* mount_path) {
|
||||||
auto* config = GET_CONFIG(device);
|
return new(std::nothrow) Esp32SdmmcFsData(config, mount_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_card_t* esp32_sdmmc_fs_get_card(Esp32SdmmcHandle handle) {
|
||||||
|
return GET_DATA(handle)->card;
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp32_sdmmc_fs_free(Esp32SdmmcHandle handle) {
|
||||||
|
auto* fs_data = GET_DATA(handle);
|
||||||
|
delete fs_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t mount(void* data) {
|
||||||
|
auto* fs_data = GET_DATA(data);
|
||||||
|
auto* config = fs_data->config;
|
||||||
|
|
||||||
|
LOG_I(TAG, "Mounting %s", fs_data->mount_path.c_str());
|
||||||
|
|
||||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||||
.format_if_mount_failed = false,
|
.format_if_mount_failed = false,
|
||||||
@ -85,9 +108,9 @@ error_t mount(Device* device, const char* mount_path) {
|
|||||||
.flags = slot_config_flags
|
.flags = slot_config_flags
|
||||||
};
|
};
|
||||||
|
|
||||||
esp_err_t result = esp_vfs_fat_sdmmc_mount(mount_path, &host, &slot_config, &mount_config, &data->card);
|
esp_err_t result = esp_vfs_fat_sdmmc_mount(fs_data->mount_path.c_str(), &host, &slot_config, &mount_config, &fs_data->card);
|
||||||
|
|
||||||
if (result != ESP_OK || data->card == nullptr) {
|
if (result != ESP_OK || fs_data->card == nullptr) {
|
||||||
if (result == ESP_FAIL) {
|
if (result == ESP_FAIL) {
|
||||||
LOG_E(TAG, "Mounting failed. Ensure the card is formatted with FAT.");
|
LOG_E(TAG, "Mounting failed. Ensure the card is formatted with FAT.");
|
||||||
} else {
|
} else {
|
||||||
@ -102,23 +125,21 @@ error_t mount(Device* device, const char* mount_path) {
|
|||||||
return ERROR_UNDEFINED;
|
return ERROR_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_I(TAG, "Mounted %s", mount_path);
|
LOG_I(TAG, "Mounted %s", fs_data->mount_path.c_str());
|
||||||
data->mount_path = mount_path;
|
|
||||||
|
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t unmount(Device* device) {
|
static error_t unmount(void* data) {
|
||||||
auto* data = GET_DATA(device);
|
auto* fs_data = GET_DATA(data);
|
||||||
|
LOG_I(TAG, "Unmounting %s", fs_data->mount_path.c_str());
|
||||||
|
|
||||||
if (esp_vfs_fat_sdcard_unmount(data->mount_path.c_str(), data->card) != ESP_OK) {
|
if (esp_vfs_fat_sdcard_unmount(fs_data->mount_path.c_str(), fs_data->card) != ESP_OK) {
|
||||||
LOG_E(TAG, "Unmount failed for %s", data->mount_path.c_str());
|
LOG_E(TAG, "Unmount failed for %s", fs_data->mount_path.c_str());
|
||||||
return ERROR_UNDEFINED;
|
return ERROR_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_I(TAG, "Unmounted %s", data->mount_path.c_str());
|
fs_data->card = nullptr;
|
||||||
data->mount_path = "";
|
|
||||||
data->card = nullptr;
|
|
||||||
|
|
||||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
if (data->pwr_ctrl_handle) {
|
if (data->pwr_ctrl_handle) {
|
||||||
@ -127,69 +148,30 @@ error_t unmount(Device* device) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ERROR_NONE;
|
LOG_I(TAG, "Unmounted %s", fs_data->mount_path.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
bool is_mounted(Device* device) {
|
|
||||||
const auto* data = GET_DATA(device);
|
|
||||||
return data != nullptr && data->card != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t get_mount_path(Device* device, char* out_path, size_t out_path_size) {
|
|
||||||
const auto* data = GET_DATA(device);
|
|
||||||
if (data == nullptr || data->card == nullptr) return ERROR_INVALID_STATE;
|
|
||||||
if (data->mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
|
||||||
strncpy(out_path, data->mount_path.c_str(), out_path_size);
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t start(Device* device) {
|
|
||||||
LOG_I(TAG, "start %s", device->name);
|
|
||||||
auto* data = new (std::nothrow) Esp32SdmmcFsInternal();
|
|
||||||
if (!data) return ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
device_set_driver_data(device, data);
|
|
||||||
|
|
||||||
if (mount(device, "/sdcard") != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to mount SD card");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static error_t stop(Device* device) {
|
static bool is_mounted(void* data) {
|
||||||
ESP_LOGI(TAG, "stop %s", device->name);
|
const auto* fs_data = GET_DATA(data);
|
||||||
auto* driver_data = GET_DATA(device);
|
if (fs_data == nullptr || fs_data->card == nullptr) return false;
|
||||||
|
return sdmmc_get_status(fs_data->card) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_mounted(device)) {
|
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||||
if (unmount(device) != ERROR_NONE) {
|
const auto* fs_data = GET_DATA(data);
|
||||||
LOG_E(TAG, "Failed to unmount SD card");
|
if (fs_data == nullptr || fs_data->card == nullptr) return ERROR_INVALID_STATE;
|
||||||
}
|
if (fs_data->mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||||
}
|
strncpy(out_path, fs_data->mount_path.c_str(), out_path_size);
|
||||||
|
|
||||||
device_set_driver_data(device, nullptr);
|
|
||||||
delete driver_data;
|
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern Module platform_esp32_module;
|
const FileSystemApi esp32_sdmmc_fs_api = {
|
||||||
|
|
||||||
static const FileSystemApi sdmmc_fs_api = {
|
|
||||||
.mount = mount,
|
.mount = mount,
|
||||||
.unmount = unmount,
|
.unmount = unmount,
|
||||||
.is_mounted = is_mounted,
|
.is_mounted = is_mounted,
|
||||||
.get_mount_path = get_mount_path
|
.get_path = get_path
|
||||||
};
|
|
||||||
|
|
||||||
Driver esp32_sdmmc_fs_driver = {
|
|
||||||
.name = "esp32_sdmmc_fs",
|
|
||||||
.compatible = (const char*[]) { "espressif,esp32-sdmmc-fs", nullptr },
|
|
||||||
.start_device = start,
|
|
||||||
.stop_device = stop,
|
|
||||||
.api = &sdmmc_fs_api,
|
|
||||||
.device_type = &FILE_SYSTEM_TYPE,
|
|
||||||
.owner = &platform_esp32_module,
|
|
||||||
.internal = nullptr
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@ -19,7 +19,6 @@ static error_t start() {
|
|||||||
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_sdmmc_fs_driver) == ERROR_NONE);
|
|
||||||
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
@ -32,7 +31,6 @@ static error_t stop() {
|
|||||||
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_sdmmc_fs_driver) == ERROR_NONE);
|
|
||||||
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
|
|||||||
@ -21,6 +21,6 @@ constexpr auto* MOUNT_POINT_DATA = "/data";
|
|||||||
constexpr auto* MOUNT_POINT_DATA = "data";
|
constexpr auto* MOUNT_POINT_DATA = "data";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<dirent> getMountPoints();
|
std::vector<dirent> getFileSystemDirents();
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -2,10 +2,19 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
bool findFirstMountedSdCardPath(std::string& path);
|
bool findFirstMountedSdCardPath(std::string& path);
|
||||||
|
|
||||||
|
bool hasMountedSdCard();
|
||||||
|
|
||||||
|
FileSystem* findFirstMountedSdcardFileSystem();
|
||||||
|
|
||||||
|
FileSystem* findFirstSdcardFileSystem();
|
||||||
|
|
||||||
std::string getSystemRootPath();
|
std::string getSystemRootPath();
|
||||||
|
|
||||||
std::string getTempPath();
|
std::string getTempPath();
|
||||||
|
|||||||
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
#include <tactility/hal/Device.h>
|
#include <tactility/hal/Device.h>
|
||||||
|
|
||||||
#include <Tactility/TactilityCore.h>
|
|
||||||
#include <Tactility/Lock.h>
|
#include <Tactility/Lock.h>
|
||||||
|
#include <Tactility/TactilityCore.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct FileSystem;
|
||||||
namespace tt::hal::sdcard {
|
namespace tt::hal::sdcard {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,11 +33,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
MountBehaviour mountBehaviour;
|
MountBehaviour mountBehaviour;
|
||||||
|
FileSystem* fileSystem;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit SdCardDevice(MountBehaviour mountBehaviour) : mountBehaviour(mountBehaviour) {}
|
explicit SdCardDevice(MountBehaviour mountBehaviour);
|
||||||
~SdCardDevice() override = default;
|
~SdCardDevice() override;
|
||||||
|
|
||||||
Type getType() const final { return Type::SdCard; };
|
Type getType() const final { return Type::SdCard; };
|
||||||
|
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
#ifdef ESP_PLATFORM
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "SdCardDevice.h"
|
|
||||||
|
|
||||||
#include <Tactility/RecursiveMutex.h>
|
|
||||||
#include <tactility/hal/Device.h>
|
|
||||||
#include <sd_protocol_types.h>
|
|
||||||
#include <soc/gpio_num.h>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tt::hal::sdcard {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SD card interface for the SDMMC interface.
|
|
||||||
*/
|
|
||||||
class SdmmcDevice final : public SdCardDevice {
|
|
||||||
|
|
||||||
std::shared_ptr<RecursiveMutex> mutex = std::make_shared<RecursiveMutex>();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct Config {
|
|
||||||
Config(
|
|
||||||
gpio_num_t pinClock,
|
|
||||||
gpio_num_t pinCmd,
|
|
||||||
gpio_num_t pinD0,
|
|
||||||
gpio_num_t pinD1,
|
|
||||||
gpio_num_t pinD2,
|
|
||||||
gpio_num_t pinD3,
|
|
||||||
MountBehaviour mountBehaviourAtBoot,
|
|
||||||
uint8_t busWidth = 4
|
|
||||||
) :
|
|
||||||
pinClock(pinClock),
|
|
||||||
pinCmd(pinCmd),
|
|
||||||
pinD0(pinD0),
|
|
||||||
pinD1(pinD1),
|
|
||||||
pinD2(pinD2),
|
|
||||||
pinD3(pinD3),
|
|
||||||
mountBehaviourAtBoot(mountBehaviourAtBoot),
|
|
||||||
busWidth(busWidth)
|
|
||||||
{}
|
|
||||||
|
|
||||||
gpio_num_t pinClock;
|
|
||||||
gpio_num_t pinCmd;
|
|
||||||
gpio_num_t pinD0;
|
|
||||||
gpio_num_t pinD1;
|
|
||||||
gpio_num_t pinD2;
|
|
||||||
gpio_num_t pinD3;
|
|
||||||
MountBehaviour mountBehaviourAtBoot;
|
|
||||||
uint8_t busWidth;
|
|
||||||
bool formatOnMountFailed = false;
|
|
||||||
uint16_t maxOpenFiles = 4;
|
|
||||||
uint16_t allocUnitSize = 16 * 1024;
|
|
||||||
bool statusCheckEnabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mountPath;
|
|
||||||
sdmmc_card_t* card = nullptr;
|
|
||||||
std::shared_ptr<Config> config;
|
|
||||||
|
|
||||||
bool applyGpioWorkAround();
|
|
||||||
bool mountInternal(const std::string& mountPath);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit SdmmcDevice(std::unique_ptr<Config> config) : SdCardDevice(config->mountBehaviourAtBoot),
|
|
||||||
config(std::move(config))
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string getName() const override { return "SDMMC"; }
|
|
||||||
std::string getDescription() const override { return "SD card via SDMMC interface"; }
|
|
||||||
|
|
||||||
bool mount(const std::string& mountPath) override;
|
|
||||||
bool unmount() override;
|
|
||||||
std::string getMountPath() const override { return mountPath; }
|
|
||||||
|
|
||||||
std::shared_ptr<Lock> getLock() const override { return mutex; }
|
|
||||||
|
|
||||||
State getState(TickType_t timeout) const override;
|
|
||||||
|
|
||||||
/** return card when mounted, otherwise return nullptr */
|
|
||||||
sdmmc_card_t* getCard() { return card; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -2,56 +2,37 @@
|
|||||||
|
|
||||||
#include "Tactility/TactilityConfig.h"
|
#include "Tactility/TactilityConfig.h"
|
||||||
#include <tactility/hal/Device.h>
|
#include <tactility/hal/Device.h>
|
||||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
|
||||||
|
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace tt::file {
|
namespace tt::file {
|
||||||
|
|
||||||
std::vector<dirent> getMountPoints() {
|
std::vector<dirent> getFileSystemDirents() {
|
||||||
std::vector<dirent> dir_entries;
|
std::vector<dirent> dir_entries;
|
||||||
dir_entries.clear();
|
dir_entries.clear();
|
||||||
|
|
||||||
// Data partition
|
file_system_for_each(&dir_entries, [](auto* fs, void* context) {
|
||||||
auto data_dirent = dirent{
|
if (!file_system_is_mounted(fs)) return true;
|
||||||
.d_ino = 1,
|
char path[128];
|
||||||
.d_type = TT_DT_DIR,
|
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||||
.d_name = { 0 }
|
auto mount_name = std::string(path).substr(1);
|
||||||
};
|
if (!config::SHOW_SYSTEM_PARTITION && mount_name.starts_with(SYSTEM_PARTITION_NAME)) return true;
|
||||||
strcpy(data_dirent.d_name, DATA_PARTITION_NAME);
|
auto dir_entry = dirent {
|
||||||
dir_entries.push_back(data_dirent);
|
.d_ino = 2,
|
||||||
|
|
||||||
// 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,
|
|
||||||
.d_type = TT_DT_DIR,
|
.d_type = TT_DT_DIR,
|
||||||
.d_name = { 0 }
|
.d_name = { 0 }
|
||||||
};
|
};
|
||||||
strcpy(system_dirent.d_name, SYSTEM_PARTITION_NAME);
|
auto& dir_entries = *static_cast<std::vector<dirent>*>(context);
|
||||||
dir_entries.push_back(system_dirent);
|
strcpy(dir_entry.d_name, mount_name.c_str());
|
||||||
}
|
dir_entries.push_back(dir_entry);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
return dir_entries;
|
return dir_entries;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,47 @@
|
|||||||
|
|
||||||
#include <esp_vfs_fat.h>
|
#include <esp_vfs_fat.h>
|
||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
static const auto LOGGER = Logger("Partitions");
|
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() {
|
static esp_err_t initNvsFlashSafely() {
|
||||||
esp_err_t result = nvs_flash_init();
|
esp_err_t result = nvs_flash_init();
|
||||||
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
@ -56,6 +92,7 @@ esp_err_t initPartitionsEsp() {
|
|||||||
LOGGER.error("Failed to mount /system ({})", esp_err_to_name(system_result));
|
LOGGER.error("Failed to mount /system ({})", esp_err_to_name(system_result));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Mounted /system");
|
LOGGER.info("Mounted /system");
|
||||||
|
file_system_add(&partition_fs_api, new PartitionFsData("/system"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data_result = esp_vfs_fat_spiflash_mount_rw_wl("/data", "data", &mount_config, &data_wl_handle);
|
auto data_result = esp_vfs_fat_spiflash_mount_rw_wl("/data", "data", &mount_config, &data_wl_handle);
|
||||||
@ -63,6 +100,7 @@ esp_err_t initPartitionsEsp() {
|
|||||||
LOGGER.error("Failed to mount /data ({})", esp_err_to_name(data_result));
|
LOGGER.error("Failed to mount /data ({})", esp_err_to_name(data_result));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Mounted /data");
|
LOGGER.info("Mounted /data");
|
||||||
|
file_system_add(&partition_fs_api, new PartitionFsData("/data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return system_result == ESP_OK && data_result == ESP_OK;
|
return system_result == ESP_OK && data_result == ESP_OK;
|
||||||
|
|||||||
@ -2,25 +2,54 @@
|
|||||||
|
|
||||||
#include <Tactility/app/AppManifestParsing.h>
|
#include <Tactility/app/AppManifestParsing.h>
|
||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
bool findFirstMountedSdCardPath(std::string& path) {
|
bool findFirstMountedSdCardPath(std::string& path) {
|
||||||
// const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
auto* fs = findFirstMountedSdcardFileSystem();
|
||||||
bool is_set = false;
|
if (fs == nullptr) return false;
|
||||||
hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard, [&is_set, &path](const auto& device) {
|
char found_path[128];
|
||||||
if (device->isMounted()) {
|
if (file_system_get_path(fs, found_path, sizeof(found_path)) != ERROR_NONE) return false;
|
||||||
path = device->getMountPath();
|
path = found_path;
|
||||||
is_set = true;
|
return true;
|
||||||
return false; // stop iterating
|
}
|
||||||
} else {
|
|
||||||
return true;
|
bool hasMountedSdCard() {
|
||||||
|
auto* fs = findFirstMountedSdcardFileSystem();
|
||||||
|
return fs != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystem* findFirstMountedSdcardFileSystem() {
|
||||||
|
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") && file_system_is_mounted(fs)) {
|
||||||
|
*static_cast<FileSystem**>(context) = fs;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
return is_set;
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystem* findFirstSdcardFileSystem() {
|
||||||
|
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 found;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getSystemRootPath() {
|
std::string getSystemRootPath() {
|
||||||
|
|||||||
@ -8,19 +8,19 @@
|
|||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/TactilityConfig.h>
|
#include <Tactility/TactilityConfig.h>
|
||||||
|
|
||||||
#include <Tactility/app/AppManifestParsing.h>
|
|
||||||
#include <Tactility/app/AppRegistration.h>
|
|
||||||
#include <Tactility/CpuAffinity.h>
|
#include <Tactility/CpuAffinity.h>
|
||||||
#include <Tactility/DispatcherThread.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/File.h>
|
||||||
#include <Tactility/file/FileLock.h>
|
#include <Tactility/file/FileLock.h>
|
||||||
#include <Tactility/file/PropertiesFile.h>
|
#include <Tactility/file/PropertiesFile.h>
|
||||||
#include <Tactility/hal/HalPrivate.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/lvgl/LvglPrivate.h>
|
||||||
#include <Tactility/MountPoints.h>
|
|
||||||
#include <Tactility/network/NtpPrivate.h>
|
#include <Tactility/network/NtpPrivate.h>
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
#include <Tactility/service/ServiceManifest.h>
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <tactility/concurrent/thread.h>
|
#include <tactility/concurrent/thread.h>
|
||||||
#include <tactility/drivers/uart_controller.h>
|
#include <tactility/drivers/uart_controller.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/hal_device_module.h>
|
#include <tactility/hal_device_module.h>
|
||||||
#include <tactility/kernel_init.h>
|
#include <tactility/kernel_init.h>
|
||||||
#include <tactility/lvgl_module.h>
|
#include <tactility/lvgl_module.h>
|
||||||
@ -228,22 +229,18 @@ static void registerInstalledApps(const std::string& path) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerInstalledAppsFromSdCard(const std::shared_ptr<hal::sdcard::SdCardDevice>& sdcard) {
|
static void registerInstalledAppsFromFileSystems() {
|
||||||
auto sdcard_root_path = sdcard->getMountPath();
|
file_system_for_each(nullptr, [](auto* fs, void* context) {
|
||||||
auto app_path = std::format("{}/app", sdcard_root_path);
|
if (!file_system_is_mounted(fs)) return true;
|
||||||
if (file::isDirectory(app_path)) {
|
char path[128];
|
||||||
registerInstalledApps(app_path);
|
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 {}", path);
|
||||||
static void registerInstalledAppsFromSdCards() {
|
registerInstalledApps(app_path);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerAndStartSecondaryServices() {
|
static void registerAndStartSecondaryServices() {
|
||||||
@ -266,7 +263,7 @@ static void registerAndStartSecondaryServices() {
|
|||||||
static void registerAndStartPrimaryServices() {
|
static void registerAndStartPrimaryServices() {
|
||||||
LOGGER.info("Registering and starting primary system services");
|
LOGGER.info("Registering and starting primary system services");
|
||||||
addService(service::gps::manifest);
|
addService(service::gps::manifest);
|
||||||
if (hal::hasDevice(hal::Device::Type::SdCard)) {
|
if (hasMountedSdCard()) {
|
||||||
addService(service::sdcard::manifest);
|
addService(service::sdcard::manifest);
|
||||||
}
|
}
|
||||||
addService(service::wifi::manifest);
|
addService(service::wifi::manifest);
|
||||||
@ -301,26 +298,19 @@ void createTempDirectory(const std::string& rootPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void prepareFileSystems() {
|
void prepareFileSystems() {
|
||||||
// Temporary directories for SD cards
|
file_system_for_each(nullptr, [](auto* fs, void* context) {
|
||||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
if (!file_system_is_mounted(fs)) return true;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
char path[128];
|
||||||
if (sdcard->isMounted()) {
|
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||||
createTempDirectory(sdcard->getMountPath());
|
if (std::string(path) == file::MOUNT_POINT_SYSTEM) return true;
|
||||||
}
|
createTempDirectory(path);
|
||||||
}
|
return true;
|
||||||
// Temporary directory for /data
|
});
|
||||||
if (file::isDirectory(file::MOUNT_POINT_DATA)) {
|
|
||||||
createTempDirectory(file::MOUNT_POINT_DATA);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerApps() {
|
void registerApps() {
|
||||||
registerInternalApps();
|
registerInternalApps();
|
||||||
auto data_apps_path = std::format("{}/app", file::MOUNT_POINT_DATA);
|
registerInstalledAppsFromFileSystems();
|
||||||
if (file::isDirectory(data_apps_path)) {
|
|
||||||
registerInstalledApps(data_apps_path);
|
|
||||||
}
|
|
||||||
registerInstalledAppsFromSdCards();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const Configuration& config, Module* dtsModules[], DtsDevice dtsDevices[]) {
|
void run(const Configuration& config, Module* dtsModules[], DtsDevice dtsDevices[]) {
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#include <Tactility/app/files/State.h>
|
#include <Tactility/app/files/State.h>
|
||||||
#include <Tactility/app/AppContext.h>
|
#include <Tactility/app/AppContext.h>
|
||||||
|
|
||||||
#include <Tactility/Assets.h>
|
|
||||||
#include <Tactility/service/loader/Loader.h>
|
#include <Tactility/service/loader/Loader.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|||||||
@ -51,7 +51,7 @@ bool State::setEntriesForPath(const std::string& path) {
|
|||||||
bool get_mount_points = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
bool get_mount_points = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
||||||
if (get_mount_points) {
|
if (get_mount_points) {
|
||||||
LOGGER.info("Setting custom root");
|
LOGGER.info("Setting custom root");
|
||||||
dir_entries = file::getMountPoints();
|
dir_entries = file::getFileSystemDirents();
|
||||||
current_path = path;
|
current_path = path;
|
||||||
selected_child_entry = "";
|
selected_child_entry = "";
|
||||||
action = ActionNone;
|
action = ActionNone;
|
||||||
|
|||||||
@ -43,7 +43,7 @@ bool State::setEntriesForPath(const std::string& path) {
|
|||||||
bool show_custom_root = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
bool show_custom_root = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
||||||
if (show_custom_root) {
|
if (show_custom_root) {
|
||||||
LOGGER.info("Setting custom root");
|
LOGGER.info("Setting custom root");
|
||||||
dir_entries = file::getMountPoints();
|
dir_entries = file::getFileSystemDirents();
|
||||||
current_path = path;
|
current_path = path;
|
||||||
selected_child_entry = "";
|
selected_child_entry = "";
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/TactilityConfig.h>
|
#include <Tactility/TactilityConfig.h>
|
||||||
|
|
||||||
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
|
|
||||||
#include <Tactility/app/App.h>
|
#include <Tactility/app/App.h>
|
||||||
#include <Tactility/app/AppManifest.h>
|
#include <Tactility/app/AppManifest.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/kernel/Platform.h>
|
#include <Tactility/kernel/Platform.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/lvgl/Lvgl.h>
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <Tactility/service/screenshot/Screenshot.h>
|
#include <Tactility/service/screenshot/Screenshot.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
|
|
||||||
#include <tactility/lvgl_icon_shared.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_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_devices = tt::hal::findDevices<tt::hal::sdcard::SdCardDevice>(tt::hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
if (sdcard_devices.size() > 1) {
|
if (findFirstMountedSdCardPath(sdcard_path)) {
|
||||||
LOGGER.warn("Found multiple SD card devices - picking first");
|
std::string lvgl_mount_path = lvgl::PATH_PREFIX + sdcard_path + "/screenshots";
|
||||||
}
|
|
||||||
if (!sdcard_devices.empty() && sdcard_devices.front()->isMounted()) {
|
|
||||||
std::string lvgl_mount_path = lvgl::PATH_PREFIX + sdcard_devices.front()->getMountPath();
|
|
||||||
lv_textarea_set_text(pathTextArea, lvgl_mount_path.c_str());
|
lv_textarea_set_text(pathTextArea, lvgl_mount_path.c_str());
|
||||||
} else {
|
} else {
|
||||||
lv_textarea_set_text(pathTextArea, "Error: no SD card");
|
lv_textarea_set_text(pathTextArea, "Error: no SD card");
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#include <Tactility/TactilityConfig.h>
|
#include <Tactility/TactilityConfig.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
@ -343,14 +343,9 @@ class SystemInfoApp final : public App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSdcardStorage) {
|
std::string sdcard_path;
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
if (findFirstMountedSdCardPath(sdcard_path) && esp_vfs_fat_info(sdcard_path.c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
updateMemoryBar(sdcardStorageBar, storage_free, storage_total);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSystemStorage) {
|
if (hasSystemStorage) {
|
||||||
@ -624,13 +619,10 @@ class SystemInfoApp final : public App {
|
|||||||
dataStorageBar = createMemoryBar(storage_tab, file::MOUNT_POINT_DATA);
|
dataStorageBar = createMemoryBar(storage_tab, file::MOUNT_POINT_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
if (findFirstMountedSdCardPath(sdcard_path) && esp_vfs_fat_info(sdcard_path.c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
hasSdcardStorage = true;
|
||||||
hasSdcardStorage = true;
|
sdcardStorageBar = createMemoryBar(storage_tab, sdcard_path.c_str());
|
||||||
sdcardStorageBar = createMemoryBar(storage_tab, sdcard->getMountPath().c_str());
|
|
||||||
break; // Only show first SD card
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config::SHOW_SYSTEM_PARTITION) {
|
if (config::SHOW_SYSTEM_PARTITION) {
|
||||||
|
|||||||
48
Tactility/Source/hal/sdcard/SdCardDevice.cpp
Normal file
48
Tactility/Source/hal/sdcard/SdCardDevice.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||||
|
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (device->getMountPath().size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||||
|
strncpy(out_path, device->getMountPath().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 = 512 * 8,
|
|
||||||
.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
|
|
||||||
@ -5,6 +5,7 @@
|
|||||||
#include <Tactility/hal/usb/UsbTusb.h>
|
#include <Tactility/hal/usb/UsbTusb.h>
|
||||||
|
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
|
|
||||||
namespace tt::hal::usb {
|
namespace tt::hal::usb {
|
||||||
|
|
||||||
@ -21,29 +22,35 @@ static Mode currentMode = Mode::Default;
|
|||||||
static RTC_NOINIT_ATTR BootModeData bootModeData;
|
static RTC_NOINIT_ATTR BootModeData bootModeData;
|
||||||
|
|
||||||
sdmmc_card_t* getCard() {
|
sdmmc_card_t* getCard() {
|
||||||
auto sdcards = findDevices<sdcard::SpiSdCardDevice>(Device::Type::SdCard);
|
sdmmc_card_t* sdcard = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<sdcard::SpiSdCardDevice> usable_sdcard;
|
// Find old HAL SD card device:
|
||||||
for (auto& sdcard : sdcards) {
|
auto sdcards = findDevices<sdcard::SpiSdCardDevice>(Device::Type::SdCard);
|
||||||
auto sdcard_candidate = std::static_pointer_cast<sdcard::SpiSdCardDevice>(sdcard);
|
for (auto& device : sdcards) {
|
||||||
if (sdcard_candidate != nullptr && sdcard_candidate->isMounted() && sdcard_candidate->getCard() != nullptr) {
|
auto sdcard_device= std::static_pointer_cast<sdcard::SpiSdCardDevice>(device);
|
||||||
usable_sdcard = sdcard_candidate;
|
if (sdcard_device != nullptr && sdcard_device->isMounted() && sdcard_device->getCard() != nullptr) {
|
||||||
|
sdcard = sdcard_device->getCard();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usable_sdcard == nullptr) {
|
// Find ESP32 SDMMC device:
|
||||||
LOGGER.warn("Couldn't find a mounted SpiSdCard");
|
if (sdcard == nullptr) {
|
||||||
return 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);
|
||||||
|
*sdcard = esp32_sdmmc_get_card(device);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sdmmc_card = usable_sdcard->getCard();
|
if (sdcard == nullptr) {
|
||||||
if (sdmmc_card == nullptr) {
|
LOGGER.warn("Couldn't find a mounted SD card");
|
||||||
LOGGER.warn("SD card has no card object available");
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sdmmc_card;
|
return sdcard;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canStartNewMode() {
|
static bool canStartNewMode() {
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/Logger.h>
|
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/LogMessages.h>
|
||||||
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/Mutex.h>
|
#include <Tactility/Mutex.h>
|
||||||
#include <Tactility/service/ServiceContext.h>
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
|
||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
|
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||||
|
#include <Tactility/service/ServiceContext.h>
|
||||||
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
|
|
||||||
namespace tt::service::sdcard {
|
namespace tt::service::sdcard {
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ class SdCardService final : public Service {
|
|||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
std::unique_ptr<Timer> updateTimer;
|
std::unique_ptr<Timer> updateTimer;
|
||||||
hal::sdcard::SdCardDevice::State lastState = hal::sdcard::SdCardDevice::State::Unmounted;
|
bool lastMountedState = false;
|
||||||
|
|
||||||
bool lock(TickType_t timeout) const {
|
bool lock(TickType_t timeout) const {
|
||||||
return mutex.lock(timeout);
|
return mutex.lock(timeout);
|
||||||
@ -29,23 +30,13 @@ class SdCardService final : public Service {
|
|||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
// TODO: Support multiple SD cards
|
// TODO: Support multiple SD cards
|
||||||
auto sdcard = hal::findFirstDevice<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
auto* file_system = findFirstSdcardFileSystem();
|
||||||
if (sdcard == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lock(50)) {
|
if (lock(50)) {
|
||||||
auto new_state = sdcard->getState();
|
auto is_mounted = file_system_is_mounted(file_system);
|
||||||
|
if (is_mounted != lastMountedState) {
|
||||||
if (new_state == hal::sdcard::SdCardDevice::State::Error) {
|
lastMountedState = is_mounted;
|
||||||
LOGGER.error("Sdcard error - unmounting. Did you eject the card in an unsafe manner?");
|
|
||||||
sdcard->unmount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_state != lastState) {
|
|
||||||
lastState = new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
} else {
|
} else {
|
||||||
LOGGER.warn(LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
LOGGER.warn(LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||||
@ -55,7 +46,8 @@ class SdCardService final : public Service {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
bool onStart(ServiceContext& serviceContext) override {
|
bool onStart(ServiceContext& serviceContext) override {
|
||||||
if (hal::findFirstDevice<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard) == nullptr) {
|
auto* sdcard_fs = findFirstSdcardFileSystem();
|
||||||
|
if (sdcard_fs == nullptr) {
|
||||||
LOGGER.warn("No SD card device found - not starting Service");
|
LOGGER.warn("No SD card device found - not starting Service");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/Mutex.h>
|
#include <Tactility/Mutex.h>
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
#include <tactility/check.h>
|
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
#include <Tactility/hal/power/PowerDevice.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||||
#include <Tactility/lvgl/Lvgl.h>
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
#include <Tactility/service/gps/GpsService.h>
|
#include <Tactility/service/gps/GpsService.h>
|
||||||
#include <Tactility/service/wifi/Wifi.h>
|
#include <Tactility/service/wifi/Wifi.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
|
||||||
#include <tactility/lvgl_icon_statusbar.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) {
|
static const char* getSdCardStatusIcon(bool mounted) {
|
||||||
switch (state) {
|
if (mounted) return LVGL_ICON_STATUSBAR_SD_CARD;
|
||||||
using enum hal::sdcard::SdCardDevice::State;
|
return LVGL_ICON_STATUSBAR_SD_CARD_ALERT;
|
||||||
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* getPowerStatusIcon() {
|
static const char* getPowerStatusIcon() {
|
||||||
@ -172,18 +164,15 @@ class StatusbarService final : public Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateSdCardIcon() {
|
void updateSdCardIcon() {
|
||||||
auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
auto* sdcard_fs = findFirstSdcardFileSystem();
|
||||||
// TODO: Support multiple SD cards
|
// TODO: Support multiple SD cards
|
||||||
auto sdcard = sdcards.empty() ? nullptr : sdcards[0];
|
if (sdcard_fs != nullptr) {
|
||||||
if (sdcard != nullptr) {
|
auto mounted = file_system_is_mounted(sdcard_fs);
|
||||||
auto state = sdcard->getState(50 / portTICK_PERIOD_MS);
|
auto* desired_icon = getSdCardStatusIcon(mounted);
|
||||||
if (state != hal::sdcard::SdCardDevice::State::Timeout) {
|
if (sdcard_last_icon != desired_icon) {
|
||||||
auto* desired_icon = getSdCardStatusIcon(state);
|
lvgl::statusbar_icon_set_image(sdcard_icon_id, desired_icon);
|
||||||
if (sdcard_last_icon != desired_icon) {
|
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
||||||
lvgl::statusbar_icon_set_image(sdcard_icon_id, desired_icon);
|
sdcard_last_icon = desired_icon;
|
||||||
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
|
||||||
sdcard_last_icon = desired_icon;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,8 +26,7 @@
|
|||||||
#include <Tactility/StringUtils.h>
|
#include <Tactility/StringUtils.h>
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <tactility/drivers/file_system.h>
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/drivers/hal_device.h>
|
|
||||||
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
#include <lv_screenshot.h>
|
#include <lv_screenshot.h>
|
||||||
@ -762,26 +761,20 @@ esp_err_t WebServerService::handleFsList(httpd_req_t* request) {
|
|||||||
|
|
||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
json << "{\"path\":\"" << norm << "\",\"entries\":[";
|
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
|
// Special handling for root: show available mount points
|
||||||
if (norm == "/") {
|
if (norm == "/") {
|
||||||
// Always show /data
|
file_system_for_each(&fs_iter_context, [] (auto* fs, void* context) {
|
||||||
json << "{\"name\":\"data\",\"type\":\"dir\",\"size\":0}";
|
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
||||||
|
char path[128];
|
||||||
// Show /sdcard if mounted
|
if (file_system_is_mounted(fs) && file_system_get_path(fs, path, sizeof(path)) == ESP_OK && strcmp(path, "/system") != 0) {
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
fs_iter_context->count++;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
if (fs_iter_context->count != 1) fs_iter_context->json << ","; // add separator between json array entries
|
||||||
if (sdcard->isMounted()) {
|
fs_iter_context->json << "{\"name\":\"" << path << "\",\"type\":\"dir\",\"size\":0}";
|
||||||
json << ",{\"name\":\"sdcard\",\"type\":\"dir\",\"size\":0}";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
device_for_each_of_type(&FILE_SYSTEM_TYPE, &json, [] (auto* fs_device, void* context) {
|
|
||||||
if (file_system_is_mounted(fs_device)) {
|
|
||||||
auto* json_context_ptr = static_cast<std::ostringstream*>(context);
|
|
||||||
auto& json_context = *json_context_ptr;
|
|
||||||
json_context << ",{\"name\":\"sdcard\",\"type\":\"dir\",\"size\":0}";
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -1168,58 +1161,39 @@ esp_err_t WebServerService::handleApiSysinfo(httpd_req_t* request) {
|
|||||||
json << "\"storage\":{";
|
json << "\"storage\":{";
|
||||||
uint64_t storage_total = 0, storage_free = 0;
|
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 << "},";
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FsIterContext {
|
struct FsIterContext {
|
||||||
std::ostringstream& json;
|
std::ostringstream& json;
|
||||||
bool sdcard_found;
|
uint16_t count = 0;
|
||||||
};
|
};
|
||||||
FsIterContext fs_iter_context { json, sdcard_found };
|
FsIterContext fs_iter_context { json };
|
||||||
device_for_each_of_type(&FILE_SYSTEM_TYPE, &fs_iter_context, [] (auto* fs_device, void* context) {
|
file_system_for_each(&fs_iter_context, [] (auto* fs, void* context) {
|
||||||
if (!file_system_is_mounted(fs_device)) return true;
|
char mount_path[128] = "";
|
||||||
char mount_path[128];
|
if (file_system_get_path(fs, mount_path, sizeof(mount_path)) != ERROR_NONE) return true;
|
||||||
if (file_system_get_mount_path(fs_device, mount_path, sizeof(mount_path)) != ESP_OK) return true;
|
if (strcmp(mount_path, "/system") == 0) return true; // Hide system partition
|
||||||
uint64_t storage_total = 0, storage_free = 0;
|
|
||||||
if (esp_vfs_fat_info(mount_path, &storage_total, &storage_free) != ESP_OK) return true;
|
bool mounted = file_system_is_mounted(fs);
|
||||||
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
||||||
auto& json_context = fs_iter_context->json;
|
auto& json_context = fs_iter_context->json;
|
||||||
json_context << "\"free\":" << storage_free << ",";
|
std::string mount_path_cpp = mount_path;
|
||||||
json_context << "\"total\":" << storage_total << ",";
|
|
||||||
json_context << "\"mounted\":true";
|
fs_iter_context->count++;
|
||||||
fs_iter_context->sdcard_found = true;
|
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,";
|
||||||
|
}
|
||||||
|
|
||||||
|
json_context << "\"mounted\":" << (mounted ? "true" : "false") << "";
|
||||||
|
json_context << "}";
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fs_iter_context.sdcard_found) sdcard_found = true;
|
|
||||||
|
|
||||||
if (!sdcard_found) {
|
|
||||||
json << "\"mounted\":false";
|
|
||||||
}
|
|
||||||
json << "}";
|
|
||||||
|
|
||||||
json << "},"; // end storage
|
json << "},"; // end storage
|
||||||
|
|
||||||
// Uptime (in seconds)
|
// Uptime (in seconds)
|
||||||
@ -1490,14 +1464,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
|||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
// Determine save location: prefer SD card root if mounted, otherwise /data
|
// Determine save location: prefer SD card root if mounted, otherwise /data
|
||||||
std::string save_path;
|
std::string save_path;
|
||||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
if (!findFirstMountedSdCardPath(save_path)) {
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
|
||||||
if (sdcard->isMounted()) {
|
|
||||||
save_path = sdcard->getMountPath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (save_path.empty()) {
|
|
||||||
save_path = file::MOUNT_POINT_DATA;
|
save_path = file::MOUNT_POINT_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1574,7 +1541,7 @@ esp_err_t WebServerService::handleFsTree(httpd_req_t* request) {
|
|||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
json << "{";
|
json << "{";
|
||||||
// Gather mount points
|
// Gather mount points
|
||||||
auto mounts = file::getMountPoints();
|
auto mounts = file::getFileSystemDirents();
|
||||||
json << "\"mounts\": [";
|
json << "\"mounts\": [";
|
||||||
bool firstMount = true;
|
bool firstMount = true;
|
||||||
for (auto& m : mounts) {
|
for (auto& m : mounts) {
|
||||||
|
|||||||
@ -6,13 +6,14 @@
|
|||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/service/wifi/WifiApSettings.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 <dirent.h>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <Tactility/Tactility.h>
|
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
namespace tt::service::wifi {
|
||||||
|
|
||||||
@ -118,18 +119,14 @@ static void importWifiApSettingsFromDir(const std::string& path) {
|
|||||||
void bootSplashInit() {
|
void bootSplashInit() {
|
||||||
getMainDispatcher().dispatch([] {
|
getMainDispatcher().dispatch([] {
|
||||||
// First import any provisioning files placed on the system data partition.
|
// First import any provisioning files placed on the system data partition.
|
||||||
const std::string settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings");
|
const std::string data_settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings");
|
||||||
importWifiApSettingsFromDir(settings_path);
|
importWifiApSettingsFromDir(data_settings_path);
|
||||||
|
|
||||||
// Then scan attached SD cards as before.
|
// Then scan attached SD cards as before.
|
||||||
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
for (auto& sdcard : sdcards) {
|
if (findFirstMountedSdCardPath((sdcard_path))) {
|
||||||
if (sdcard->isMounted()) {
|
const std::string sd_settings_path = file::getChildPath(sdcard_path, "settings");
|
||||||
const std::string settings_path = file::getChildPath(sdcard->getMountPath(), "settings");
|
importWifiApSettingsFromDir(sd_settings_path);
|
||||||
importWifiApSettingsFromDir(settings_path);
|
|
||||||
} else {
|
|
||||||
LOGGER.warn("Skipping unmounted SD card {}", sdcard->getMountPath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/settings/BootSettings.h>
|
#include <Tactility/settings/BootSettings.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -18,9 +19,9 @@ constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId";
|
|||||||
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
||||||
|
|
||||||
static std::string getPropertiesFilePath() {
|
static std::string getPropertiesFilePath() {
|
||||||
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
for (auto& sdcard : sdcards) {
|
if (findFirstMountedSdCardPath(sdcard_path)) {
|
||||||
std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard->getMountPath());
|
std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard_path);
|
||||||
if (file::isFile(path)) {
|
if (file::isFile(path)) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <tactility/error.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct Device;
|
|
||||||
|
|
||||||
struct FileSystemApi {
|
|
||||||
error_t (*mount)(struct Device* device, const char* mount_path);
|
|
||||||
error_t (*unmount)(struct Device* device);
|
|
||||||
bool (*is_mounted)(struct Device* device);
|
|
||||||
error_t (*get_mount_path)(struct Device*, char* out_path, size_t out_path_size);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const struct DeviceType FILE_SYSTEM_TYPE;
|
|
||||||
|
|
||||||
error_t file_system_mount(struct Device* device, const char* mount_path);
|
|
||||||
|
|
||||||
error_t file_system_unmount(struct Device* device);
|
|
||||||
|
|
||||||
bool file_system_is_mounted(struct Device* device);
|
|
||||||
|
|
||||||
error_t file_system_get_mount_path(struct Device*, char* out_path, size_t out_path_size);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
37
TactilityKernel/include/tactility/filesystem/file_system.h
Normal file
37
TactilityKernel/include/tactility/filesystem/file_system.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct FileSystem;
|
||||||
|
|
||||||
|
struct FileSystemApi {
|
||||||
|
error_t (*mount)(void* data);
|
||||||
|
error_t (*unmount)(void* data);
|
||||||
|
bool (*is_mounted)(void* data);
|
||||||
|
error_t (*get_path)(void* data, char* out_path, size_t out_path_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileSystem* file_system_add(const struct FileSystemApi* fs_api, void* data);
|
||||||
|
|
||||||
|
void file_system_remove(struct FileSystem* fs);
|
||||||
|
|
||||||
|
void file_system_for_each(void* callback_context, bool (*callback)(struct FileSystem* fs, void* context));
|
||||||
|
|
||||||
|
error_t file_system_mount(struct FileSystem* fs);
|
||||||
|
|
||||||
|
error_t file_system_unmount(struct FileSystem* fs);
|
||||||
|
|
||||||
|
bool file_system_is_mounted(struct FileSystem* fs);
|
||||||
|
|
||||||
|
error_t file_system_get_path(struct FileSystem* fs, char* out_path, size_t out_path_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -1,32 +0,0 @@
|
|||||||
#include <tactility/drivers/file_system.h>
|
|
||||||
#include <tactility/device.h>
|
|
||||||
|
|
||||||
#define INTERNAL_API(driver) ((FileSystemApi*)(driver)->api)
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
error_t file_system_mount(Device* device, const char* mount_path) {
|
|
||||||
const auto* driver = device_get_driver(device);
|
|
||||||
return INTERNAL_API(driver)->mount(device, mount_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t file_system_unmount(Device* device) {
|
|
||||||
const auto* driver = device_get_driver(device);
|
|
||||||
return INTERNAL_API(driver)->unmount(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_system_is_mounted(Device* device) {
|
|
||||||
const auto* driver = device_get_driver(device);
|
|
||||||
return INTERNAL_API(driver)->is_mounted(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t file_system_get_mount_path(Device* device, char* out_path, size_t out_path_size) {
|
|
||||||
const auto* driver = device_get_driver(device);
|
|
||||||
return INTERNAL_API(driver)->get_mount_path(device, out_path, out_path_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
const DeviceType FILE_SYSTEM_TYPE {
|
|
||||||
.name = "file-system"
|
|
||||||
};
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
85
TactilityKernel/source/filesystem/file_system.cpp
Normal file
85
TactilityKernel/source/filesystem/file_system.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
#include <tactility/concurrent/mutex.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// Define the internal FileSystem structure
|
||||||
|
struct FileSystem {
|
||||||
|
const FileSystemApi* api;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global Mutex and the master list of file systems
|
||||||
|
static Mutex fs_mutex;
|
||||||
|
static bool fs_mutex_initialized = false;
|
||||||
|
static std::vector<FileSystem*> file_systems;
|
||||||
|
|
||||||
|
static void ensure_mutex_initialized() {
|
||||||
|
if (!fs_mutex_initialized) {
|
||||||
|
mutex_construct(&fs_mutex);
|
||||||
|
fs_mutex_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
FileSystem* file_system_add(const FileSystemApi* fs_api, void* data) {
|
||||||
|
ensure_mutex_initialized();
|
||||||
|
mutex_lock(&fs_mutex);
|
||||||
|
|
||||||
|
auto* fs = new(std::nothrow) struct FileSystem();
|
||||||
|
check(fs != nullptr);
|
||||||
|
fs->api = fs_api;
|
||||||
|
fs->data = data;
|
||||||
|
file_systems.push_back(fs);
|
||||||
|
|
||||||
|
mutex_unlock(&fs_mutex);
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_system_remove(FileSystem* fs) {
|
||||||
|
check(!file_system_is_mounted(fs));
|
||||||
|
ensure_mutex_initialized();
|
||||||
|
mutex_lock(&fs_mutex);
|
||||||
|
|
||||||
|
auto it = std::ranges::find(file_systems, fs);
|
||||||
|
if (it != file_systems.end()) {
|
||||||
|
file_systems.erase(it);
|
||||||
|
delete fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&fs_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_system_for_each(void* callback_context, bool (*callback)(FileSystem* fs, void* context)) {
|
||||||
|
ensure_mutex_initialized();
|
||||||
|
mutex_lock(&fs_mutex);
|
||||||
|
|
||||||
|
for (auto* fs : file_systems) {
|
||||||
|
if (!callback(fs, callback_context)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&fs_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t file_system_mount(FileSystem* fs) {
|
||||||
|
// Assuming 'device' is accessible or passed via a different mechanism
|
||||||
|
// as it's required by the FileSystemApi signatures.
|
||||||
|
return fs->api->mount(fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t file_system_unmount(FileSystem* fs) {
|
||||||
|
return fs->api->unmount(fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_system_is_mounted(FileSystem* fs) {
|
||||||
|
return fs->api->is_mounted(fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t file_system_get_path(FileSystem* fs, char* out_path, size_t out_path_size) {
|
||||||
|
return fs->api->get_path(fs->data, out_path, out_path_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,13 +5,13 @@
|
|||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/driver.h>
|
#include <tactility/driver.h>
|
||||||
#include <tactility/drivers/gpio_controller.h>
|
#include <tactility/drivers/gpio_controller.h>
|
||||||
#include <tactility/drivers/file_system.h>
|
|
||||||
#include <tactility/drivers/i2c_controller.h>
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
#include <tactility/drivers/i2s_controller.h>
|
#include <tactility/drivers/i2s_controller.h>
|
||||||
#include <tactility/drivers/root.h>
|
#include <tactility/drivers/root.h>
|
||||||
#include <tactility/drivers/spi_controller.h>
|
#include <tactility/drivers/spi_controller.h>
|
||||||
#include <tactility/drivers/uart_controller.h>
|
#include <tactility/drivers/uart_controller.h>
|
||||||
#include <tactility/error.h>
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,11 +58,6 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(driver_is_compatible),
|
DEFINE_MODULE_SYMBOL(driver_is_compatible),
|
||||||
DEFINE_MODULE_SYMBOL(driver_find_compatible),
|
DEFINE_MODULE_SYMBOL(driver_find_compatible),
|
||||||
DEFINE_MODULE_SYMBOL(driver_get_device_type),
|
DEFINE_MODULE_SYMBOL(driver_get_device_type),
|
||||||
// file system
|
|
||||||
DEFINE_MODULE_SYMBOL(file_system_mount),
|
|
||||||
DEFINE_MODULE_SYMBOL(file_system_unmount),
|
|
||||||
DEFINE_MODULE_SYMBOL(file_system_is_mounted),
|
|
||||||
DEFINE_MODULE_SYMBOL(file_system_get_mount_path),
|
|
||||||
// drivers/gpio_controller
|
// drivers/gpio_controller
|
||||||
DEFINE_MODULE_SYMBOL(gpio_descriptor_acquire),
|
DEFINE_MODULE_SYMBOL(gpio_descriptor_acquire),
|
||||||
DEFINE_MODULE_SYMBOL(gpio_descriptor_release),
|
DEFINE_MODULE_SYMBOL(gpio_descriptor_release),
|
||||||
@ -158,6 +153,11 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(timer_set_callback_priority),
|
DEFINE_MODULE_SYMBOL(timer_set_callback_priority),
|
||||||
// error
|
// error
|
||||||
DEFINE_MODULE_SYMBOL(error_to_string),
|
DEFINE_MODULE_SYMBOL(error_to_string),
|
||||||
|
// file system
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_mount),
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_unmount),
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_is_mounted),
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_get_path),
|
||||||
// log
|
// log
|
||||||
#ifndef ESP_PLATFORM
|
#ifndef ESP_PLATFORM
|
||||||
DEFINE_MODULE_SYMBOL(log_generic),
|
DEFINE_MODULE_SYMBOL(log_generic),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user