mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-08-20 17:05:06 +00:00
Fixes and improvements (#617)
This commit is contained in:
parent
b03759a111
commit
0ff1627385
@ -1,7 +1,7 @@
|
||||
# Increase stack size for Wi-Fi (fixes crash after scan)
|
||||
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3072
|
||||
# Ensure large enough stack for network operations
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096
|
||||
# Ensure large enough stack for network operations (e.g. AppHub)
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
|
||||
# Fixes static assertion: FLASH and PSRAM Mode configuration are not supported
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
# Free up IRAM
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
## Higher Priority
|
||||
|
||||
- AppEventSubscription, SystemEventSubscription: should use TaskHandle_t notification. That way, there can be a single wait event for a task instead of X separate ones with each their timeout.
|
||||
- AppHubApp: Prevent download callbacks from accessing a destroyed view.
|
||||
- Move USB host task stacks to SPIRAM when available: esp32_usbhost*.cpp
|
||||
- wifi: wifi_add_event_callback() and wifi_remove_event_callback() should be replaced by a subscribe/await pattern like system events.
|
||||
@ -46,14 +47,11 @@
|
||||
|
||||
## Medium Priority
|
||||
|
||||
- `platform-esp32`'s module drivers are declared in start/stop of the module but they should be set via `Module::drivers`
|
||||
- `struct Driver` has an `.owner`, but it's not always set. Either validate on Module construct that it matches, or otherwise set it during module start. The problem: NULL parent currently means that driver is not removable. This clashes with setting it dynamically. Consider some kind of flag to determine removability.
|
||||
- Consider moving certain drivers into separate modules: audio, bt, wifi, etc
|
||||
- Consider using https://github.com/Graphify-Labs/graphify
|
||||
- Consider implementing LVGL gridnav in apps https://lvgl.io/docs/open/9.3/details/auxiliary-modules/gridnav.html
|
||||
- Make USB host driver disabled by default, so it doesn't consume memory
|
||||
- Filtering for apps in App Hub:
|
||||
- apps that only work on a specific device
|
||||
- Diceware app has large "+" and "-' buttons on Cardputer. It should be smaller.
|
||||
- TactilityTool: Make API compatibility table (and check for compatibility in the tool itself)
|
||||
- Improve EspLcdDisplay to contain all the standard configuration options, and implement a default init function. Add a configuration class.
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include "instance.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@ -54,7 +56,7 @@ struct AppEvent {
|
||||
*/
|
||||
struct AppEventSubscription {
|
||||
/** The app instance this subscription receives events for; set by the caller before app_event_subscribe(). */
|
||||
uint32_t app_instance_id;
|
||||
AppInstanceId app_instance_id;
|
||||
|
||||
TaskHandle_t task;
|
||||
|
||||
@ -89,7 +91,7 @@ error_t app_event_unsubscribe(struct AppEventSubscription* sub);
|
||||
* @retval ERROR_RESOURCE at least one matching subscription's queue was full; the event was
|
||||
* dropped for that subscription (still delivered to any other matching subscription)
|
||||
*/
|
||||
error_t app_event_emit(uint32_t app_instance_id, const struct AppEvent* event);
|
||||
error_t app_event_emit(AppInstanceId app_instance_id, const struct AppEvent* event);
|
||||
|
||||
/**
|
||||
* Pop the next event for @a sub, blocking up to @a timeout if the queue is currently empty.
|
||||
|
||||
@ -152,6 +152,14 @@ error_t app_manager_install_path_add(const char* path);
|
||||
*/
|
||||
void app_manager_install_path_scan(void);
|
||||
|
||||
/**
|
||||
* Uninstalls an app that was registered via app_manager_install_path_scan() (i.e. discovered on
|
||||
* disk, not installed via app_install()). Stops running instances, removes the manifest
|
||||
* registration, and deletes the app directory. Returns ERROR_NOT_FOUND if the app id is not in
|
||||
* the scan registry.
|
||||
*/
|
||||
error_t app_manager_install_path_uninstall(const char* app_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -12,6 +12,11 @@
|
||||
#include <dirent.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <sys/unistd.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
inline bool app_fs_is_directory(const std::string& path) {
|
||||
@ -36,6 +41,87 @@ inline bool app_fs_is_file(const std::string& path) {
|
||||
|
||||
// Appends the full path of every direct subdirectory of @a path to @a out.
|
||||
// No-op (not an error) if @a path can't be opened.
|
||||
inline bool app_fs_delete_recursively(const std::string& path) {
|
||||
if (path.empty() || path == "/" || path == "." || path == "..") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use lstat() so symbolic links are not followed: a symlink that points at
|
||||
// an external directory must be removed as a leaf entry (unlink), not
|
||||
// recursed into. app_fs_is_directory() uses stat() and would follow the
|
||||
// link, potentially deleting files outside the target tree.
|
||||
// ESP-IDF newlib has no lstat(); ESP32 filesystems (FAT/SPIFFS) don't
|
||||
// support symlinks, so stat() is equivalent there.
|
||||
struct stat st {};
|
||||
FileMutex file_mutex;
|
||||
file_mutex_get(&file_mutex, path.c_str());
|
||||
file_mutex_lock(&file_mutex);
|
||||
#ifdef ESP_PLATFORM
|
||||
int rc = stat(path.c_str(), &st);
|
||||
#else
|
||||
int rc = lstat(path.c_str(), &st);
|
||||
#endif
|
||||
file_mutex_unlock(&file_mutex);
|
||||
|
||||
if (rc != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
// Symlink — remove as a leaf regardless of its target.
|
||||
file_mutex_lock(&file_mutex);
|
||||
bool result = unlink(path.c_str()) == 0;
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
// Collect child names while locked, then release before recursing —
|
||||
// child paths can resolve to the same mount mutex (see
|
||||
// app_fs_list_direct_subdirectories comment), so holding the parent
|
||||
// lock across the recursive call would self-deadlock.
|
||||
std::vector<std::string> children;
|
||||
|
||||
file_mutex_lock(&file_mutex);
|
||||
DIR* dir = opendir(path.c_str());
|
||||
if (dir == nullptr) {
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != nullptr) {
|
||||
if (std::strcmp(entry->d_name, ".") == 0 || std::strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
children.push_back(path + "/" + entry->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
file_mutex_unlock(&file_mutex);
|
||||
|
||||
bool success = true;
|
||||
for (const auto& child : children) {
|
||||
success = app_fs_delete_recursively(child);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
file_mutex_lock(&file_mutex);
|
||||
bool result = rmdir(path.c_str()) == 0;
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Regular file or other — unlink.
|
||||
file_mutex_lock(&file_mutex);
|
||||
bool result = unlink(path.c_str()) == 0;
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void app_fs_list_direct_subdirectories(const std::string& path, std::vector<std::string>& out) {
|
||||
// Collect child names while the directory lock is held, then release it before classifying
|
||||
// each one with app_fs_is_directory() - that function looks up and locks a FileMutex too,
|
||||
|
||||
@ -66,62 +66,13 @@ bool ensure_directory_recursive(const std::string& path) {
|
||||
}
|
||||
|
||||
bool delete_recursively(const std::string& path) {
|
||||
LOG_D(TAG, "Deleting %s...", path.c_str());
|
||||
if (path.empty() || path == "/" || path == "." || path == "..") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (app_fs_is_directory(path)) {
|
||||
LOG_D(TAG, "Deleting dir %s", path.c_str());
|
||||
|
||||
FileMutex file_mutex;
|
||||
file_mutex_get(&file_mutex, path.c_str());
|
||||
file_mutex_lock(&file_mutex);
|
||||
|
||||
DIR* dir = opendir(path.c_str());
|
||||
if (dir == nullptr) {
|
||||
LOG_E(TAG, "Failed to scan directory %s", path.c_str());
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
dirent* entry;
|
||||
while (success && (entry = readdir(dir)) != nullptr) {
|
||||
if (std::strcmp(entry->d_name, ".") == 0 || std::strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
success = delete_recursively(path + "/" + entry->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (!success) {
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = rmdir(path.c_str()) == 0;
|
||||
file_mutex_unlock(&file_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (app_fs_is_file(path)) {
|
||||
LOG_D(TAG, "Deleting file %s", path.c_str());
|
||||
FileMutex mutex {};
|
||||
file_mutex_get(&mutex, path.c_str());
|
||||
file_mutex_lock(&mutex);
|
||||
bool result = remove(path.c_str()) == 0;
|
||||
file_mutex_unlock(&mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
LOG_D(TAG, "Deleting done");
|
||||
return true;
|
||||
LOG_I(TAG, "Deleting %s...", path.c_str());
|
||||
return app_fs_delete_recursively(path);
|
||||
}
|
||||
|
||||
bool get_app_install_directory(std::string& out_path) {
|
||||
char root[192];
|
||||
if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
if (paths_get_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
out_path = std::string(root) + "/app";
|
||||
@ -277,6 +228,11 @@ error_t uninstall_locked(const std::string& app_id) {
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Can't uninstall in-memory apps
|
||||
if (iterator->second->manifest.location.type != APP_LOCATION_PATH) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
stop_all_instances_of(&iterator->second->manifest);
|
||||
app_manager_remove(app_id.c_str());
|
||||
delete_recursively(iterator->second->path);
|
||||
@ -404,10 +360,20 @@ error_t app_uninstall(const char* app_id) {
|
||||
|
||||
auto& registry = install_registry();
|
||||
mutex_lock(®istry.mutex);
|
||||
error_t result = uninstall_locked(app_id);
|
||||
error_t error = uninstall_locked(app_id);
|
||||
mutex_unlock(®istry.mutex);
|
||||
|
||||
return result;
|
||||
if (error == ERROR_NOT_FOUND) {
|
||||
error = app_manager_install_path_uninstall(app_id);
|
||||
}
|
||||
|
||||
if (error == ERROR_NONE) {
|
||||
LOG_I(TAG, "Uninstalled %s", app_id);
|
||||
} else {
|
||||
LOG_I(TAG, "Uninstalling %s failed: %s", app_id, error_to_string(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <app/location.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/paths.h>
|
||||
#include <tactility/paths.h>
|
||||
|
||||
@ -9,7 +11,7 @@ extern "C" {
|
||||
|
||||
error_t app_paths_get_user_data_directory(const char* app_id, char* out_path, size_t out_path_size) {
|
||||
char root[192];
|
||||
error_t error = paths_get_user_data_path(root, sizeof(root));
|
||||
error_t error = paths_get_data_path(root, sizeof(root));
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
@ -34,12 +36,17 @@ error_t app_paths_get_user_data_path(const char* app_id, const char* child_path,
|
||||
}
|
||||
|
||||
error_t app_paths_get_assets_directory(const char* app_id, char* out_path, size_t out_path_size) {
|
||||
char directory[224];
|
||||
error_t error = app_paths_get_user_data_directory(app_id, directory, sizeof(directory));
|
||||
AppManifest manifest;
|
||||
error_t error = app_manager_find_manifest(app_id, &manifest);
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
int written = std::snprintf(out_path, out_path_size, "%s/assets", directory);
|
||||
|
||||
if (manifest.location.type != APP_LOCATION_PATH) {
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int written = std::snprintf(out_path, out_path_size, "%s/assets", static_cast<const char*>(manifest.location.location));
|
||||
if (written < 0 || (size_t)written >= out_path_size) {
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ error_t app_event_unsubscribe(AppEventSubscription* sub) {
|
||||
return result;
|
||||
}
|
||||
|
||||
error_t app_event_emit(uint32_t app_instance_id, const AppEvent* event) {
|
||||
error_t app_event_emit(AppInstanceId app_instance_id, const AppEvent* event) {
|
||||
AppEvent stamped_event = *event;
|
||||
stamped_event.timestamp = get_micros_since_boot();
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <app/manager.h>
|
||||
|
||||
#include <app/metadata.h>
|
||||
|
||||
#include <app/private/app_fs.h>
|
||||
#include <app/private/app_ledger.h>
|
||||
#include <app/private/app_scheduler.h>
|
||||
|
||||
#include <tactility/concurrent/mutex.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <algorithm>
|
||||
@ -340,4 +339,55 @@ void app_manager_install_path_scan(void) {
|
||||
mutex_unlock(®istry.mutex);
|
||||
}
|
||||
|
||||
error_t app_manager_install_path_uninstall(const char* app_id) {
|
||||
auto& registry = install_path_registry();
|
||||
|
||||
mutex_lock(®istry.mutex);
|
||||
auto iterator = registry.scanned.find(app_id);
|
||||
if (iterator == registry.scanned.end()) {
|
||||
mutex_unlock(®istry.mutex);
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
const AppManifest* manifest = &iterator->second->manifest;
|
||||
auto path = iterator->second->path;
|
||||
mutex_unlock(®istry.mutex);
|
||||
|
||||
// Stop every running instance that retains this manifest pointer, mirroring
|
||||
// stop_all_instances_of() in app_install.cpp. Collect under ledger.mutex,
|
||||
// then call app_manager_stop() outside it (that call bound-joins the
|
||||
// instance's thread, which itself takes ledger.mutex in its thread_main).
|
||||
std::vector<uint32_t> instance_ids;
|
||||
auto& ledger = app_ledger();
|
||||
mutex_lock(&ledger.mutex);
|
||||
for (const auto& [id, record] : ledger.instances) {
|
||||
if (record.manifest == manifest) {
|
||||
instance_ids.push_back(id);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ledger.mutex);
|
||||
|
||||
for (uint32_t id : instance_ids) {
|
||||
app_manager_stop(id);
|
||||
}
|
||||
|
||||
// app_manager_remove takes ledger.mutex internally - call outside both
|
||||
// registry.mutex and ledger.mutex to match the lock ordering in
|
||||
// app_manager_install_path_scan().
|
||||
app_manager_remove(app_id);
|
||||
|
||||
// Every instance has stopped and the manifest is unregistered — safe to
|
||||
// delete the on-disk directory. Delete before erasing the scan record so
|
||||
// that a failed deletion leaves the entry discoverable for a retry.
|
||||
if (!app_fs_delete_recursively(path)) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
mutex_lock(®istry.mutex);
|
||||
registry.scanned.erase(app_id);
|
||||
mutex_unlock(®istry.mutex);
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@ -40,6 +40,7 @@ const ModuleSymbol app_module_symbols[] = {
|
||||
DEFINE_MODULE_SYMBOL(app_manager_get_topmost_app_id),
|
||||
DEFINE_MODULE_SYMBOL(app_manager_install_path_add),
|
||||
DEFINE_MODULE_SYMBOL(app_manager_install_path_scan),
|
||||
DEFINE_MODULE_SYMBOL(app_manager_install_path_uninstall),
|
||||
// app/metadata
|
||||
DEFINE_MODULE_SYMBOL(app_metadata_parse),
|
||||
// app/paths
|
||||
|
||||
@ -9,7 +9,7 @@ extern "C" {
|
||||
|
||||
error_t service_paths_get_user_data_directory(const char* service_id, char* out_path, size_t out_path_size) {
|
||||
char root[192];
|
||||
error_t error = paths_get_user_data_path(root, sizeof(root));
|
||||
error_t error = paths_get_data_path(root, sizeof(root));
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -7,20 +7,20 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("paths_get_user_data_path returns a non-empty path") {
|
||||
TEST_CASE("paths_get_data_path returns a non-empty path") {
|
||||
char buffer[192];
|
||||
CHECK_EQ(paths_get_user_data_path(buffer, sizeof(buffer)), ERROR_NONE);
|
||||
REQUIRE_EQ(paths_get_data_path(buffer, sizeof(buffer)), ERROR_NONE);
|
||||
CHECK_GT(std::strlen(buffer), 0);
|
||||
}
|
||||
|
||||
TEST_CASE("paths_get_user_data_path reports overflow for a too-small buffer") {
|
||||
TEST_CASE("paths_get_data_path reports overflow for a too-small buffer") {
|
||||
char buffer[1];
|
||||
CHECK_EQ(paths_get_user_data_path(buffer, sizeof(buffer)), ERROR_BUFFER_OVERFLOW);
|
||||
CHECK_EQ(paths_get_data_path(buffer, sizeof(buffer)), ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
TEST_CASE("service_paths_get_user_data_directory includes the service id") {
|
||||
char root[192];
|
||||
REQUIRE_EQ(paths_get_user_data_path(root, sizeof(root)), ERROR_NONE);
|
||||
REQUIRE_EQ(paths_get_data_path(root, sizeof(root)), ERROR_NONE);
|
||||
|
||||
char buffer[224];
|
||||
CHECK_EQ(service_paths_get_user_data_directory("my-service", buffer, sizeof(buffer)), ERROR_NONE);
|
||||
|
||||
@ -2,9 +2,6 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
#include <soc/soc_caps.h>
|
||||
@ -60,122 +57,61 @@ extern Driver esp32_usb_midi_device_driver;
|
||||
extern Driver esp32_usb_cdc_device_driver;
|
||||
#endif
|
||||
|
||||
static error_t start() {
|
||||
/* We crash when construct fails, because if a single driver fails to construct,
|
||||
* there is no guarantee that the previously constructed drivers can be destroyed */
|
||||
check(driver_construct_add(&esp32_adc_oneshot_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_gpio_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2c_master_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
||||
static Driver* const platform_esp32_drivers[] = {
|
||||
&esp32_adc_oneshot_driver,
|
||||
&esp32_gpio_driver,
|
||||
&esp32_i2c_driver,
|
||||
&esp32_i2c_master_driver,
|
||||
&esp32_i2s_driver,
|
||||
#if SOC_LCD_I80_SUPPORTED
|
||||
check(driver_construct_add(&esp32_i8080_driver) == ERROR_NONE);
|
||||
&esp32_i8080_driver,
|
||||
#endif
|
||||
check(driver_construct_add(&esp32_pwm_ledc_driver) == ERROR_NONE);
|
||||
&esp32_pwm_ledc_driver,
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
&esp32_sdmmc_driver,
|
||||
#endif
|
||||
check(driver_construct_add(&esp32_sdspi_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_grove_driver) == ERROR_NONE);
|
||||
&esp32_sdspi_driver,
|
||||
&esp32_spi_driver,
|
||||
&esp32_uart_driver,
|
||||
&esp32_grove_driver,
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
check(driver_construct_add(&esp32_wifi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_wifi_pinned_driver) == ERROR_NONE);
|
||||
&esp32_wifi_driver,
|
||||
&esp32_wifi_pinned_driver,
|
||||
#endif
|
||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
check(driver_construct_add(&esp32_bluetooth_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_ble_serial_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_ble_midi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_ble_hid_device_driver) == ERROR_NONE);
|
||||
&esp32_bluetooth_driver,
|
||||
&esp32_ble_serial_driver,
|
||||
&esp32_ble_midi_driver,
|
||||
&esp32_ble_hid_device_driver,
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
check(driver_construct_add(&esp32_usbhost_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_hid_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_hid_keyboard_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_midi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_msc_driver) == ERROR_NONE);
|
||||
#endif
|
||||
// usbdevice0 and its children (usbdevicehid0, usbdevicemsc0, ...) are declared per-board in
|
||||
// .dts, same pattern as usbhost0 above - the devicetree compiler constructs/adds/starts their
|
||||
// Device instances and wires parent/child relationships. Only driver registration happens
|
||||
// here.
|
||||
#if SOC_USB_OTG_SUPPORTED && (CONFIG_TINYUSB_HID_COUNT || CONFIG_TINYUSB_MSC_ENABLED || CONFIG_TINYUSB_MIDI_COUNT || CONFIG_TINYUSB_CDC_ENABLED)
|
||||
check(driver_construct_add(&esp32_usb_device_controller_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_HID_COUNT
|
||||
check(driver_construct_add(&esp32_usb_hid_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_MSC_ENABLED
|
||||
check(driver_construct_add(&esp32_usb_msc_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_MIDI_COUNT
|
||||
check(driver_construct_add(&esp32_usb_midi_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_CDC_ENABLED
|
||||
check(driver_construct_add(&esp32_usb_cdc_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop() {
|
||||
/* We crash when destruct fails, because if a single driver fails to destruct,
|
||||
* there is no guarantee that the previously destroyed drivers can be recovered */
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
check(driver_remove_destruct(&esp32_wifi_pinned_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_wifi_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_CDC_ENABLED
|
||||
check(driver_remove_destruct(&esp32_usb_cdc_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_MIDI_COUNT
|
||||
check(driver_remove_destruct(&esp32_usb_midi_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_MSC_ENABLED
|
||||
check(driver_remove_destruct(&esp32_usb_msc_device_driver) == ERROR_NONE);
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_HID_COUNT
|
||||
check(driver_remove_destruct(&esp32_usb_hid_device_driver) == ERROR_NONE);
|
||||
&esp32_usbhost_driver,
|
||||
&esp32_usbhost_hid_driver,
|
||||
&esp32_usbhost_hid_keyboard_driver,
|
||||
&esp32_usbhost_midi_driver,
|
||||
&esp32_usbhost_msc_driver,
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED && (CONFIG_TINYUSB_HID_COUNT || CONFIG_TINYUSB_MSC_ENABLED || CONFIG_TINYUSB_MIDI_COUNT || CONFIG_TINYUSB_CDC_ENABLED)
|
||||
check(driver_remove_destruct(&esp32_usb_device_controller_driver) == ERROR_NONE);
|
||||
&esp32_usb_device_controller_driver,
|
||||
#endif
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_usbhost_msc_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_midi_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_hid_keyboard_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_hid_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_driver) == ERROR_NONE);
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_HID_COUNT
|
||||
&esp32_usb_hid_device_driver,
|
||||
#endif
|
||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
check(driver_remove_destruct(&esp32_ble_hid_device_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_ble_midi_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_ble_serial_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_bluetooth_driver) == ERROR_NONE);
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_MSC_ENABLED
|
||||
&esp32_usb_msc_device_driver,
|
||||
#endif
|
||||
check(driver_remove_destruct(&esp32_adc_oneshot_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_gpio_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2c_master_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
||||
#if SOC_LCD_I80_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_i8080_driver) == ERROR_NONE);
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_MIDI_COUNT
|
||||
&esp32_usb_midi_device_driver,
|
||||
#endif
|
||||
check(driver_remove_destruct(&esp32_pwm_ledc_driver) == ERROR_NONE);
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
#if SOC_USB_OTG_SUPPORTED && CONFIG_TINYUSB_CDC_ENABLED
|
||||
&esp32_usb_cdc_device_driver,
|
||||
#endif
|
||||
check(driver_remove_destruct(&esp32_sdspi_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_grove_driver) == ERROR_NONE);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
nullptr
|
||||
};
|
||||
|
||||
Module platform_esp32_module = {
|
||||
.name = "platform-esp32",
|
||||
.start = start,
|
||||
.stop = stop,
|
||||
.drivers = platform_esp32_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
@ -1,26 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver posix_wifi_driver;
|
||||
|
||||
static error_t start() {
|
||||
check(driver_construct_add(&posix_wifi_driver) == ERROR_NONE);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop() {
|
||||
check(driver_remove_destruct(&posix_wifi_driver) == ERROR_NONE);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
static Driver* const platform_posix_drivers[] = {
|
||||
&posix_wifi_driver,
|
||||
nullptr
|
||||
};
|
||||
|
||||
struct Module platform_posix_module = {
|
||||
.name = "platform-posix",
|
||||
.start = start,
|
||||
.stop = stop,
|
||||
.drivers = platform_posix_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
@ -15,7 +15,7 @@ FileSystem* findSdcardFileSystem(bool mustBeMounted);
|
||||
|
||||
std::string getUserDataRootPath();
|
||||
|
||||
std::string getUserDataPath();
|
||||
std::string getDataPath();
|
||||
|
||||
std::string getTempPath();
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ std::string getUserDataRootPath() {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getUserDataPath() {
|
||||
std::string getDataPath() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return getUserDataRootPath() + "/tactility";
|
||||
#else
|
||||
@ -60,15 +60,15 @@ std::string getUserDataPath() {
|
||||
}
|
||||
|
||||
std::string getTempPath() {
|
||||
return getUserDataPath() + "/tmp";
|
||||
return getDataPath() + "/tmp";
|
||||
}
|
||||
|
||||
std::string getAppInstallPath() {
|
||||
return getUserDataPath() + "/app";
|
||||
return getDataPath() + "/app";
|
||||
}
|
||||
|
||||
std::string getUserHomePath() {
|
||||
return getUserDataPath() + "/user";
|
||||
return getDataPath() + "/user";
|
||||
}
|
||||
|
||||
std::string getAppInstallPath(const std::string& appId) {
|
||||
|
||||
@ -318,7 +318,7 @@ static void registerAndStartServices() {
|
||||
}
|
||||
|
||||
void createTempDirectory() {
|
||||
auto data_path = getUserDataPath();
|
||||
auto data_path = getDataPath();
|
||||
auto temp_path = std::format("{}/tmp", data_path);
|
||||
if (!file::isDirectory(temp_path)) {
|
||||
FileMutex mutex;
|
||||
|
||||
@ -152,27 +152,19 @@ void updateApp(Context* ctx) {
|
||||
void updateViews(Context* ctx) {
|
||||
lvgl_toolbar_clear_actions(ctx->toolbar);
|
||||
auto app_id = ctx->entry.appId.c_str();
|
||||
AppManifest manifest;
|
||||
bool is_installed = app_manager_find_manifest(app_id, &manifest) == ERROR_NONE;
|
||||
ctx->spinner = lvgl_toolbar_add_spinner_action(ctx->toolbar);
|
||||
lv_obj_add_flag(ctx->spinner, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(ctx->updateLabel, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
char install_path[128];
|
||||
if (app_get_install_path(app_id, install_path, sizeof(install_path)) != ERROR_NONE) {
|
||||
LOG_E(TAG, "Install path not found for %s", app_id);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string metadata_path = std::string(install_path) + "/manifest.properties";
|
||||
AppMetadata metadata;
|
||||
if (app_metadata_parse(metadata_path.c_str(), &metadata) != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to parse metadata at %s", metadata_path.c_str());
|
||||
return;
|
||||
}
|
||||
bool is_installed = app_get_install_path(app_id, install_path, sizeof(install_path)) == ERROR_NONE
|
||||
&& file::isFile(std::string(install_path) + "/manifest.properties");
|
||||
|
||||
if (is_installed) {
|
||||
if (metadata.app_version_code < ctx->entry.appVersionCode) {
|
||||
std::string metadata_path = std::string(install_path) + "/manifest.properties";
|
||||
AppMetadata metadata;
|
||||
if (app_metadata_parse(metadata_path.c_str(), &metadata) == ERROR_NONE
|
||||
&& metadata.app_version_code < ctx->entry.appVersionCode) {
|
||||
ctx->updateButton = lvgl_toolbar_add_image_button_action(ctx->toolbar, LV_SYMBOL_DOWNLOAD, onUpdatePressed, ctx);
|
||||
lv_obj_remove_flag(ctx->updateLabel, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
#include <Tactility/app/i2cscanner/I2cHelpers.h>
|
||||
#include <Tactility/app/i2cscanner/I2cScannerPrivate.h>
|
||||
|
||||
#include <Tactility/LogMessages.h>
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
#include <Tactility/Timer.h>
|
||||
#include <Tactility/app/i2cscanner/I2cHelpers.h>
|
||||
#include <Tactility/app/i2cscanner/I2cScannerPrivate.h>
|
||||
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/paths.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/paths.h>
|
||||
#include <tactility/preferences.h>
|
||||
|
||||
#include <cassert>
|
||||
@ -55,7 +56,7 @@ struct Context {
|
||||
|
||||
bool getPreferencesPath(std::string& outPath) {
|
||||
char root[128];
|
||||
if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
if (app_paths_get_user_data_directory(manifest.id, root, sizeof(root)) != ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
outPath = std::string(root) + "/i2c_scanner.properties";
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include <Tactility/app/setup/Setup.h>
|
||||
|
||||
#include <tactility/paths.h>
|
||||
|
||||
#include <Tactility/StringUtils.h>
|
||||
#include <Tactility/app/timezone/TimeZone.h>
|
||||
#include <Tactility/app/wifimanage/WifiManage.h>
|
||||
@ -13,7 +15,6 @@
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/paths.h>
|
||||
|
||||
#include <lvgl/fonts.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
@ -39,11 +40,11 @@ constexpr auto* TAG = "setup";
|
||||
namespace {
|
||||
|
||||
bool getCompletedMarkerPath(std::string& outPath) {
|
||||
char root[128];
|
||||
if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
char path[128];
|
||||
if (paths_get_data_path(path, sizeof(path)) != ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
outPath = std::string(root) + "/.setup_complete";
|
||||
outPath = std::string(path) + "/.setup_complete";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ constexpr auto* KEY_AUTO_CONNECT = "autoConnect";
|
||||
constexpr auto* KEY_PROFILE_ID = "profileId";
|
||||
|
||||
static std::string getSettingsFilePath() {
|
||||
return getUserDataPath() + "/service/bluetooth";
|
||||
return getDataPath() + "/service/bluetooth";
|
||||
}
|
||||
|
||||
std::string addrToHex(const std::array<uint8_t, 6>& addr) {
|
||||
|
||||
@ -11,7 +11,7 @@ namespace tt::bluetooth::settings {
|
||||
constexpr auto* TAG = "BluetoothSettings";
|
||||
|
||||
static std::string getSettingsPath() {
|
||||
return getUserDataPath() + "/settings/bluetooth.settings";
|
||||
return getDataPath() + "/settings/bluetooth.properties";
|
||||
}
|
||||
|
||||
constexpr auto* KEY_ENABLE_ON_BOOT = "enableOnBoot";
|
||||
|
||||
@ -3,12 +3,11 @@
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/paths.h>
|
||||
#include <tactility/preferences.h>
|
||||
#include <tactility/system_event.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <tactility/system_event.h>
|
||||
#include <esp_netif_sntp.h>
|
||||
#include <esp_sntp.h>
|
||||
#endif
|
||||
@ -23,10 +22,10 @@ static bool processedSyncEvent = false;
|
||||
|
||||
static bool getPreferencesPath(std::string& outPath) {
|
||||
char root[128];
|
||||
if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
if (paths_get_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
outPath = std::string(root) + "/time.properties";
|
||||
outPath = std::string(root) + "/settings/ntp.properties";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1450,7 +1450,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 = getUserDataPath();
|
||||
std::string save_path = getDataPath();
|
||||
|
||||
// Find next available filename with incrementing number
|
||||
std::string screenshot_path;
|
||||
|
||||
@ -126,7 +126,7 @@ void bootSplashInit() {
|
||||
getMainDispatcher().dispatch([] {
|
||||
LOG_I(TAG, "bootSplashInit dispatch begin");
|
||||
// Import any provisioning files placed on the system data partition.
|
||||
const std::string provisioning_path = file::getChildPath(getUserDataPath(), "provisioning");
|
||||
const std::string provisioning_path = file::getChildPath(getDataPath(), "provisioning");
|
||||
if (file::isDirectory(provisioning_path)) {
|
||||
importWifiApSettingsFromDir(provisioning_path);
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include <Tactility/settings/AudioSettings.h>
|
||||
|
||||
#include "tactility/paths.h"
|
||||
|
||||
#include <Tactility/DeprecatedPaths.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
@ -12,8 +14,14 @@
|
||||
|
||||
namespace tt::settings::audio {
|
||||
|
||||
static std::string getSettingsFilePath() {
|
||||
return getUserDataPath() + "/settings/audio.properties";
|
||||
static bool getSettingsFilePath(std::string& outPath) {
|
||||
char root[128];
|
||||
// Not really a service, but this is the best way of organising it for now
|
||||
if (paths_get_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
outPath = std::string(root) + "/settings/audio.properties";
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr auto* SETTINGS_KEY_INPUT_ENABLED = "inputEnabled";
|
||||
@ -56,7 +64,11 @@ static std::string toString(float value) {
|
||||
}
|
||||
|
||||
bool load(AudioSettings& settings) {
|
||||
auto settings_path = getSettingsFilePath();
|
||||
std::string settings_path;
|
||||
if (!getSettingsFilePath(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file::isFile(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
@ -103,10 +115,16 @@ bool save(const AudioSettings& settings) {
|
||||
map[SETTINGS_KEY_OUTPUT_MUTED] = toString(settings.outputMuted);
|
||||
map[SETTINGS_KEY_INPUT_VOLUME] = toString(settings.inputVolume);
|
||||
map[SETTINGS_KEY_OUTPUT_VOLUME] = toString(settings.outputVolume);
|
||||
auto settings_path = getSettingsFilePath();
|
||||
|
||||
std::string settings_path;
|
||||
if (getSettingsFilePath(settings_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return file::savePropertiesFile(settings_path, map);
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId";
|
||||
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
||||
|
||||
static std::string getPropertiesFilePath() {
|
||||
return std::format(PROPERTIES_FILE_FORMAT, getUserDataPath());
|
||||
return std::format(PROPERTIES_FILE_FORMAT, getDataPath());
|
||||
}
|
||||
|
||||
bool loadBootSettings(BootSettings& properties) {
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
namespace tt::settings::keyboard {
|
||||
|
||||
static std::string getSettingsFilePath() {
|
||||
return getUserDataPath() + "/settings/keyboard.properties";
|
||||
return getDataPath() + "/settings/keyboard.properties";
|
||||
}
|
||||
|
||||
constexpr auto* KEY_BACKLIGHT_ENABLED = "backlightEnabled";
|
||||
|
||||
@ -21,12 +21,12 @@ static bool cached = false;
|
||||
static SystemSettings cachedSettings;
|
||||
|
||||
static bool hasSystemSettingsFile() {
|
||||
auto file_path = std::format(FILE_PATH_FORMAT, getUserDataPath());
|
||||
auto file_path = std::format(FILE_PATH_FORMAT, getDataPath());
|
||||
return file::isFile(file_path);
|
||||
}
|
||||
|
||||
static bool loadSystemSettingsFromFile(SystemSettings& properties) {
|
||||
auto file_path = std::format(FILE_PATH_FORMAT, getUserDataPath());
|
||||
auto file_path = std::format(FILE_PATH_FORMAT, getDataPath());
|
||||
LOG_I(TAG, "System settings loading from %s", file_path.c_str());
|
||||
std::map<std::string, std::string> map;
|
||||
if (!file::loadPropertiesFile(file_path, map)) {
|
||||
@ -75,7 +75,7 @@ bool loadSystemSettings(SystemSettings& properties) {
|
||||
}
|
||||
|
||||
bool saveSystemSettings(const SystemSettings& properties) {
|
||||
auto file_path = std::format(FILE_PATH_FORMAT, getUserDataPath());
|
||||
auto file_path = std::format(FILE_PATH_FORMAT, getDataPath());
|
||||
std::map<std::string, std::string> map;
|
||||
map["language"] = toString(properties.language);
|
||||
map["timeFormat24h"] = properties.timeFormat24h ? "true" : "false";
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
namespace tt::settings::touch {
|
||||
|
||||
static std::string getSettingsFilePath() {
|
||||
return getUserDataPath() + "/settings/touch-calibration.properties";
|
||||
return getDataPath() + "/settings/touch-calibration.properties";
|
||||
}
|
||||
|
||||
constexpr auto* SETTINGS_KEY_ENABLED = "enabled";
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include <Tactility/settings/Time.h>
|
||||
#include <service/paths.h>
|
||||
|
||||
#include <Tactility/settings/Time.h>
|
||||
#include <Tactility/settings/SystemSettings.h>
|
||||
|
||||
#include <tactility/paths.h>
|
||||
@ -12,8 +13,6 @@
|
||||
|
||||
namespace tt::settings {
|
||||
|
||||
constexpr auto* TIME_SETTINGS_NAMESPACE = "time";
|
||||
|
||||
constexpr auto* TIMEZONE_PREFERENCES_KEY_NAME = "tz_name";
|
||||
constexpr auto* TIMEZONE_PREFERENCES_KEY_CODE = "tz_code";
|
||||
constexpr auto* TIMEZONE_PREFERENCES_KEY_TIME24 = "tz_time24";
|
||||
@ -24,10 +23,11 @@ namespace {
|
||||
// "syncTime" - matches the shared NVS namespace this used to be.
|
||||
bool getPreferencesPath(std::string& outPath) {
|
||||
char root[128];
|
||||
if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
// Not really a service, but this is the best way of organising it for now
|
||||
if (paths_get_data_path(root, sizeof(root)) != ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
outPath = std::string(root) + "/" + TIME_SETTINGS_NAMESPACE + ".properties";
|
||||
outPath = std::string(root) + "/settings/time.properties";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define TT_TIMEZONE_NAME_BUFFER_LENGTH 32
|
||||
#define TT_TIMEZONE_CODE_BUFFER_LENGTH 48
|
||||
|
||||
/**
|
||||
* Set the timezone
|
||||
* @param[in] name human-readable name
|
||||
* @param[in] code the technical code (from timezones.csv)
|
||||
*/
|
||||
void tt_timezone_set(const char* name, const char* code);
|
||||
|
||||
/**
|
||||
* Get the name of the timezone
|
||||
* @param[out] buffer the output buffer which will include a null terminator (should be TT_TIMEZONE_NAME_BUFFER_LENGTH)
|
||||
* @param[in] bufferSize the size of the output buffer
|
||||
*/
|
||||
bool tt_timezone_get_name(char* buffer, size_t bufferSize);
|
||||
|
||||
/**
|
||||
* Get the code of the timezone (see timezones.csv)
|
||||
*/
|
||||
bool tt_timezone_get_code(char* buffer, size_t bufferSize);
|
||||
|
||||
/** @return true when clocks should be shown as a 24 hours one instead of 12 hours */
|
||||
bool tt_timezone_is_format_24_hour();
|
||||
|
||||
/** Set whether clocks should be shown as a 24 hours instead of 12 hours
|
||||
* @param[in] show24Hour
|
||||
*/
|
||||
void tt_timezone_set_format_24_hour(bool show24Hour);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -3,7 +3,6 @@
|
||||
#include "tt_app_alertdialog.h"
|
||||
#include "tt_app_fileselection.h"
|
||||
#include "tt_app_selectiondialog.h"
|
||||
#include "tt_time.h"
|
||||
|
||||
#include "symbols/cplusplus.h"
|
||||
#include "symbols/esp_event.h"
|
||||
@ -276,11 +275,6 @@ const esp_elfsym main_symbols[] {
|
||||
ESP_ELFSYM_EXPORT(tt_app_fileselection_get_result_path),
|
||||
ESP_ELFSYM_EXPORT(tt_app_selectiondialog_start),
|
||||
ESP_ELFSYM_EXPORT(tt_app_alertdialog_start),
|
||||
ESP_ELFSYM_EXPORT(tt_timezone_set),
|
||||
ESP_ELFSYM_EXPORT(tt_timezone_get_name),
|
||||
ESP_ELFSYM_EXPORT(tt_timezone_get_code),
|
||||
ESP_ELFSYM_EXPORT(tt_timezone_is_format_24_hour),
|
||||
ESP_ELFSYM_EXPORT(tt_timezone_set_format_24_hour),
|
||||
|
||||
// stdio.h
|
||||
ESP_ELFSYM_EXPORT(rename),
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
#include "tt_time.h"
|
||||
|
||||
#include <Tactility/settings/Time.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
extern "C" {
|
||||
|
||||
void tt_timezone_set(const char* name, const char* code) {
|
||||
settings::setTimeZone(name, code);
|
||||
}
|
||||
|
||||
bool tt_timezone_get_name(char* buffer, size_t bufferSize) {
|
||||
auto name = settings::getTimeZoneName();
|
||||
if (bufferSize < (name.length() + 1)) {
|
||||
return false;
|
||||
} else {
|
||||
strcpy(buffer, name.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool tt_timezone_get_code(char* buffer, size_t bufferSize) {
|
||||
auto code = settings::getTimeZoneCode();
|
||||
if (bufferSize < (code.length() + 1)) {
|
||||
return false;
|
||||
} else {
|
||||
strcpy(buffer, code.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool tt_timezone_is_format_24_hour() {
|
||||
return settings::isTimeFormat24Hour();
|
||||
}
|
||||
|
||||
void tt_timezone_set_format_24_hour(bool show24Hour) {
|
||||
return settings::setTimeFormat24Hour(show24Hour);
|
||||
}
|
||||
|
||||
}
|
||||
@ -17,7 +17,7 @@ extern "C" {
|
||||
* @retval ERROR_BUFFER_OVERFLOW if out_path_size is too small
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t paths_get_user_data_path(char* out_path, size_t out_path_size);
|
||||
error_t paths_get_data_path(char* out_path, size_t out_path_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
static error_t paths_get_user_data_root_path(char* out_path, size_t out_path_size) {
|
||||
static error_t paths_get_data_root_path(char* out_path, size_t out_path_size) {
|
||||
#if defined(CONFIG_TT_USER_DATA_LOCATION_INTERNAL)
|
||||
#ifdef ESP_PLATFORM
|
||||
const char* mount_point = "/data";
|
||||
@ -41,10 +41,10 @@ static error_t paths_get_user_data_root_path(char* out_path, size_t out_path_siz
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t paths_get_user_data_path(char* out_path, size_t out_path_size) {
|
||||
error_t paths_get_data_path(char* out_path, size_t out_path_size) {
|
||||
#ifdef ESP_PLATFORM
|
||||
char root[64];
|
||||
error_t error = paths_get_user_data_root_path(root, sizeof(root));
|
||||
error_t error = paths_get_data_root_path(root, sizeof(root));
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -249,7 +249,7 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
||||
DEFINE_MODULE_SYMBOL(keyboard_read_key),
|
||||
DEFINE_MODULE_SYMBOL(KEYBOARD_TYPE),
|
||||
// drivers/paths
|
||||
DEFINE_MODULE_SYMBOL(paths_get_user_data_path),
|
||||
DEFINE_MODULE_SYMBOL(paths_get_data_path),
|
||||
// drivers/pointer
|
||||
DEFINE_MODULE_SYMBOL(pointer_enter_sleep),
|
||||
DEFINE_MODULE_SYMBOL(pointer_exit_sleep),
|
||||
|
||||
@ -4,28 +4,28 @@
|
||||
|
||||
#include <tactility/paths.h>
|
||||
|
||||
// The simulator target is never built with ESP_PLATFORM, so paths_get_user_data_path()
|
||||
// The simulator target is never built with ESP_PLATFORM, so paths_get_data_path()
|
||||
// always takes the fixed "data" path branch here, guarded by a buffer-size check.
|
||||
|
||||
TEST_CASE("paths_get_user_data_path succeeds when the buffer exactly fits") {
|
||||
TEST_CASE("paths_get_data_path succeeds when the buffer exactly fits") {
|
||||
char buffer[16] = { 0 };
|
||||
CHECK_EQ(paths_get_user_data_path(buffer, sizeof(buffer)), ERROR_NONE);
|
||||
CHECK_EQ(paths_get_data_path(buffer, sizeof(buffer)), ERROR_NONE);
|
||||
CHECK_EQ(std::strcmp(buffer, "data"), 0);
|
||||
}
|
||||
|
||||
TEST_CASE("paths_get_user_data_path succeeds with a buffer sized to exactly fit the string and terminator") {
|
||||
TEST_CASE("paths_get_data_path succeeds with a buffer sized to exactly fit the string and terminator") {
|
||||
char buffer[5] = { 0 }; // strlen("data") + 1
|
||||
CHECK_EQ(paths_get_user_data_path(buffer, sizeof(buffer)), ERROR_NONE);
|
||||
CHECK_EQ(paths_get_data_path(buffer, sizeof(buffer)), ERROR_NONE);
|
||||
CHECK_EQ(std::strcmp(buffer, "data"), 0);
|
||||
}
|
||||
|
||||
TEST_CASE("paths_get_user_data_path reports a buffer overflow when the buffer is one byte too small") {
|
||||
TEST_CASE("paths_get_data_path reports a buffer overflow when the buffer is one byte too small") {
|
||||
char buffer[4] = { 0 }; // strlen("data"), no room for the terminator
|
||||
CHECK_EQ(paths_get_user_data_path(buffer, sizeof(buffer)), ERROR_BUFFER_OVERFLOW);
|
||||
CHECK_EQ(paths_get_data_path(buffer, sizeof(buffer)), ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
TEST_CASE("paths_get_user_data_path reports a buffer overflow for a zero-size buffer") {
|
||||
TEST_CASE("paths_get_data_path reports a buffer overflow for a zero-size buffer") {
|
||||
char buffer[1] = { 'x' };
|
||||
CHECK_EQ(paths_get_user_data_path(buffer, 0), ERROR_BUFFER_OVERFLOW);
|
||||
CHECK_EQ(paths_get_data_path(buffer, 0), ERROR_BUFFER_OVERFLOW);
|
||||
CHECK_EQ(buffer[0], 'x'); // untouched
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user