mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
Merge branch 'flipperdevices:dev' into nestednonces
This commit is contained in:
51
applications/debug/unit_tests/tests/furi/furi_errno_test.c
Normal file
51
applications/debug/unit_tests/tests/furi/furi_errno_test.c
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "../test.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#define TAG "ErrnoTest"
|
||||||
|
#define THREAD_CNT 16
|
||||||
|
#define ITER_CNT 1000
|
||||||
|
|
||||||
|
static int32_t errno_fuzzer(void* context) {
|
||||||
|
int start_value = (int)context;
|
||||||
|
int32_t fails = 0;
|
||||||
|
|
||||||
|
for(int i = start_value; i < start_value + ITER_CNT; i++) {
|
||||||
|
errno = i;
|
||||||
|
furi_thread_yield();
|
||||||
|
if(errno != i) fails++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < ITER_CNT; i++) {
|
||||||
|
errno = 0;
|
||||||
|
furi_thread_yield();
|
||||||
|
UNUSED(strtol("123456", NULL, 10)); // -V530
|
||||||
|
furi_thread_yield();
|
||||||
|
if(errno != 0) fails++;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
furi_thread_yield();
|
||||||
|
UNUSED(strtol("123456123456123456123456123456123456123456123456", NULL, 10)); // -V530
|
||||||
|
furi_thread_yield();
|
||||||
|
if(errno != ERANGE) fails++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fails;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_errno_saving(void) {
|
||||||
|
FuriThread* threads[THREAD_CNT];
|
||||||
|
|
||||||
|
for(int i = 0; i < THREAD_CNT; i++) {
|
||||||
|
int start_value = i * ITER_CNT;
|
||||||
|
threads[i] = furi_thread_alloc_ex("ErrnoFuzzer", 1024, errno_fuzzer, (void*)start_value);
|
||||||
|
furi_thread_set_priority(threads[i], FuriThreadPriorityNormal);
|
||||||
|
furi_thread_start(threads[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < THREAD_CNT; i++) {
|
||||||
|
furi_thread_join(threads[i]);
|
||||||
|
mu_assert_int_eq(0, furi_thread_get_return_code(threads[i]));
|
||||||
|
furi_thread_free(threads[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ void test_furi_concurrent_access(void);
|
|||||||
void test_furi_pubsub(void);
|
void test_furi_pubsub(void);
|
||||||
void test_furi_memmgr(void);
|
void test_furi_memmgr(void);
|
||||||
void test_furi_event_loop(void);
|
void test_furi_event_loop(void);
|
||||||
|
void test_errno_saving(void);
|
||||||
|
|
||||||
static int foo = 0;
|
static int foo = 0;
|
||||||
|
|
||||||
@@ -42,6 +43,10 @@ MU_TEST(mu_test_furi_event_loop) {
|
|||||||
test_furi_event_loop();
|
test_furi_event_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(mu_test_errno_saving) {
|
||||||
|
test_errno_saving();
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST_SUITE(test_suite) {
|
MU_TEST_SUITE(test_suite) {
|
||||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
MU_RUN_TEST(test_check);
|
MU_RUN_TEST(test_check);
|
||||||
@@ -51,6 +56,7 @@ MU_TEST_SUITE(test_suite) {
|
|||||||
MU_RUN_TEST(mu_test_furi_pubsub);
|
MU_RUN_TEST(mu_test_furi_pubsub);
|
||||||
MU_RUN_TEST(mu_test_furi_memmgr);
|
MU_RUN_TEST(mu_test_furi_memmgr);
|
||||||
MU_RUN_TEST(mu_test_furi_event_loop);
|
MU_RUN_TEST(mu_test_furi_event_loop);
|
||||||
|
MU_RUN_TEST(mu_test_errno_saving);
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_minunit_test_furi(void) {
|
int run_minunit_test_furi(void) {
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
// This is a hack to access internal storage functions and definitions
|
// This is a hack to access internal storage functions and definitions
|
||||||
#include <storage/storage_i.h>
|
#include <storage/storage_i.h>
|
||||||
|
|
||||||
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
|
#define UNIT_TESTS_RESOURCES_PATH(path) EXT_PATH("unit_tests/" path)
|
||||||
|
#define UNIT_TESTS_PATH(path) EXT_PATH(".tmp/unit_tests/" path)
|
||||||
|
|
||||||
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
|
#define STORAGE_LOCKED_FILE UNIT_TESTS_PATH("locked_file.test")
|
||||||
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
|
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
|
||||||
|
|
||||||
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")
|
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")
|
||||||
@@ -369,33 +370,78 @@ MU_TEST(storage_file_rename) {
|
|||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
File* file = storage_file_alloc(storage);
|
File* file = storage_file_alloc(storage);
|
||||||
|
|
||||||
mu_check(write_file_13DA(storage, EXT_PATH("file.old")));
|
mu_check(write_file_13DA(storage, UNIT_TESTS_PATH("file.old")));
|
||||||
mu_check(check_file_13DA(storage, EXT_PATH("file.old")));
|
mu_check(check_file_13DA(storage, UNIT_TESTS_PATH("file.old")));
|
||||||
mu_assert_int_eq(
|
mu_assert_int_eq(
|
||||||
FSE_OK, storage_common_rename(storage, EXT_PATH("file.old"), EXT_PATH("file.new")));
|
FSE_OK,
|
||||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("file.old"), NULL));
|
storage_common_rename(storage, UNIT_TESTS_PATH("file.old"), UNIT_TESTS_PATH("file.new")));
|
||||||
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, EXT_PATH("file.new"), NULL));
|
mu_assert_int_eq(
|
||||||
mu_check(check_file_13DA(storage, EXT_PATH("file.new")));
|
FSE_NOT_EXIST, storage_common_stat(storage, UNIT_TESTS_PATH("file.old"), NULL));
|
||||||
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, EXT_PATH("file.new")));
|
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, UNIT_TESTS_PATH("file.new"), NULL));
|
||||||
|
mu_check(check_file_13DA(storage, UNIT_TESTS_PATH("file.new")));
|
||||||
|
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, UNIT_TESTS_PATH("file.new")));
|
||||||
|
|
||||||
storage_file_free(file);
|
storage_file_free(file);
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* dir_rename_tests[][2] = {
|
||||||
|
{UNIT_TESTS_PATH("dir.old"), UNIT_TESTS_PATH("dir.new")},
|
||||||
|
{UNIT_TESTS_PATH("test_dir"), UNIT_TESTS_PATH("test_dir-new")},
|
||||||
|
{UNIT_TESTS_PATH("test"), UNIT_TESTS_PATH("test-test")},
|
||||||
|
};
|
||||||
|
|
||||||
MU_TEST(storage_dir_rename) {
|
MU_TEST(storage_dir_rename) {
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
|
||||||
storage_dir_create(storage, EXT_PATH("dir.old"));
|
for(size_t i = 0; i < COUNT_OF(dir_rename_tests); i++) {
|
||||||
|
const char* old_path = dir_rename_tests[i][0];
|
||||||
|
const char* new_path = dir_rename_tests[i][1];
|
||||||
|
|
||||||
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.old")));
|
storage_dir_create(storage, old_path);
|
||||||
|
mu_check(storage_dir_rename_check(storage, old_path));
|
||||||
|
|
||||||
|
mu_assert_int_eq(FSE_OK, storage_common_rename(storage, old_path, new_path));
|
||||||
|
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, old_path, NULL));
|
||||||
|
mu_check(storage_dir_rename_check(storage, new_path));
|
||||||
|
|
||||||
|
storage_dir_remove(storage, new_path);
|
||||||
|
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, new_path, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(storage_equiv_and_subdir) {
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
|
||||||
mu_assert_int_eq(
|
mu_assert_int_eq(
|
||||||
FSE_OK, storage_common_rename(storage, EXT_PATH("dir.old"), EXT_PATH("dir.new")));
|
true,
|
||||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.old"), NULL));
|
storage_common_equivalent_path(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah")));
|
||||||
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.new")));
|
mu_assert_int_eq(
|
||||||
|
true,
|
||||||
|
storage_common_equivalent_path(
|
||||||
|
storage, UNIT_TESTS_PATH("blah/"), UNIT_TESTS_PATH("blah/")));
|
||||||
|
mu_assert_int_eq(
|
||||||
|
false,
|
||||||
|
storage_common_equivalent_path(
|
||||||
|
storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah-blah")));
|
||||||
|
mu_assert_int_eq(
|
||||||
|
false,
|
||||||
|
storage_common_equivalent_path(
|
||||||
|
storage, UNIT_TESTS_PATH("blah/"), UNIT_TESTS_PATH("blah-blah/")));
|
||||||
|
|
||||||
storage_dir_remove(storage, EXT_PATH("dir.new"));
|
mu_assert_int_eq(
|
||||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.new"), NULL));
|
true, storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah")));
|
||||||
|
mu_assert_int_eq(
|
||||||
|
true,
|
||||||
|
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah/blah")));
|
||||||
|
mu_assert_int_eq(
|
||||||
|
false,
|
||||||
|
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah/blah"), UNIT_TESTS_PATH("blah")));
|
||||||
|
mu_assert_int_eq(
|
||||||
|
false,
|
||||||
|
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah-blah")));
|
||||||
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
@@ -403,10 +449,13 @@ MU_TEST(storage_dir_rename) {
|
|||||||
MU_TEST_SUITE(storage_rename) {
|
MU_TEST_SUITE(storage_rename) {
|
||||||
MU_RUN_TEST(storage_file_rename);
|
MU_RUN_TEST(storage_file_rename);
|
||||||
MU_RUN_TEST(storage_dir_rename);
|
MU_RUN_TEST(storage_dir_rename);
|
||||||
|
MU_RUN_TEST(storage_equiv_and_subdir);
|
||||||
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
storage_dir_remove(storage, EXT_PATH("dir.old"));
|
for(size_t i = 0; i < COUNT_OF(dir_rename_tests); i++) {
|
||||||
storage_dir_remove(storage, EXT_PATH("dir.new"));
|
storage_dir_remove(storage, dir_rename_tests[i][0]);
|
||||||
|
storage_dir_remove(storage, dir_rename_tests[i][1]);
|
||||||
|
}
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,7 +702,7 @@ MU_TEST(test_md5_calc) {
|
|||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
File* file = storage_file_alloc(storage);
|
File* file = storage_file_alloc(storage);
|
||||||
|
|
||||||
const char* path = UNIT_TESTS_PATH("storage/md5.txt");
|
const char* path = UNIT_TESTS_RESOURCES_PATH("storage/md5.txt");
|
||||||
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
|
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
|
||||||
const uint8_t md5[MD5_HASH_SIZE] = {
|
const uint8_t md5[MD5_HASH_SIZE] = {
|
||||||
0x2a,
|
0x2a,
|
||||||
|
|||||||
@@ -3,4 +3,3 @@ ADD_SCENE(gpio, test, Test)
|
|||||||
ADD_SCENE(gpio, usb_uart, UsbUart)
|
ADD_SCENE(gpio, usb_uart, UsbUart)
|
||||||
ADD_SCENE(gpio, usb_uart_cfg, UsbUartCfg)
|
ADD_SCENE(gpio, usb_uart_cfg, UsbUartCfg)
|
||||||
ADD_SCENE(gpio, usb_uart_close_rpc, UsbUartCloseRpc)
|
ADD_SCENE(gpio, usb_uart_close_rpc, UsbUartCloseRpc)
|
||||||
ADD_SCENE(gpio, exit_confirm, ExitConfirm)
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
#include "gpio_app_i.h"
|
|
||||||
|
|
||||||
void gpio_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) {
|
|
||||||
GpioApp* app = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_scene_exit_confirm_on_enter(void* context) {
|
|
||||||
GpioApp* app = context;
|
|
||||||
DialogEx* dialog = app->dialog;
|
|
||||||
|
|
||||||
dialog_ex_set_context(dialog, app);
|
|
||||||
dialog_ex_set_left_button_text(dialog, "Exit");
|
|
||||||
dialog_ex_set_right_button_text(dialog, "Stay");
|
|
||||||
dialog_ex_set_header(dialog, "Exit USB-UART?", 22, 12, AlignLeft, AlignTop);
|
|
||||||
dialog_ex_set_result_callback(dialog, gpio_scene_exit_confirm_dialog_callback);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewExitConfirm);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gpio_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
GpioApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == DialogExResultRight) {
|
|
||||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
|
||||||
} else if(event.event == DialogExResultLeft) {
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, GpioSceneStart);
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpio_scene_exit_confirm_on_exit(void* context) {
|
|
||||||
GpioApp* app = context;
|
|
||||||
|
|
||||||
// Clean view
|
|
||||||
dialog_ex_reset(app->dialog);
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ typedef struct {
|
|||||||
UsbUartState state;
|
UsbUartState state;
|
||||||
} SceneUsbUartBridge;
|
} SceneUsbUartBridge;
|
||||||
|
|
||||||
static SceneUsbUartBridge* scene_usb_uart;
|
static SceneUsbUartBridge* scene_usb_uart = NULL;
|
||||||
|
|
||||||
void gpio_scene_usb_uart_callback(GpioCustomEvent event, void* context) {
|
void gpio_scene_usb_uart_callback(GpioCustomEvent event, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
@@ -14,10 +14,21 @@ void gpio_scene_usb_uart_callback(GpioCustomEvent event, void* context) {
|
|||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gpio_scene_usb_uart_dialog_callback(DialogExResult result, void* context) {
|
||||||
|
GpioApp* app = context;
|
||||||
|
if(result == DialogExResultLeft) {
|
||||||
|
usb_uart_disable(app->usb_uart_bridge);
|
||||||
|
free(scene_usb_uart);
|
||||||
|
scene_usb_uart = NULL;
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, GpioSceneStart);
|
||||||
|
} else {
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void gpio_scene_usb_uart_on_enter(void* context) {
|
void gpio_scene_usb_uart_on_enter(void* context) {
|
||||||
GpioApp* app = context;
|
GpioApp* app = context;
|
||||||
uint32_t prev_state = scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUart);
|
if(!scene_usb_uart) {
|
||||||
if(prev_state == 0) {
|
|
||||||
scene_usb_uart = malloc(sizeof(SceneUsbUartBridge));
|
scene_usb_uart = malloc(sizeof(SceneUsbUartBridge));
|
||||||
scene_usb_uart->cfg.vcp_ch = 0;
|
scene_usb_uart->cfg.vcp_ch = 0;
|
||||||
scene_usb_uart->cfg.uart_ch = 0;
|
scene_usb_uart->cfg.uart_ch = 0;
|
||||||
@@ -31,7 +42,6 @@ void gpio_scene_usb_uart_on_enter(void* context) {
|
|||||||
usb_uart_get_state(app->usb_uart_bridge, &scene_usb_uart->state);
|
usb_uart_get_state(app->usb_uart_bridge, &scene_usb_uart->state);
|
||||||
|
|
||||||
gpio_usb_uart_set_callback(app->gpio_usb_uart, gpio_scene_usb_uart_callback, app);
|
gpio_usb_uart_set_callback(app->gpio_usb_uart, gpio_scene_usb_uart_callback, app);
|
||||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneUsbUart, 0);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
|
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
|
||||||
notification_message(app->notifications, &sequence_display_backlight_enforce_on);
|
notification_message(app->notifications, &sequence_display_backlight_enforce_on);
|
||||||
}
|
}
|
||||||
@@ -39,11 +49,16 @@ void gpio_scene_usb_uart_on_enter(void* context) {
|
|||||||
bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
|
bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
|
||||||
GpioApp* app = context;
|
GpioApp* app = context;
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneUsbUart, 1);
|
|
||||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCfg);
|
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCfg);
|
||||||
return true;
|
return true;
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
scene_manager_next_scene(app->scene_manager, GpioSceneExitConfirm);
|
DialogEx* dialog = app->dialog;
|
||||||
|
dialog_ex_set_context(dialog, app);
|
||||||
|
dialog_ex_set_left_button_text(dialog, "Exit");
|
||||||
|
dialog_ex_set_right_button_text(dialog, "Stay");
|
||||||
|
dialog_ex_set_header(dialog, "Exit USB-UART?", 22, 12, AlignLeft, AlignTop);
|
||||||
|
dialog_ex_set_result_callback(dialog, gpio_scene_usb_uart_dialog_callback);
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewExitConfirm);
|
||||||
return true;
|
return true;
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
uint32_t tx_cnt_last = scene_usb_uart->state.tx_cnt;
|
uint32_t tx_cnt_last = scene_usb_uart->state.tx_cnt;
|
||||||
@@ -61,10 +76,5 @@ bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
void gpio_scene_usb_uart_on_exit(void* context) {
|
void gpio_scene_usb_uart_on_exit(void* context) {
|
||||||
GpioApp* app = context;
|
GpioApp* app = context;
|
||||||
uint32_t prev_state = scene_manager_get_scene_state(app->scene_manager, GpioSceneUsbUart);
|
|
||||||
if(prev_state == 0) {
|
|
||||||
usb_uart_disable(app->usb_uart_bridge);
|
|
||||||
free(scene_usb_uart);
|
|
||||||
}
|
|
||||||
notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
|
notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,21 +401,26 @@ bool storage_common_exists(Storage* storage, const char* path);
|
|||||||
* - /int/Test and /int/test -> false (Case-sensitive storage),
|
* - /int/Test and /int/test -> false (Case-sensitive storage),
|
||||||
* - /ext/Test and /ext/test -> true (Case-insensitive storage).
|
* - /ext/Test and /ext/test -> true (Case-insensitive storage).
|
||||||
*
|
*
|
||||||
* If the truncate parameter is set to true, the second path will be
|
|
||||||
* truncated to be no longer than the first one. It is useful to determine
|
|
||||||
* whether path2 is a subdirectory of path1.
|
|
||||||
*
|
|
||||||
* @param storage pointer to a storage API instance.
|
* @param storage pointer to a storage API instance.
|
||||||
* @param path1 pointer to a zero-terminated string containing the first path.
|
* @param path1 pointer to a zero-terminated string containing the first path.
|
||||||
* @param path2 pointer to a zero-terminated string containing the second path.
|
* @param path2 pointer to a zero-terminated string containing the second path.
|
||||||
* @param truncate whether to truncate path2 to be no longer than path1.
|
|
||||||
* @return true if paths are equivalent, false otherwise.
|
* @return true if paths are equivalent, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_common_equivalent_path(
|
bool storage_common_equivalent_path(Storage* storage, const char* path1, const char* path2);
|
||||||
Storage* storage,
|
|
||||||
const char* path1,
|
/**
|
||||||
const char* path2,
|
* @brief Check whether a path is a subpath of another path.
|
||||||
bool truncate);
|
*
|
||||||
|
* This function respects storage-defined equivalence rules
|
||||||
|
* (see `storage_common_equivalent_path`).
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param parent pointer to a zero-terminated string containing the parent path.
|
||||||
|
* @param child pointer to a zero-terminated string containing the child path.
|
||||||
|
* @return true if `child` is a subpath of `parent`, or if `child` is equivalent
|
||||||
|
* to `parent`; false otherwise.
|
||||||
|
*/
|
||||||
|
bool storage_common_is_subdir(Storage* storage, const char* parent, const char* child);
|
||||||
|
|
||||||
/******************* Error Functions *******************/
|
/******************* Error Functions *******************/
|
||||||
|
|
||||||
|
|||||||
@@ -493,13 +493,13 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cannot rename a directory to itself or to a nested directory
|
// Cannot rename a directory to itself or to a nested directory
|
||||||
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
|
if(storage_common_is_subdir(storage, old_path, new_path)) {
|
||||||
error = FSE_INVALID_NAME;
|
error = FSE_INVALID_NAME;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renaming a regular file to itself does nothing and always succeeds
|
// Renaming a regular file to itself does nothing and always succeeds
|
||||||
} else if(storage_common_equivalent_path(storage, old_path, new_path, false)) {
|
} else if(storage_common_equivalent_path(storage, old_path, new_path)) {
|
||||||
error = FSE_OK;
|
error = FSE_OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -816,11 +816,11 @@ bool storage_common_exists(Storage* storage, const char* path) {
|
|||||||
return storage_common_stat(storage, path, &file_info) == FSE_OK;
|
return storage_common_stat(storage, path, &file_info) == FSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool storage_common_equivalent_path(
|
static bool storage_internal_equivalent_path(
|
||||||
Storage* storage,
|
Storage* storage,
|
||||||
const char* path1,
|
const char* path1,
|
||||||
const char* path2,
|
const char* path2,
|
||||||
bool truncate) {
|
bool check_subdir) {
|
||||||
furi_check(storage);
|
furi_check(storage);
|
||||||
|
|
||||||
S_API_PROLOGUE;
|
S_API_PROLOGUE;
|
||||||
@@ -829,7 +829,7 @@ bool storage_common_equivalent_path(
|
|||||||
.cequivpath = {
|
.cequivpath = {
|
||||||
.path1 = path1,
|
.path1 = path1,
|
||||||
.path2 = path2,
|
.path2 = path2,
|
||||||
.truncate = truncate,
|
.check_subdir = check_subdir,
|
||||||
.thread_id = furi_thread_get_current_id(),
|
.thread_id = furi_thread_get_current_id(),
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -839,6 +839,14 @@ bool storage_common_equivalent_path(
|
|||||||
return S_RETURN_BOOL;
|
return S_RETURN_BOOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool storage_common_equivalent_path(Storage* storage, const char* path1, const char* path2) {
|
||||||
|
return storage_internal_equivalent_path(storage, path1, path2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storage_common_is_subdir(Storage* storage, const char* parent, const char* child) {
|
||||||
|
return storage_internal_equivalent_path(storage, parent, child, true);
|
||||||
|
}
|
||||||
|
|
||||||
/****************** ERROR ******************/
|
/****************** ERROR ******************/
|
||||||
|
|
||||||
const char* storage_error_get_desc(FS_Error error_id) {
|
const char* storage_error_get_desc(FS_Error error_id) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
const char* path1;
|
const char* path1;
|
||||||
const char* path2;
|
const char* path2;
|
||||||
bool truncate;
|
bool check_subdir;
|
||||||
FuriThreadId thread_id;
|
FuriThreadId thread_id;
|
||||||
} SADataCEquivPath;
|
} SADataCEquivPath;
|
||||||
|
|
||||||
|
|||||||
@@ -694,7 +694,23 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
|
|||||||
storage_path_trim_trailing_slashes(path2);
|
storage_path_trim_trailing_slashes(path2);
|
||||||
storage_process_alias(app, path1, message->data->cequivpath.thread_id, false);
|
storage_process_alias(app, path1, message->data->cequivpath.thread_id, false);
|
||||||
storage_process_alias(app, path2, message->data->cequivpath.thread_id, false);
|
storage_process_alias(app, path2, message->data->cequivpath.thread_id, false);
|
||||||
if(message->data->cequivpath.truncate) {
|
if(message->data->cequivpath.check_subdir) {
|
||||||
|
// by appending slashes at the end and then truncating the second path, we can
|
||||||
|
// effectively check for shared path components:
|
||||||
|
// example 1:
|
||||||
|
// path1: "/ext/blah" -> "/ext/blah/" -> "/ext/blah/"
|
||||||
|
// path2: "/ext/blah-blah" -> "/ect/blah-blah/" -> "/ext/blah-"
|
||||||
|
// results unequal, conclusion: path2 is not a subpath of path1
|
||||||
|
// example 2:
|
||||||
|
// path1: "/ext/blah" -> "/ext/blah/" -> "/ext/blah/"
|
||||||
|
// path2: "/ext/blah/blah" -> "/ect/blah/blah/" -> "/ext/blah/"
|
||||||
|
// results equal, conclusion: path2 is a subpath of path1
|
||||||
|
// example 3:
|
||||||
|
// path1: "/ext/blah/blah" -> "/ect/blah/blah/" -> "/ext/blah/blah/"
|
||||||
|
// path2: "/ext/blah" -> "/ext/blah/" -> "/ext/blah/"
|
||||||
|
// results unequal, conclusion: path2 is not a subpath of path1
|
||||||
|
furi_string_push_back(path1, '/');
|
||||||
|
furi_string_push_back(path2, '/');
|
||||||
furi_string_left(path2, furi_string_size(path1));
|
furi_string_left(path2, furi_string_size(path1));
|
||||||
}
|
}
|
||||||
message->return_data->bool_value =
|
message->return_data->bool_value =
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ void furi_delay_tick(uint32_t ticks);
|
|||||||
*
|
*
|
||||||
* @warning This should never be called in interrupt request context.
|
* @warning This should never be called in interrupt request context.
|
||||||
*
|
*
|
||||||
* @param[in] tick The tick until which kerel should delay task execution
|
* @param[in] tick The tick until which kernel should delay task execution
|
||||||
*
|
*
|
||||||
* @return The furi status.
|
* @return The furi status.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,73.0,,
|
Version,+,74.0,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
@@ -2491,9 +2491,10 @@ Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_
|
|||||||
Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t"
|
Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t"
|
||||||
Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t"
|
Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t"
|
||||||
Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*"
|
Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*, _Bool"
|
Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_exists,_Bool,"Storage*, const char*"
|
Function,+,storage_common_exists,_Bool,"Storage*, const char*"
|
||||||
Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*"
|
Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*"
|
||||||
|
Function,+,storage_common_is_subdir,_Bool,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*"
|
Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*"
|
Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*"
|
Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*"
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,73.0,,
|
Version,+,74.0,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
@@ -3173,9 +3173,10 @@ Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*"
|
|||||||
Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t"
|
Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t"
|
||||||
Function,+,st25tb_verify,_Bool,"St25tbData*, const FuriString*"
|
Function,+,st25tb_verify,_Bool,"St25tbData*, const FuriString*"
|
||||||
Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*"
|
Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*, _Bool"
|
Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_exists,_Bool,"Storage*, const char*"
|
Function,+,storage_common_exists,_Bool,"Storage*, const char*"
|
||||||
Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*"
|
Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*"
|
||||||
|
Function,+,storage_common_is_subdir,_Bool,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*"
|
Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*"
|
Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*"
|
||||||
Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*"
|
Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*"
|
||||||
|
|||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
#define configUSE_16_BIT_TICKS 0
|
#define configUSE_16_BIT_TICKS 0
|
||||||
#define configMAX_PRIORITIES (32)
|
#define configMAX_PRIORITIES (32)
|
||||||
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||||
|
#define configUSE_POSIX_ERRNO 1
|
||||||
|
|
||||||
/* Heap size determined automatically by linker */
|
/* Heap size determined automatically by linker */
|
||||||
// #define configTOTAL_HEAP_SIZE ((size_t)0)
|
// #define configTOTAL_HEAP_SIZE ((size_t)0)
|
||||||
@@ -146,9 +148,14 @@ standard names. */
|
|||||||
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION \
|
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION \
|
||||||
1 /* required only for Keil but does not hurt otherwise */
|
1 /* required only for Keil but does not hurt otherwise */
|
||||||
|
|
||||||
#define traceTASK_SWITCHED_IN() \
|
#define traceTASK_SWITCHED_IN() \
|
||||||
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
|
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
|
||||||
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack)
|
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack); \
|
||||||
|
errno = pxCurrentTCB->iTaskErrno
|
||||||
|
// ^^^^^ acquire errno directly from TCB because FreeRTOS assigns its `FreeRTOS_errno' _after_ our hook is called
|
||||||
|
|
||||||
|
// referencing `FreeRTOS_errno' here vvvvv because FreeRTOS calls our hook _before_ copying the value into the TCB, hence a manual write to the TCB would get overwritten
|
||||||
|
#define traceTASK_SWITCHED_OUT() FreeRTOS_errno = errno
|
||||||
|
|
||||||
#define portCLEAN_UP_TCB(pxTCB) \
|
#define portCLEAN_UP_TCB(pxTCB) \
|
||||||
extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \
|
extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \
|
||||||
|
|||||||
Reference in New Issue
Block a user