[FL-2499] Folders rename fix (#1190)
* Toolbox: dir_walk concept (like os.walk) * Storage CLI: tree command * Storage: fix folders copying, stage 1 * UnitTest: proper delays in subghz tests * Toolbox: dir_walk, recursive and filter options * dir_walk: unit tests * Merge: Fix unused param * SubGhz: cleaned up data parsing routine * SubGhz unit test: cleaned up logs, yield data load * SubGhz unit test: naming Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
parent
f04d0eea96
commit
fac4391af7
@ -282,7 +282,7 @@ FS_Error storage_int_restore(Storage* api, const char* dstname);
|
||||
/***************** Simplified Functions ******************/
|
||||
|
||||
/**
|
||||
* Removes a file/directory from the repository, the directory must be empty and the file/directory must not be open
|
||||
* Removes a file/directory, the directory must be empty and the file/directory must not be open
|
||||
* @param storage pointer to the api
|
||||
* @param path
|
||||
* @return true on success or if file/dir is not exist
|
||||
@ -290,7 +290,7 @@ FS_Error storage_int_restore(Storage* api, const char* dstname);
|
||||
bool storage_simply_remove(Storage* storage, const char* path);
|
||||
|
||||
/**
|
||||
* Removes a file/directory from the repository, the directory can be not empty
|
||||
* Recursively removes a file/directory, the directory can be not empty
|
||||
* @param storage pointer to the api
|
||||
* @param path
|
||||
* @return true on success or if file/dir is not exist
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <cli/cli.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/md5.h>
|
||||
#include <lib/toolbox/dir_walk.h>
|
||||
#include <storage/storage.h>
|
||||
#include <storage/storage_sd_api.h>
|
||||
#include <power/power_service/power.h>
|
||||
@ -18,6 +19,7 @@ static void storage_cli_print_usage() {
|
||||
printf("\tinfo\t - get FS info\r\n");
|
||||
printf("\tformat\t - format filesystem\r\n");
|
||||
printf("\tlist\t - list files and dirs\r\n");
|
||||
printf("\ttree\t - list files and dirs, recursive\r\n");
|
||||
printf("\tremove\t - delete the file or directory\r\n");
|
||||
printf("\tread\t - read text from file and print file size and content to cli\r\n");
|
||||
printf(
|
||||
@ -138,6 +140,44 @@ static void storage_cli_list(Cli* cli, string_t path) {
|
||||
}
|
||||
}
|
||||
|
||||
static void storage_cli_tree(Cli* cli, string_t path) {
|
||||
if(string_cmp_str(path, "/") == 0) {
|
||||
string_set(path, "/int");
|
||||
storage_cli_tree(cli, path);
|
||||
string_set(path, "/ext");
|
||||
storage_cli_tree(cli, path);
|
||||
} else {
|
||||
Storage* api = furi_record_open("storage");
|
||||
DirWalk* dir_walk = dir_walk_alloc(api);
|
||||
string_t name;
|
||||
string_init(name);
|
||||
|
||||
if(dir_walk_open(dir_walk, string_get_cstr(path))) {
|
||||
FileInfo fileinfo;
|
||||
bool read_done = false;
|
||||
|
||||
while(dir_walk_read(dir_walk, name, &fileinfo) == DirWalkOK) {
|
||||
read_done = true;
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
printf("\t[D] %s\r\n", string_get_cstr(name));
|
||||
} else {
|
||||
printf("\t[F] %s %lub\r\n", string_get_cstr(name), (uint32_t)(fileinfo.size));
|
||||
}
|
||||
}
|
||||
|
||||
if(!read_done) {
|
||||
printf("\tEmpty\r\n");
|
||||
}
|
||||
} else {
|
||||
storage_cli_print_error(dir_walk_get_error(dir_walk));
|
||||
}
|
||||
|
||||
string_clear(name);
|
||||
dir_walk_free(dir_walk);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
}
|
||||
|
||||
static void storage_cli_read(Cli* cli, string_t path) {
|
||||
UNUSED(cli);
|
||||
Storage* api = furi_record_open("storage");
|
||||
@ -474,6 +514,11 @@ void storage_cli(Cli* cli, string_t args, void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "tree") == 0) {
|
||||
storage_cli_tree(cli, path);
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "read") == 0) {
|
||||
storage_cli_read(cli, path);
|
||||
break;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "storage_i.h"
|
||||
#include "storage_message.h"
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/dir_walk.h>
|
||||
|
||||
#define MAX_NAME_LENGTH 256
|
||||
|
||||
@ -332,12 +333,69 @@ FS_Error storage_common_remove(Storage* storage, const char* path) {
|
||||
FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path) {
|
||||
FS_Error error = storage_common_copy(storage, old_path, new_path);
|
||||
if(error == FSE_OK) {
|
||||
error = storage_common_remove(storage, old_path);
|
||||
if(storage_simply_remove_recursive(storage, old_path)) {
|
||||
error = FSE_OK;
|
||||
} else {
|
||||
error = FSE_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static FS_Error
|
||||
storage_copy_recursive(Storage* storage, const char* old_path, const char* new_path) {
|
||||
FS_Error error = storage_common_mkdir(storage, new_path);
|
||||
DirWalk* dir_walk = dir_walk_alloc(storage);
|
||||
string_t path;
|
||||
string_t tmp_new_path;
|
||||
string_t tmp_old_path;
|
||||
FileInfo fileinfo;
|
||||
string_init(path);
|
||||
string_init(tmp_new_path);
|
||||
string_init(tmp_old_path);
|
||||
|
||||
do {
|
||||
if(error != FSE_OK) break;
|
||||
|
||||
if(!dir_walk_open(dir_walk, old_path)) {
|
||||
error = dir_walk_get_error(dir_walk);
|
||||
break;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
DirWalkResult res = dir_walk_read(dir_walk, path, &fileinfo);
|
||||
|
||||
if(res == DirWalkError) {
|
||||
error = dir_walk_get_error(dir_walk);
|
||||
break;
|
||||
} else if(res == DirWalkLast) {
|
||||
break;
|
||||
} else {
|
||||
string_set(tmp_old_path, path);
|
||||
string_right(path, strlen(old_path));
|
||||
string_printf(tmp_new_path, "%s%s", new_path, string_get_cstr(path));
|
||||
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
error = storage_common_mkdir(storage, string_get_cstr(tmp_new_path));
|
||||
} else {
|
||||
error = storage_common_copy(
|
||||
storage, string_get_cstr(tmp_old_path), string_get_cstr(tmp_new_path));
|
||||
}
|
||||
|
||||
if(error != FSE_OK) break;
|
||||
}
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
string_clear(tmp_new_path);
|
||||
string_clear(tmp_old_path);
|
||||
string_clear(path);
|
||||
dir_walk_free(dir_walk);
|
||||
return error;
|
||||
}
|
||||
|
||||
FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path) {
|
||||
FS_Error error;
|
||||
|
||||
@ -346,7 +404,7 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char*
|
||||
|
||||
if(error == FSE_OK) {
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
error = storage_common_mkdir(storage, new_path);
|
||||
error = storage_copy_recursive(storage, old_path, new_path);
|
||||
} else {
|
||||
Stream* stream_from = file_stream_alloc(storage);
|
||||
Stream* stream_to = file_stream_alloc(storage);
|
||||
|
272
applications/unit_tests/storage/dirwalk_test.c
Normal file
272
applications/unit_tests/storage/dirwalk_test.c
Normal file
@ -0,0 +1,272 @@
|
||||
#include "../minunit.h"
|
||||
#include <furi.h>
|
||||
#include <m-dict.h>
|
||||
#include <toolbox/dir_walk.h>
|
||||
|
||||
static const char* const storage_test_dirwalk_paths[] = {
|
||||
"1",
|
||||
"11",
|
||||
"111",
|
||||
"1/2",
|
||||
"1/22",
|
||||
"1/222",
|
||||
"11/2",
|
||||
"111/2",
|
||||
"111/22",
|
||||
"111/22/33",
|
||||
};
|
||||
|
||||
static const char* const storage_test_dirwalk_files[] = {
|
||||
"file1.test",
|
||||
"file2.test",
|
||||
"file3.ext_test",
|
||||
"1/file1.test",
|
||||
"111/22/33/file1.test",
|
||||
"111/22/33/file2.test",
|
||||
"111/22/33/file3.ext_test",
|
||||
"111/22/33/file4.ext_test",
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* const path;
|
||||
bool is_dir;
|
||||
} StorageTestPathDesc;
|
||||
|
||||
const StorageTestPathDesc storage_test_dirwalk_full[] = {
|
||||
{.path = "1", .is_dir = true},
|
||||
{.path = "11", .is_dir = true},
|
||||
{.path = "111", .is_dir = true},
|
||||
{.path = "1/2", .is_dir = true},
|
||||
{.path = "1/22", .is_dir = true},
|
||||
{.path = "1/222", .is_dir = true},
|
||||
{.path = "11/2", .is_dir = true},
|
||||
{.path = "111/2", .is_dir = true},
|
||||
{.path = "111/22", .is_dir = true},
|
||||
{.path = "111/22/33", .is_dir = true},
|
||||
{.path = "file1.test", .is_dir = false},
|
||||
{.path = "file2.test", .is_dir = false},
|
||||
{.path = "file3.ext_test", .is_dir = false},
|
||||
{.path = "1/file1.test", .is_dir = false},
|
||||
{.path = "111/22/33/file1.test", .is_dir = false},
|
||||
{.path = "111/22/33/file2.test", .is_dir = false},
|
||||
{.path = "111/22/33/file3.ext_test", .is_dir = false},
|
||||
{.path = "111/22/33/file4.ext_test", .is_dir = false},
|
||||
};
|
||||
|
||||
const StorageTestPathDesc storage_test_dirwalk_no_recursive[] = {
|
||||
{.path = "1", .is_dir = true},
|
||||
{.path = "11", .is_dir = true},
|
||||
{.path = "111", .is_dir = true},
|
||||
{.path = "file1.test", .is_dir = false},
|
||||
{.path = "file2.test", .is_dir = false},
|
||||
{.path = "file3.ext_test", .is_dir = false},
|
||||
};
|
||||
|
||||
const StorageTestPathDesc storage_test_dirwalk_filter[] = {
|
||||
{.path = "file1.test", .is_dir = false},
|
||||
{.path = "file2.test", .is_dir = false},
|
||||
{.path = "1/file1.test", .is_dir = false},
|
||||
{.path = "111/22/33/file1.test", .is_dir = false},
|
||||
{.path = "111/22/33/file2.test", .is_dir = false},
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool is_dir;
|
||||
bool visited;
|
||||
} StorageTestPath;
|
||||
|
||||
DICT_DEF2(StorageTestPathDict, string_t, STRING_OPLIST, StorageTestPath, M_POD_OPLIST)
|
||||
|
||||
static StorageTestPathDict_t*
|
||||
storage_test_paths_alloc(const StorageTestPathDesc paths[], size_t paths_count) {
|
||||
StorageTestPathDict_t* data = malloc(sizeof(StorageTestPathDict_t));
|
||||
StorageTestPathDict_init(*data);
|
||||
|
||||
for(size_t i = 0; i < paths_count; i++) {
|
||||
string_t key;
|
||||
string_init_set(key, paths[i].path);
|
||||
StorageTestPath value = {
|
||||
.is_dir = paths[i].is_dir,
|
||||
.visited = false,
|
||||
};
|
||||
|
||||
StorageTestPathDict_set_at(*data, key, value);
|
||||
string_clear(key);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void storage_test_paths_free(StorageTestPathDict_t* data) {
|
||||
StorageTestPathDict_clear(*data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static bool storage_test_paths_mark(StorageTestPathDict_t* data, string_t path, bool is_dir) {
|
||||
bool found = false;
|
||||
|
||||
StorageTestPath* record = StorageTestPathDict_get(*data, path);
|
||||
if(record) {
|
||||
if(is_dir == record->is_dir) {
|
||||
if(record->visited == false) {
|
||||
record->visited = true;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool storage_test_paths_check(StorageTestPathDict_t* data) {
|
||||
bool error = false;
|
||||
|
||||
StorageTestPathDict_it_t it;
|
||||
for(StorageTestPathDict_it(it, *data); !StorageTestPathDict_end_p(it);
|
||||
StorageTestPathDict_next(it)) {
|
||||
const StorageTestPathDict_itref_t* itref = StorageTestPathDict_cref(it);
|
||||
|
||||
if(itref->value.visited == false) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static bool write_file_13DA(Storage* storage, const char* path) {
|
||||
File* file = storage_file_alloc(storage);
|
||||
bool result = false;
|
||||
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
result = storage_file_write(file, "13DA", 4) == 4;
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void storage_dirs_create(Storage* storage, const char* base) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
|
||||
storage_common_mkdir(storage, base);
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_paths); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]);
|
||||
storage_common_mkdir(storage, string_get_cstr(path));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_files); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]);
|
||||
write_file_13DA(storage, string_get_cstr(path));
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
}
|
||||
|
||||
MU_TEST_1(test_dirwalk_full, Storage* storage) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FileInfo fileinfo;
|
||||
|
||||
StorageTestPathDict_t* paths =
|
||||
storage_test_paths_alloc(storage_test_dirwalk_full, COUNT_OF(storage_test_dirwalk_full));
|
||||
|
||||
DirWalk* dir_walk = dir_walk_alloc(storage);
|
||||
mu_check(dir_walk_open(dir_walk, "/ext/dirwalk"));
|
||||
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
string_right(path, strlen("/ext/dirwalk/"));
|
||||
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
|
||||
}
|
||||
|
||||
dir_walk_free(dir_walk);
|
||||
string_clear(path);
|
||||
|
||||
mu_check(storage_test_paths_check(paths) == false);
|
||||
|
||||
storage_test_paths_free(paths);
|
||||
}
|
||||
|
||||
MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FileInfo fileinfo;
|
||||
|
||||
StorageTestPathDict_t* paths = storage_test_paths_alloc(
|
||||
storage_test_dirwalk_no_recursive, COUNT_OF(storage_test_dirwalk_no_recursive));
|
||||
|
||||
DirWalk* dir_walk = dir_walk_alloc(storage);
|
||||
dir_walk_set_recursive(dir_walk, false);
|
||||
mu_check(dir_walk_open(dir_walk, "/ext/dirwalk"));
|
||||
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
string_right(path, strlen("/ext/dirwalk/"));
|
||||
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
|
||||
}
|
||||
|
||||
dir_walk_free(dir_walk);
|
||||
string_clear(path);
|
||||
|
||||
mu_check(storage_test_paths_check(paths) == false);
|
||||
|
||||
storage_test_paths_free(paths);
|
||||
}
|
||||
|
||||
static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* fileinfo, void* ctx) {
|
||||
UNUSED(ctx);
|
||||
|
||||
// only files
|
||||
if(!(fileinfo->flags & FSF_DIRECTORY)) {
|
||||
// with ".test" in name
|
||||
if(strstr(name, ".test") != NULL) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MU_TEST_1(test_dirwalk_filter, Storage* storage) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FileInfo fileinfo;
|
||||
|
||||
StorageTestPathDict_t* paths = storage_test_paths_alloc(
|
||||
storage_test_dirwalk_filter, COUNT_OF(storage_test_dirwalk_filter));
|
||||
|
||||
DirWalk* dir_walk = dir_walk_alloc(storage);
|
||||
dir_walk_set_filter_cb(dir_walk, test_dirwalk_filter_no_folder_ext, NULL);
|
||||
mu_check(dir_walk_open(dir_walk, "/ext/dirwalk"));
|
||||
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
string_right(path, strlen("/ext/dirwalk/"));
|
||||
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
|
||||
}
|
||||
|
||||
dir_walk_free(dir_walk);
|
||||
string_clear(path);
|
||||
|
||||
mu_check(storage_test_paths_check(paths) == false);
|
||||
|
||||
storage_test_paths_free(paths);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_dirwalk_suite) {
|
||||
Storage* storage = furi_record_open("storage");
|
||||
storage_dirs_create(storage, "/ext/dirwalk");
|
||||
|
||||
MU_RUN_TEST_1(test_dirwalk_full, storage);
|
||||
MU_RUN_TEST_1(test_dirwalk_no_recursive, storage);
|
||||
MU_RUN_TEST_1(test_dirwalk_filter, storage);
|
||||
|
||||
storage_simply_remove_recursive(storage, "/ext/dirwalk");
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
int run_minunit_test_dirwalk() {
|
||||
MU_RUN_SUITE(test_dirwalk_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
@ -164,8 +164,153 @@ MU_TEST_SUITE(storage_dir) {
|
||||
MU_RUN_TEST(storage_dir_open_lock);
|
||||
}
|
||||
|
||||
static const char* const storage_copy_test_paths[] = {
|
||||
"1",
|
||||
"11",
|
||||
"111",
|
||||
"1/2",
|
||||
"1/22",
|
||||
"1/222",
|
||||
"11/1",
|
||||
"111/2",
|
||||
"111/22",
|
||||
"111/22/33",
|
||||
};
|
||||
|
||||
static const char* const storage_copy_test_files[] = {
|
||||
"file.test",
|
||||
"1/file.test",
|
||||
"111/22/33/file.test",
|
||||
};
|
||||
|
||||
static bool write_file_13DA(Storage* storage, const char* path) {
|
||||
File* file = storage_file_alloc(storage);
|
||||
bool result = false;
|
||||
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
result = storage_file_write(file, "13DA", 4) == 4;
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool check_file_13DA(Storage* storage, const char* path) {
|
||||
File* file = storage_file_alloc(storage);
|
||||
bool result = false;
|
||||
if(storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
char data[10] = {0};
|
||||
result = storage_file_read(file, data, 4) == 4;
|
||||
if(result) {
|
||||
result = memcmp(data, "13DA", 4) == 0;
|
||||
}
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void storage_dir_create(Storage* storage, const char* base) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
|
||||
storage_common_mkdir(storage, base);
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
|
||||
storage_common_mkdir(storage, string_get_cstr(path));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
|
||||
write_file_13DA(storage, string_get_cstr(path));
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
}
|
||||
|
||||
static void storage_dir_remove(Storage* storage, const char* base) {
|
||||
storage_simply_remove_recursive(storage, base);
|
||||
}
|
||||
|
||||
static bool storage_dir_rename_check(Storage* storage, const char* base) {
|
||||
bool result = false;
|
||||
string_t path;
|
||||
string_init(path);
|
||||
|
||||
result = (storage_common_stat(storage, base, NULL) == FSE_OK);
|
||||
|
||||
if(result) {
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
|
||||
result = (storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK);
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(result) {
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
|
||||
result = check_file_13DA(storage, string_get_cstr(path));
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
MU_TEST(storage_file_rename) {
|
||||
Storage* storage = furi_record_open("storage");
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
mu_check(write_file_13DA(storage, "/ext/file.old"));
|
||||
mu_check(check_file_13DA(storage, "/ext/file.old"));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_rename(storage, "/ext/file.old", "/ext/file.new"));
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, "/ext/file.old", NULL));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, "/ext/file.new", NULL));
|
||||
mu_check(check_file_13DA(storage, "/ext/file.new"));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, "/ext/file.new"));
|
||||
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
MU_TEST(storage_dir_rename) {
|
||||
Storage* storage = furi_record_open("storage");
|
||||
|
||||
storage_dir_create(storage, "/ext/dir.old");
|
||||
|
||||
mu_check(storage_dir_rename_check(storage, "/ext/dir.old"));
|
||||
|
||||
mu_assert_int_eq(FSE_OK, storage_common_rename(storage, "/ext/dir.old", "/ext/dir.new"));
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, "/ext/dir.old", NULL));
|
||||
mu_check(storage_dir_rename_check(storage, "/ext/dir.new"));
|
||||
|
||||
storage_dir_remove(storage, "/ext/dir.new");
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, "/ext/dir.new", NULL));
|
||||
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(storage_rename) {
|
||||
MU_RUN_TEST(storage_file_rename);
|
||||
MU_RUN_TEST(storage_dir_rename);
|
||||
|
||||
Storage* storage = furi_record_open("storage");
|
||||
storage_dir_remove(storage, "/ext/dir.old");
|
||||
storage_dir_remove(storage, "/ext/dir.new");
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
int run_minunit_test_storage() {
|
||||
MU_RUN_SUITE(storage_file);
|
||||
MU_RUN_SUITE(storage_dir);
|
||||
MU_RUN_SUITE(storage_rename);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ static void subghz_test_rx_callback(
|
||||
string_init(text);
|
||||
subghz_protocol_decoder_base_get_string(decoder_base, text);
|
||||
subghz_receiver_reset(receiver_handler);
|
||||
FURI_LOG_I(TAG, "\r\n%s", string_get_cstr(text));
|
||||
FURI_LOG_T(TAG, "\r\n%s", string_get_cstr(text));
|
||||
string_clear(text);
|
||||
subghz_test_decoder_count++;
|
||||
}
|
||||
@ -54,7 +54,7 @@ static void subghz_test_deinit(void) {
|
||||
subghz_environment_free(environment_handler);
|
||||
}
|
||||
|
||||
static bool subghz_decode_test(const char* path, const char* name_decoder) {
|
||||
static bool subghz_decoder_test(const char* path, const char* name_decoder) {
|
||||
subghz_test_decoder_count = 0;
|
||||
uint32_t test_start = furi_hal_get_tick();
|
||||
|
||||
@ -69,13 +69,13 @@ static bool subghz_decode_test(const char* path, const char* name_decoder) {
|
||||
|
||||
LevelDuration level_duration;
|
||||
while(furi_hal_get_tick() - test_start < TEST_TIMEOUT) {
|
||||
furi_hal_delay_us(
|
||||
500); //you need to have time to read from the file from the SD card
|
||||
level_duration =
|
||||
subghz_file_encoder_worker_get_level_duration(file_worker_encoder_handler);
|
||||
if(!level_duration_is_reset(level_duration)) {
|
||||
bool level = level_duration_get_level(level_duration);
|
||||
uint32_t duration = level_duration_get_duration(level_duration);
|
||||
// Yield, to load data inside the worker
|
||||
osThreadYield();
|
||||
decoder->protocol->decoder->feed(decoder, level, duration);
|
||||
} else {
|
||||
break;
|
||||
@ -88,7 +88,7 @@ static bool subghz_decode_test(const char* path, const char* name_decoder) {
|
||||
}
|
||||
subghz_file_encoder_worker_free(file_worker_encoder_handler);
|
||||
}
|
||||
FURI_LOG_I(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
if(furi_hal_get_tick() - test_start > TEST_TIMEOUT) {
|
||||
printf("\033[0;31mTest decoder %s ERROR TimeOut\033[0m\r\n", name_decoder);
|
||||
return false;
|
||||
@ -97,7 +97,7 @@ static bool subghz_decode_test(const char* path, const char* name_decoder) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool subghz_decode_ramdom_test(const char* path) {
|
||||
static bool subghz_decode_random_test(const char* path) {
|
||||
subghz_test_decoder_count = 0;
|
||||
subghz_receiver_reset(receiver_handler);
|
||||
uint32_t test_start = furi_hal_get_tick();
|
||||
@ -109,12 +109,13 @@ static bool subghz_decode_ramdom_test(const char* path) {
|
||||
|
||||
LevelDuration level_duration;
|
||||
while(furi_hal_get_tick() - test_start < TEST_TIMEOUT * 10) {
|
||||
furi_hal_delay_us(500); //you need to have time to read from the file from the SD card
|
||||
level_duration =
|
||||
subghz_file_encoder_worker_get_level_duration(file_worker_encoder_handler);
|
||||
if(!level_duration_is_reset(level_duration)) {
|
||||
bool level = level_duration_get_level(level_duration);
|
||||
uint32_t duration = level_duration_get_duration(level_duration);
|
||||
// Yield, to load data inside the worker
|
||||
osThreadYield();
|
||||
subghz_receiver_decode(receiver_handler, level, duration);
|
||||
} else {
|
||||
break;
|
||||
@ -126,7 +127,7 @@ static bool subghz_decode_ramdom_test(const char* path) {
|
||||
}
|
||||
subghz_file_encoder_worker_free(file_worker_encoder_handler);
|
||||
}
|
||||
FURI_LOG_I(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
if(furi_hal_get_tick() - test_start > TEST_TIMEOUT * 10) {
|
||||
printf("\033[0;31mRandom test ERROR TimeOut\033[0m\r\n");
|
||||
return false;
|
||||
@ -137,7 +138,7 @@ static bool subghz_decode_ramdom_test(const char* path) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool subghz_ecode_test(const char* path) {
|
||||
static bool subghz_encoder_test(const char* path) {
|
||||
subghz_test_decoder_count = 0;
|
||||
uint32_t test_start = furi_hal_get_tick();
|
||||
string_t temp_str;
|
||||
@ -189,7 +190,7 @@ static bool subghz_ecode_test(const char* path) {
|
||||
subghz_transmitter_free(transmitter);
|
||||
}
|
||||
flipper_format_free(fff_data_file);
|
||||
FURI_LOG_I(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
if(furi_hal_get_tick() - test_start > TEST_TIMEOUT) {
|
||||
printf("\033[0;31mTest encoder %s ERROR TimeOut\033[0m\r\n", string_get_cstr(temp_str));
|
||||
subghz_test_decoder_count = 0;
|
||||
@ -207,167 +208,166 @@ MU_TEST(subghz_keystore_test) {
|
||||
|
||||
MU_TEST(subghz_decoder_came_atomo_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/came_atomo_raw.sub", SUBGHZ_PROTOCOL_CAME_ATOMO_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_CAME_ATOMO_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_came_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test("/ext/unit_tests/subghz/came_raw.sub", SUBGHZ_PROTOCOL_CAME_NAME),
|
||||
subghz_decoder_test("/ext/unit_tests/subghz/came_raw.sub", SUBGHZ_PROTOCOL_CAME_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_CAME_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_came_twee_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/came_twee_raw.sub", SUBGHZ_PROTOCOL_CAME_TWEE_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_CAME_TWEE_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_faac_slh_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/faac_slh_raw.sub", SUBGHZ_PROTOCOL_FAAC_SLH_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_FAAC_SLH_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_gate_tx_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test("/ext/unit_tests/subghz/gate_tx_raw.sub", SUBGHZ_PROTOCOL_GATE_TX_NAME),
|
||||
subghz_decoder_test("/ext/unit_tests/subghz/gate_tx_raw.sub", SUBGHZ_PROTOCOL_GATE_TX_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_GATE_TX_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_hormann_hsm_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/hormann_hsm_raw.sub", SUBGHZ_PROTOCOL_HORMANN_HSM_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_HORMANN_HSM_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_ido_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test("/ext/unit_tests/subghz/ido_117_111_raw.sub", SUBGHZ_PROTOCOL_IDO_NAME),
|
||||
subghz_decoder_test("/ext/unit_tests/subghz/ido_117_111_raw.sub", SUBGHZ_PROTOCOL_IDO_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_IDO_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_keelog_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test("/ext/unit_tests/subghz/doorhan_raw.sub", SUBGHZ_PROTOCOL_KEELOQ_NAME),
|
||||
subghz_decoder_test("/ext/unit_tests/subghz/doorhan_raw.sub", SUBGHZ_PROTOCOL_KEELOQ_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_kia_seed_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test("/ext/unit_tests/subghz/kia_seed_raw.sub", SUBGHZ_PROTOCOL_KIA_NAME),
|
||||
subghz_decoder_test("/ext/unit_tests/subghz/kia_seed_raw.sub", SUBGHZ_PROTOCOL_KIA_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_KIA_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_nero_radio_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/nero_radio_raw.sub", SUBGHZ_PROTOCOL_NERO_RADIO_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_NERO_RADIO_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_nero_sketch_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/nero_sketch_raw.sub", SUBGHZ_PROTOCOL_NERO_SKETCH_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_NERO_SKETCH_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_nice_flo_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/nice_flo_raw.sub", SUBGHZ_PROTOCOL_NICE_FLO_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_NICE_FLO_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_nice_flor_s_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/nice_flor_s_raw.sub", SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_princeton_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/Princeton_raw.sub", SUBGHZ_PROTOCOL_PRINCETON_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_PRINCETON_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_scher_khan_magic_code_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/scher_khan_magic_code.sub", SUBGHZ_PROTOCOL_SCHER_KHAN_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_SCHER_KHAN_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_somfy_keytis_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/Somfy_keytis_raw.sub", SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_somfy_telis_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test(
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/somfy_telis_raw.sub", SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_star_line_test) {
|
||||
mu_assert(
|
||||
subghz_decode_test("/ext/unit_tests/subghz/cenmax_raw.sub", SUBGHZ_PROTOCOL_STAR_LINE_NAME),
|
||||
subghz_decoder_test(
|
||||
"/ext/unit_tests/subghz/cenmax_raw.sub", SUBGHZ_PROTOCOL_STAR_LINE_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_STAR_LINE_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_ecoder_princeton_test) {
|
||||
MU_TEST(subghz_encoder_princeton_test) {
|
||||
mu_assert(
|
||||
subghz_ecode_test("/ext/unit_tests/subghz/princeton.sub"),
|
||||
subghz_encoder_test("/ext/unit_tests/subghz/princeton.sub"),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_PRINCETON_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_ecoder_came_test) {
|
||||
MU_TEST(subghz_encoder_came_test) {
|
||||
mu_assert(
|
||||
subghz_ecode_test("/ext/unit_tests/subghz/came.sub"),
|
||||
subghz_encoder_test("/ext/unit_tests/subghz/came.sub"),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_CAME_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_ecoder_came_twee_test) {
|
||||
MU_TEST(subghz_encoder_came_twee_test) {
|
||||
mu_assert(
|
||||
subghz_ecode_test("/ext/unit_tests/subghz/came_twee.sub"),
|
||||
subghz_encoder_test("/ext/unit_tests/subghz/came_twee.sub"),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_CAME_TWEE_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_ecoder_gate_tx_test) {
|
||||
MU_TEST(subghz_encoder_gate_tx_test) {
|
||||
mu_assert(
|
||||
subghz_ecode_test("/ext/unit_tests/subghz/gate_tx.sub"),
|
||||
subghz_encoder_test("/ext/unit_tests/subghz/gate_tx.sub"),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_GATE_TX_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_ecoder_nice_flo_test) {
|
||||
MU_TEST(subghz_encoder_nice_flo_test) {
|
||||
mu_assert(
|
||||
subghz_ecode_test("/ext/unit_tests/subghz/nice_flo.sub"),
|
||||
subghz_encoder_test("/ext/unit_tests/subghz/nice_flo.sub"),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_NICE_FLO_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_ecoder_keelog_test) {
|
||||
MU_TEST(subghz_encoder_keelog_test) {
|
||||
mu_assert(
|
||||
subghz_ecode_test("/ext/unit_tests/subghz/doorhan.sub"),
|
||||
subghz_encoder_test("/ext/unit_tests/subghz/doorhan.sub"),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_random_test) {
|
||||
mu_assert(subghz_decode_ramdom_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
||||
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(subghz) {
|
||||
//MU_SUITE_CONFIGURE(&subghz_test_init, &subghz_test_deinit);
|
||||
|
||||
subghz_test_init();
|
||||
MU_RUN_TEST(subghz_keystore_test);
|
||||
|
||||
@ -390,12 +390,12 @@ MU_TEST_SUITE(subghz) {
|
||||
MU_RUN_TEST(subghz_decoder_somfy_telis_test);
|
||||
MU_RUN_TEST(subghz_decoder_star_line_test);
|
||||
|
||||
MU_RUN_TEST(subghz_ecoder_princeton_test);
|
||||
MU_RUN_TEST(subghz_ecoder_came_test);
|
||||
MU_RUN_TEST(subghz_ecoder_came_twee_test);
|
||||
MU_RUN_TEST(subghz_ecoder_gate_tx_test);
|
||||
MU_RUN_TEST(subghz_ecoder_nice_flo_test);
|
||||
MU_RUN_TEST(subghz_ecoder_keelog_test);
|
||||
MU_RUN_TEST(subghz_encoder_princeton_test);
|
||||
MU_RUN_TEST(subghz_encoder_came_test);
|
||||
MU_RUN_TEST(subghz_encoder_came_twee_test);
|
||||
MU_RUN_TEST(subghz_encoder_gate_tx_test);
|
||||
MU_RUN_TEST(subghz_encoder_nice_flo_test);
|
||||
MU_RUN_TEST(subghz_encoder_keelog_test);
|
||||
|
||||
MU_RUN_TEST(subghz_random_test);
|
||||
subghz_test_deinit();
|
||||
|
@ -18,6 +18,7 @@ int run_minunit_test_flipper_format_string();
|
||||
int run_minunit_test_stream();
|
||||
int run_minunit_test_storage();
|
||||
int run_minunit_test_subghz();
|
||||
int run_minunit_test_dirwalk();
|
||||
|
||||
void minunit_print_progress(void) {
|
||||
static char progress[] = {'\\', '|', '/', '-'};
|
||||
@ -60,6 +61,7 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) {
|
||||
test_result |= run_minunit();
|
||||
test_result |= run_minunit_test_storage();
|
||||
test_result |= run_minunit_test_stream();
|
||||
test_result |= run_minunit_test_dirwalk();
|
||||
test_result |= run_minunit_test_flipper_format();
|
||||
test_result |= run_minunit_test_flipper_format_string();
|
||||
test_result |= run_minunit_test_infrared_decoder_encoder();
|
||||
|
@ -54,27 +54,24 @@ void subghz_file_encoder_worker_add_level_duration(
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_file_encoder_worker_data_parse(
|
||||
SubGhzFileEncoderWorker* instance,
|
||||
const char* strStart,
|
||||
size_t len) {
|
||||
bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) {
|
||||
char* str1;
|
||||
size_t ind_start = (size_t)strStart; //store the start address of the beginning of the line
|
||||
bool res = false;
|
||||
// Line sample: "RAW_Data: -1, 2, -2..."
|
||||
|
||||
// Look for a key in the line
|
||||
str1 = strstr(strStart, "RAW_Data: ");
|
||||
|
||||
str1 = strstr(
|
||||
strStart, "RAW_Data: "); //looking for the beginning of the desired title in the line
|
||||
if(str1 != NULL) {
|
||||
str1 = strchr(
|
||||
str1,
|
||||
' '); //if found, shift the pointer by 1 element per line "RAW_Data: -1, 2, -2..."
|
||||
while(
|
||||
strchr(str1, ' ') != NULL &&
|
||||
((size_t)str1 <
|
||||
(len +
|
||||
ind_start))) { //check that there is still an element in the line and that it has not gone beyond the line
|
||||
// Skip key
|
||||
str1 = strchr(str1, ' ');
|
||||
str1 += 1; //if found, shift the pointer by next element per line
|
||||
|
||||
// Check that there is still an element in the line
|
||||
while(strchr(str1, ' ') != NULL) {
|
||||
str1 = strchr(str1, ' ');
|
||||
|
||||
// Skip space
|
||||
str1 += 1;
|
||||
subghz_file_encoder_worker_add_level_duration(instance, atoi(str1));
|
||||
}
|
||||
res = true;
|
||||
@ -143,9 +140,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) {
|
||||
if(stream_read_line(stream, instance->str_data)) {
|
||||
string_strim(instance->str_data);
|
||||
if(!subghz_file_encoder_worker_data_parse(
|
||||
instance,
|
||||
string_get_cstr(instance->str_data),
|
||||
strlen(string_get_cstr(instance->str_data)))) {
|
||||
instance, string_get_cstr(instance->str_data))) {
|
||||
//to stop DMA correctly
|
||||
subghz_file_encoder_worker_add_level_duration(instance, LEVEL_DURATION_RESET);
|
||||
subghz_file_encoder_worker_add_level_duration(instance, LEVEL_DURATION_RESET);
|
||||
|
152
lib/toolbox/dir_walk.c
Normal file
152
lib/toolbox/dir_walk.c
Normal file
@ -0,0 +1,152 @@
|
||||
#include "dir_walk.h"
|
||||
#include <m-list.h>
|
||||
|
||||
LIST_DEF(DirIndexList, uint32_t);
|
||||
|
||||
struct DirWalk {
|
||||
File* file;
|
||||
string_t path;
|
||||
DirIndexList_t index_list;
|
||||
uint32_t current_index;
|
||||
bool recursive;
|
||||
DirWalkFilterCb filter_cb;
|
||||
void* filter_context;
|
||||
};
|
||||
|
||||
DirWalk* dir_walk_alloc(Storage* storage) {
|
||||
DirWalk* dir_walk = malloc(sizeof(DirWalk));
|
||||
string_init(dir_walk->path);
|
||||
dir_walk->file = storage_file_alloc(storage);
|
||||
DirIndexList_init(dir_walk->index_list);
|
||||
dir_walk->recursive = true;
|
||||
dir_walk->filter_cb = NULL;
|
||||
return dir_walk;
|
||||
}
|
||||
|
||||
void dir_walk_free(DirWalk* dir_walk) {
|
||||
storage_file_free(dir_walk->file);
|
||||
string_clear(dir_walk->path);
|
||||
DirIndexList_clear(dir_walk->index_list);
|
||||
free(dir_walk);
|
||||
}
|
||||
|
||||
void dir_walk_set_recursive(DirWalk* dir_walk, bool recursive) {
|
||||
dir_walk->recursive = recursive;
|
||||
}
|
||||
|
||||
void dir_walk_set_filter_cb(DirWalk* dir_walk, DirWalkFilterCb cb, void* context) {
|
||||
dir_walk->filter_cb = cb;
|
||||
dir_walk->filter_context = context;
|
||||
}
|
||||
|
||||
bool dir_walk_open(DirWalk* dir_walk, const char* path) {
|
||||
string_set(dir_walk->path, path);
|
||||
dir_walk->current_index = 0;
|
||||
return storage_dir_open(dir_walk->file, path);
|
||||
}
|
||||
|
||||
static bool dir_walk_filter(DirWalk* dir_walk, const char* name, FileInfo* fileinfo) {
|
||||
if(dir_walk->filter_cb) {
|
||||
return dir_walk->filter_cb(name, fileinfo, dir_walk->filter_context);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static DirWalkResult dir_walk_iter(DirWalk* dir_walk, string_t return_path, FileInfo* fileinfo) {
|
||||
DirWalkResult result = DirWalkError;
|
||||
char* name = malloc(256);
|
||||
FileInfo info;
|
||||
bool end = false;
|
||||
|
||||
while(!end) {
|
||||
storage_dir_read(dir_walk->file, &info, name, 255);
|
||||
|
||||
if(storage_file_get_error(dir_walk->file) == FSE_OK) {
|
||||
result = DirWalkOK;
|
||||
dir_walk->current_index++;
|
||||
|
||||
if(dir_walk_filter(dir_walk, name, &info)) {
|
||||
if(return_path != NULL) {
|
||||
string_printf(return_path, "%s/%s", string_get_cstr(dir_walk->path), name);
|
||||
}
|
||||
|
||||
if(fileinfo != NULL) {
|
||||
memcpy(fileinfo, &info, sizeof(FileInfo));
|
||||
}
|
||||
|
||||
end = true;
|
||||
}
|
||||
|
||||
if((info.flags & FSF_DIRECTORY) && dir_walk->recursive) {
|
||||
// step into
|
||||
DirIndexList_push_back(dir_walk->index_list, dir_walk->current_index);
|
||||
dir_walk->current_index = 0;
|
||||
storage_dir_close(dir_walk->file);
|
||||
|
||||
string_cat_printf(dir_walk->path, "/%s", name);
|
||||
storage_dir_open(dir_walk->file, string_get_cstr(dir_walk->path));
|
||||
}
|
||||
} else if(storage_file_get_error(dir_walk->file) == FSE_NOT_EXIST) {
|
||||
if(DirIndexList_size(dir_walk->index_list) == 0) {
|
||||
// last
|
||||
result = DirWalkLast;
|
||||
end = true;
|
||||
} else {
|
||||
// step out
|
||||
uint32_t index;
|
||||
DirIndexList_pop_back(&index, dir_walk->index_list);
|
||||
dir_walk->current_index = 0;
|
||||
|
||||
storage_dir_close(dir_walk->file);
|
||||
|
||||
size_t last_char = string_search_rchar(dir_walk->path, '/');
|
||||
if(last_char != STRING_FAILURE) {
|
||||
string_left(dir_walk->path, last_char);
|
||||
}
|
||||
|
||||
storage_dir_open(dir_walk->file, string_get_cstr(dir_walk->path));
|
||||
|
||||
// rewind
|
||||
while(true) {
|
||||
if(index == dir_walk->current_index) {
|
||||
result = DirWalkOK;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!storage_dir_read(dir_walk->file, &info, name, 255)) {
|
||||
result = DirWalkError;
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
|
||||
dir_walk->current_index++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = DirWalkError;
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
FS_Error dir_walk_get_error(DirWalk* dir_walk) {
|
||||
return storage_file_get_error(dir_walk->file);
|
||||
}
|
||||
|
||||
DirWalkResult dir_walk_read(DirWalk* dir_walk, string_t return_path, FileInfo* fileinfo) {
|
||||
return dir_walk_iter(dir_walk, return_path, fileinfo);
|
||||
}
|
||||
|
||||
void dir_walk_close(DirWalk* dir_walk) {
|
||||
if(storage_file_is_open(dir_walk->file)) {
|
||||
storage_dir_close(dir_walk->file);
|
||||
}
|
||||
|
||||
DirIndexList_reset(dir_walk->index_list);
|
||||
string_reset(dir_walk->path);
|
||||
dir_walk->current_index = 0;
|
||||
}
|
79
lib/toolbox/dir_walk.h
Normal file
79
lib/toolbox/dir_walk.h
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include <storage/storage.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DirWalk DirWalk;
|
||||
|
||||
typedef enum {
|
||||
DirWalkOK, /**< OK */
|
||||
DirWalkError, /**< Error */
|
||||
DirWalkLast, /**< Last element */
|
||||
} DirWalkResult;
|
||||
|
||||
typedef bool (*DirWalkFilterCb)(const char* name, FileInfo* fileinfo, void* ctx);
|
||||
|
||||
/**
|
||||
* Allocate DirWalk
|
||||
* @param storage
|
||||
* @return DirWalk*
|
||||
*/
|
||||
DirWalk* dir_walk_alloc(Storage* storage);
|
||||
|
||||
/**
|
||||
* Free DirWalk
|
||||
* @param dir_walk
|
||||
*/
|
||||
void dir_walk_free(DirWalk* dir_walk);
|
||||
|
||||
/**
|
||||
* Set recursive mode (true by default)
|
||||
* @param dir_walk
|
||||
* @param recursive
|
||||
*/
|
||||
void dir_walk_set_recursive(DirWalk* dir_walk, bool recursive);
|
||||
|
||||
/**
|
||||
* Set filter callback (Should return true if the data is valid)
|
||||
* @param dir_walk
|
||||
* @param cb
|
||||
* @param context
|
||||
*/
|
||||
void dir_walk_set_filter_cb(DirWalk* dir_walk, DirWalkFilterCb cb, void* context);
|
||||
|
||||
/**
|
||||
* Open directory
|
||||
* @param dir_walk
|
||||
* @param path
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool dir_walk_open(DirWalk* dir_walk, const char* path);
|
||||
|
||||
/**
|
||||
* Get error id
|
||||
* @param dir_walk
|
||||
* @return FS_Error
|
||||
*/
|
||||
FS_Error dir_walk_get_error(DirWalk* dir_walk);
|
||||
|
||||
/**
|
||||
* Read next element from directory
|
||||
* @param dir_walk
|
||||
* @param return_path
|
||||
* @param fileinfo
|
||||
* @return DirWalkResult
|
||||
*/
|
||||
DirWalkResult dir_walk_read(DirWalk* dir_walk, string_t return_path, FileInfo* fileinfo);
|
||||
|
||||
/**
|
||||
* Close directory
|
||||
* @param dir_walk
|
||||
*/
|
||||
void dir_walk_close(DirWalk* dir_walk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user