This commit is contained in:
Willy-JL
2023-03-04 02:55:19 +00:00
273 changed files with 6399 additions and 4441 deletions

View File

@@ -44,3 +44,6 @@
# Functions that always return the same error code # Functions that always return the same error code
//-V:picopass_device_decrypt:1048 //-V:picopass_device_decrypt:1048
# Examples
//V_EXCLUDE_PATH applications/examples/

View File

@@ -191,7 +191,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) {
size_t size = strlen(clean_dir) + strlen(name) + 1 + 1; size_t size = strlen(clean_dir) + strlen(name) + 1 + 1;
char* fullname = malloc(size); char* fullname = malloc(size);
snprintf(fullname, size, "%s/%s", clean_dir, name); snprintf(fullname, size, "%s/%s", clean_dir, name);
if(fileinfo.flags & FSF_DIRECTORY) { if(file_info_is_dir(&fileinfo)) {
clean_directory(fs_api, fullname); clean_directory(fs_api, fullname);
} }
FS_Error error = storage_common_remove(fs_api, fullname); FS_Error error = storage_common_remove(fs_api, fullname);
@@ -608,9 +608,8 @@ static void test_rpc_storage_list_create_expected_list(
} }
if(path_contains_only_ascii(name)) { if(path_contains_only_ascii(name)) {
list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_DIR : PB_Storage_File_FileType_FILE;
PB_Storage_File_FileType_FILE;
list->file[i].size = fileinfo.size; list->file[i].size = fileinfo.size;
list->file[i].data = NULL; list->file[i].data = NULL;
/* memory free inside rpc_encode_and_send() -> pb_release() */ /* memory free inside rpc_encode_and_send() -> pb_release() */
@@ -873,7 +872,7 @@ static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) {
if(error == FSE_OK) { if(error == FSE_OK) {
response->which_content = PB_Main_storage_stat_response_tag; response->which_content = PB_Main_storage_stat_response_tag;
response->content.storage_stat_response.has_file = true; response->content.storage_stat_response.has_file = true;
response->content.storage_stat_response.file.type = (fileinfo.flags & FSF_DIRECTORY) ? response->content.storage_stat_response.file.type = file_info_is_dir(&fileinfo) ?
PB_Storage_File_FileType_DIR : PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_FILE; PB_Storage_File_FileType_FILE;
response->content.storage_stat_response.file.size = fileinfo.size; response->content.storage_stat_response.file.size = fileinfo.size;

View File

@@ -179,7 +179,7 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) {
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/"))); furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
} }
dir_walk_free(dir_walk); dir_walk_free(dir_walk);
@@ -204,7 +204,7 @@ MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) {
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/"))); furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
} }
dir_walk_free(dir_walk); dir_walk_free(dir_walk);
@@ -219,7 +219,7 @@ static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* filein
UNUSED(ctx); UNUSED(ctx);
// only files // only files
if(!(fileinfo->flags & FSF_DIRECTORY)) { if(!file_info_is_dir(fileinfo)) {
// with ".test" in name // with ".test" in name
if(strstr(name, ".test") != NULL) { if(strstr(name, ".test") != NULL) {
return true; return true;
@@ -243,7 +243,7 @@ MU_TEST_1(test_dirwalk_filter, Storage* storage) {
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/"))); furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY))); mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
} }
dir_walk_free(dir_walk); dir_walk_free(dir_walk);

View File

@@ -2,9 +2,40 @@
#include <furi.h> #include <furi.h>
#include <storage/storage.h> #include <storage/storage.h>
// DO NOT USE THIS IN PRODUCTION CODE
// This is a hack to access internal storage functions and definitions
#include <storage/storage_i.h>
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test") #define STORAGE_LOCKED_FILE EXT_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")
static bool storage_file_create(Storage* storage, const char* path, const char* data) {
File* file = storage_file_alloc(storage);
bool result = false;
do {
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_NEW)) {
break;
}
if(storage_file_write(file, data, strlen(data)) != strlen(data)) {
break;
}
if(!storage_file_close(file)) {
break;
}
result = true;
} while(0);
storage_file_free(file);
return result;
}
static void storage_file_open_lock_setup() { static void storage_file_open_lock_setup() {
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);
@@ -115,7 +146,7 @@ static int32_t storage_dir_locker(void* ctx) {
File* file = storage_file_alloc(storage); File* file = storage_file_alloc(storage);
furi_check(storage_dir_open(file, STORAGE_LOCKED_DIR)); furi_check(storage_dir_open(file, STORAGE_LOCKED_DIR));
furi_semaphore_release(semaphore); furi_semaphore_release(semaphore);
furi_delay_ms(1000); furi_delay_ms(100);
furi_check(storage_dir_close(file)); furi_check(storage_dir_close(file));
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
@@ -152,9 +183,21 @@ MU_TEST(storage_dir_open_lock) {
mu_assert(result, "cannot open locked dir"); mu_assert(result, "cannot open locked dir");
} }
MU_TEST(storage_dir_exists_test) {
Storage* storage = furi_record_open(RECORD_STORAGE);
mu_check(!storage_dir_exists(storage, STORAGE_TEST_DIR));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, STORAGE_TEST_DIR));
mu_check(storage_dir_exists(storage, STORAGE_TEST_DIR));
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, STORAGE_TEST_DIR));
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(storage_dir) { MU_TEST_SUITE(storage_dir) {
MU_RUN_TEST(storage_dir_open_close); MU_RUN_TEST(storage_dir_open_close);
MU_RUN_TEST(storage_dir_open_lock); MU_RUN_TEST(storage_dir_open_lock);
MU_RUN_TEST(storage_dir_exists_test);
} }
static const char* const storage_copy_test_paths[] = { static const char* const storage_copy_test_paths[] = {
@@ -303,9 +346,256 @@ MU_TEST_SUITE(storage_rename) {
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
} }
#define APPSDATA_APP_PATH(path) APPS_DATA_PATH "/" path
static const char* storage_test_apps[] = {
"-_twilight_-",
"-_rainbow_-",
"-_pinkie_-",
"-_apple_-",
"-_flutter_-",
"-_rare_-",
};
static size_t storage_test_apps_count = COUNT_OF(storage_test_apps);
static int32_t storage_test_app(void* arg) {
UNUSED(arg);
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_remove(storage, "/app/test");
int32_t ret = storage_file_create(storage, "/app/test", "test");
furi_record_close(RECORD_STORAGE);
return ret;
}
MU_TEST(test_storage_data_path_apps) {
for(size_t i = 0; i < storage_test_apps_count; i++) {
FuriThread* thread =
furi_thread_alloc_ex(storage_test_apps[i], 1024, storage_test_app, NULL);
furi_thread_set_appid(thread, storage_test_apps[i]);
furi_thread_start(thread);
furi_thread_join(thread);
mu_assert_int_eq(true, furi_thread_get_return_code(thread));
// Check if app data dir and file exists
Storage* storage = furi_record_open(RECORD_STORAGE);
FuriString* expected = furi_string_alloc();
furi_string_printf(expected, APPSDATA_APP_PATH("%s"), storage_test_apps[i]);
mu_check(storage_dir_exists(storage, furi_string_get_cstr(expected)));
furi_string_cat(expected, "/test");
mu_check(storage_file_exists(storage, furi_string_get_cstr(expected)));
furi_string_printf(expected, APPSDATA_APP_PATH("%s"), storage_test_apps[i]);
storage_simply_remove_recursive(storage, furi_string_get_cstr(expected));
furi_record_close(RECORD_STORAGE);
furi_string_free(expected);
furi_thread_free(thread);
}
}
MU_TEST(test_storage_data_path) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
mu_check(storage_dir_open(file, "/app"));
mu_check(storage_dir_close(file));
storage_file_free(file);
// check that appsdata folder exists
mu_check(storage_dir_exists(storage, APPS_DATA_PATH));
// check that cli folder exists
mu_check(storage_dir_exists(storage, APPSDATA_APP_PATH("cli")));
storage_simply_remove(storage, APPSDATA_APP_PATH("cli"));
furi_record_close(RECORD_STORAGE);
}
MU_TEST(test_storage_common_migrate) {
Storage* storage = furi_record_open(RECORD_STORAGE);
// Setup test folders
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from non existing
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
// Test migration from existing folder to non existing
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file1"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file2.ext"), "test2"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file3.ext.ext"), "test3"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file1")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file2.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext.ext")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
// Test migration from existing folder to existing folder
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file1"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file2.ext"), "test2"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file3.ext.ext"), "test3"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file1")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file2.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file11")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file21.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext1.ext")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from empty folder to existing file
// Expected result: FSE_OK, folder removed, file untouched
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from empty folder to existing folder
// Expected result: FSE_OK, old folder removed, new folder untouched
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_new")));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from existing file to non existing, no extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from existing file to non existing, with extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old.file"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old.file"), UNIT_TESTS_PATH("migrate_new.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new.file")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old.file")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new.file"));
// Test migration from existing file to existing file, no extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new"), "test2"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1"));
// Test migration from existing file to existing file, with extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old.file"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new.file"), "test2"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old.file"), UNIT_TESTS_PATH("migrate_new.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new.file")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1.file")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1.file"));
// Test migration from existing file to existing folder
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_new")));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1"));
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(test_data_path) {
MU_RUN_TEST(test_storage_data_path);
MU_RUN_TEST(test_storage_data_path_apps);
}
MU_TEST_SUITE(test_storage_common) {
MU_RUN_TEST(test_storage_common_migrate);
}
int run_minunit_test_storage() { int run_minunit_test_storage() {
MU_RUN_SUITE(storage_file); MU_RUN_SUITE(storage_file);
MU_RUN_SUITE(storage_dir); MU_RUN_SUITE(storage_dir);
MU_RUN_SUITE(storage_rename); MU_RUN_SUITE(storage_rename);
MU_RUN_SUITE(test_data_path);
MU_RUN_SUITE(test_storage_common);
return MU_EXIT_CODE; return MU_EXIT_CODE;
} }

View File

@@ -0,0 +1,18 @@
# Apps Data folder Example
This example demonstrates how to utilize the Apps Data folder to store data that is not part of the app itself, such as user data, configuration files, and so forth.
## What is the Apps Data Folder?
The **Apps Data** folder is a folder used to store data for external apps that are not part of the main firmware.
The path to the current application folder is related to the `appid` of the app. The `appid` is used to identify the app in the app store and is stored in the `application.fam` file.
The Apps Data folder is located only on the external storage, the SD card.
For example, if the `appid` of the app is `snake_game`, the path to the Apps Data folder will be `/ext/apps_data/snake_game`. But using raw paths is not recommended, because the path to the Apps Data folder can change in the future. Use the `/app` alias instead.
## How to get the path to the Apps Data folder?
You can use `/app` alias to get the path to the current application data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `/app/config.txt`. But this way is not recommended, because even the `/app` alias can change in the future.
We recommend to use the `APP_DATA_PATH` macro to get the path to the Apps Data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `APP_DATA_PATH("config.txt")`.

View File

@@ -0,0 +1,9 @@
App(
appid="example_apps_data",
name="Example: Apps Data",
apptype=FlipperAppType.EXTERNAL,
entry_point="example_apps_data_main",
requires=["gui"],
stack_size=1 * 1024,
fap_category="Examples",
)

View File

@@ -0,0 +1,40 @@
#include <furi.h>
#include <storage/storage.h>
// Define log tag
#define TAG "example_apps_data"
// Application entry point
int32_t example_apps_data_main(void* p) {
// Mark argument as unused
UNUSED(p);
// Open storage
Storage* storage = furi_record_open(RECORD_STORAGE);
// Allocate file
File* file = storage_file_alloc(storage);
// Get the path to the current application data folder
// That is: /ext/apps_data/<app_name>
// And it will create folders in the path if they don't exist
// In this example it will create /ext/apps_data/example_apps_data
// And file will be /ext/apps_data/example_apps_data/test.txt
// Open file, write data and close it
if(!storage_file_open(file, APP_DATA_PATH("test.txt"), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
FURI_LOG_E(TAG, "Failed to open file");
}
if(!storage_file_write(file, "Hello World!", strlen("Hello World!"))) {
FURI_LOG_E(TAG, "Failed to write to file");
}
storage_file_close(file);
// Deallocate file
storage_file_free(file);
// Close storage
furi_record_close(RECORD_STORAGE);
return 0;
}

View File

@@ -451,7 +451,7 @@ static bool archive_is_dir_exists(FuriString* path) {
FileInfo file_info; FileInfo file_info;
Storage* storage = furi_record_open(RECORD_STORAGE); Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) {
if(file_info.flags & FSF_DIRECTORY) { if(file_info_is_dir(&file_info)) {
state = true; state = true;
} }
} }
@@ -532,12 +532,16 @@ void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) {
browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false);
furi_string_set(browser->path, path); furi_string_set(browser->path, path);
file_browser_worker_folder_enter(browser->worker, path, idx_temp); file_browser_worker_folder_enter(browser->worker, path, idx_temp);
} }
void archive_leave_dir(ArchiveBrowserView* browser) { void archive_leave_dir(ArchiveBrowserView* browser) {
furi_assert(browser); furi_assert(browser);
size_t dirname_start = furi_string_search_rchar(browser->path, '/');
furi_string_left(browser->path, dirname_start);
file_browser_worker_folder_exit(browser->worker); file_browser_worker_folder_exit(browser->worker);
} }

View File

@@ -160,7 +160,7 @@ bool archive_favorites_read(void* context) {
if(storage_file_exists(storage, furi_string_get_cstr(buffer))) { if(storage_file_exists(storage, furi_string_get_cstr(buffer))) {
storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info); storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info);
archive_add_file_item( archive_add_file_item(
browser, (file_info.flags & FSF_DIRECTORY), furi_string_get_cstr(buffer)); browser, file_info_is_dir(&file_info), furi_string_get_cstr(buffer));
file_count++; file_count++;
} else { } else {
need_refresh = true; need_refresh = true;

View File

@@ -96,7 +96,7 @@ void archive_delete_file(void* context, const char* format, ...) {
bool res = false; bool res = false;
if(fileinfo.flags & FSF_DIRECTORY) { if(file_info_is_dir(&fileinfo)) {
res = storage_simply_remove_recursive(fs_api, furi_string_get_cstr(filename)); res = storage_simply_remove_recursive(fs_api, furi_string_get_cstr(filename));
} else { } else {
res = (storage_common_remove(fs_api, furi_string_get_cstr(filename)) == FSE_OK); res = (storage_common_remove(fs_api, furi_string_get_cstr(filename)) == FSE_OK);

View File

@@ -5,6 +5,7 @@
#include <storage/storage.h> #include <storage/storage.h>
#include <gui/modules/loading.h> #include <gui/modules/loading.h>
#include <dialogs/dialogs.h> #include <dialogs/dialogs.h>
#include <toolbox/path.h>
#include <flipper_application/flipper_application.h> #include <flipper_application/flipper_application.h>
#include "elf_cpp/elf_hashtable.h" #include "elf_cpp/elf_hashtable.h"
#include "fap_loader_app.h" #include "fap_loader_app.h"
@@ -105,6 +106,12 @@ static bool fap_loader_run_selected_app(FapLoader* loader) {
FURI_LOG_I(TAG, "FAP Loader is starting app"); FURI_LOG_I(TAG, "FAP Loader is starting app");
FuriThread* thread = flipper_application_spawn(loader->app, NULL); FuriThread* thread = flipper_application_spawn(loader->app, NULL);
FuriString* app_name = furi_string_alloc();
path_extract_filename_no_ext(furi_string_get_cstr(loader->fap_path), app_name);
furi_thread_set_appid(thread, furi_string_get_cstr(app_name));
furi_string_free(app_name);
furi_thread_start(thread); furi_thread_start(thread);
furi_thread_join(thread); furi_thread_join(thread);

View File

@@ -1,10 +1,6 @@
#include "ibutton.h"
#include "assets_icons.h"
#include "ibutton_i.h" #include "ibutton_i.h"
#include "ibutton/scenes/ibutton_scene.h"
#include <toolbox/path.h> #include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
#include <rpc/rpc_app.h>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#define TAG "iButtonApp" #define TAG "iButtonApp"
@@ -34,50 +30,13 @@ static const NotificationSequence* ibutton_notification_sequences[] = {
}; };
static void ibutton_make_app_folder(iButton* ibutton) { static void ibutton_make_app_folder(iButton* ibutton) {
if(!storage_simply_mkdir(ibutton->storage, IBUTTON_APP_FOLDER)) { Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, IBUTTON_APP_FOLDER)) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot create\napp folder"); dialog_message_show_storage_error(ibutton->dialogs, "Cannot create\napp folder");
} }
}
bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog) { furi_record_close(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
bool result = false;
FuriString* data;
data = furi_string_alloc();
do {
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(key_path))) break;
// header
uint32_t version;
if(!flipper_format_read_header(file, data, &version)) break;
if(furi_string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break;
if(version != 1) break;
// key type
iButtonKeyType type;
if(!flipper_format_read_string(file, "Key type", data)) break;
if(!ibutton_key_get_type_by_string(furi_string_get_cstr(data), &type)) break;
// key data
uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0};
if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type)))
break;
ibutton_key_set_type(ibutton->key, type);
ibutton_key_set_data(ibutton->key, key_data, IBUTTON_KEY_DATA_SIZE);
result = true;
} while(false);
flipper_format_free(file);
furi_string_free(data);
if((!result) && (show_dialog)) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
}
return result;
} }
static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) { static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) {
@@ -87,14 +46,14 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context)
if(event == RpcAppEventSessionClose) { if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
ibutton->rpc_ctx = NULL; ibutton->rpc = NULL;
} else if(event == RpcAppEventAppExit) { } else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit);
} else if(event == RpcAppEventLoadFile) { } else if(event == RpcAppEventLoadFile) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad); view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad);
} else { } else {
rpc_system_app_confirm(ibutton->rpc_ctx, event, false); rpc_system_app_confirm(ibutton->rpc, event, false);
} }
} }
@@ -135,13 +94,13 @@ iButton* ibutton_alloc() {
ibutton->gui = furi_record_open(RECORD_GUI); ibutton->gui = furi_record_open(RECORD_GUI);
ibutton->storage = furi_record_open(RECORD_STORAGE);
ibutton->dialogs = furi_record_open(RECORD_DIALOGS); ibutton->dialogs = furi_record_open(RECORD_DIALOGS);
ibutton->notifications = furi_record_open(RECORD_NOTIFICATION); ibutton->notifications = furi_record_open(RECORD_NOTIFICATION);
ibutton->key = ibutton_key_alloc(); ibutton->protocols = ibutton_protocols_alloc();
ibutton->key_worker = ibutton_worker_alloc(); ibutton->key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(ibutton->protocols));
ibutton_worker_start_thread(ibutton->key_worker); ibutton->worker = ibutton_worker_alloc(ibutton->protocols);
ibutton_worker_start_thread(ibutton->worker);
ibutton->submenu = submenu_alloc(); ibutton->submenu = submenu_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
@@ -163,9 +122,9 @@ iButton* ibutton_alloc() {
view_dispatcher_add_view( view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewWidget, widget_get_view(ibutton->widget)); ibutton->view_dispatcher, iButtonViewWidget, widget_get_view(ibutton->widget));
ibutton->dialog_ex = dialog_ex_alloc(); ibutton->loading = loading_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewDialogEx, dialog_ex_get_view(ibutton->dialog_ex)); ibutton->view_dispatcher, iButtonViewLoading, loading_get_view(ibutton->loading));
return ibutton; return ibutton;
} }
@@ -173,8 +132,8 @@ iButton* ibutton_alloc() {
void ibutton_free(iButton* ibutton) { void ibutton_free(iButton* ibutton) {
furi_assert(ibutton); furi_assert(ibutton);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewDialogEx); view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewLoading);
dialog_ex_free(ibutton->dialog_ex); loading_free(ibutton->loading);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewWidget); view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewWidget);
widget_free(ibutton->widget); widget_free(ibutton->widget);
@@ -194,9 +153,6 @@ void ibutton_free(iButton* ibutton) {
view_dispatcher_free(ibutton->view_dispatcher); view_dispatcher_free(ibutton->view_dispatcher);
scene_manager_free(ibutton->scene_manager); scene_manager_free(ibutton->scene_manager);
furi_record_close(RECORD_STORAGE);
ibutton->storage = NULL;
furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_NOTIFICATION);
ibutton->notifications = NULL; ibutton->notifications = NULL;
@@ -206,103 +162,83 @@ void ibutton_free(iButton* ibutton) {
furi_record_close(RECORD_GUI); furi_record_close(RECORD_GUI);
ibutton->gui = NULL; ibutton->gui = NULL;
ibutton_worker_stop_thread(ibutton->key_worker); ibutton_worker_stop_thread(ibutton->worker);
ibutton_worker_free(ibutton->key_worker); ibutton_worker_free(ibutton->worker);
ibutton_key_free(ibutton->key); ibutton_key_free(ibutton->key);
ibutton_protocols_free(ibutton->protocols);
furi_string_free(ibutton->file_path); furi_string_free(ibutton->file_path);
free(ibutton); free(ibutton);
} }
bool ibutton_file_select(iButton* ibutton) { bool ibutton_load_key(iButton* ibutton) {
DialogsFileBrowserOptions browser_options; view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
browser_options.base_path = IBUTTON_APP_FOLDER;
bool success = dialog_file_browser_show( const bool success = ibutton_protocols_load(
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options); ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
if(success) { if(!success) {
success = ibutton_load_key_data(ibutton, ibutton->file_path, true); dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
} else {
FuriString* tmp = furi_string_alloc();
path_extract_filename(ibutton->file_path, tmp, true);
strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
furi_string_free(tmp);
} }
return success; return success;
} }
bool ibutton_save_key(iButton* ibutton, const char* key_name) { bool ibutton_select_and_load_key(iButton* ibutton) {
// Create ibutton directory if necessary DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
browser_options.base_path = IBUTTON_APP_FOLDER;
if(furi_string_empty(ibutton->file_path)) {
furi_string_set(ibutton->file_path, browser_options.base_path);
}
return dialog_file_browser_show(
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options) &&
ibutton_load_key(ibutton);
}
bool ibutton_save_key(iButton* ibutton) {
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
ibutton_make_app_folder(ibutton); ibutton_make_app_folder(ibutton);
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
const bool success =
ibutton_protocols_save(ibutton->protocols, key, furi_string_get_cstr(ibutton->file_path));
bool result = false; if(!success) {
do {
// Check if we has old key
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
// First remove old key
ibutton_delete_key(ibutton);
// Remove old key name from path
size_t filename_start = furi_string_search_rchar(ibutton->file_path, '/');
furi_string_left(ibutton->file_path, filename_start);
}
furi_string_cat_printf(ibutton->file_path, "/%s%s", key_name, IBUTTON_APP_EXTENSION);
// Open file for write
if(!flipper_format_file_open_always(file, furi_string_get_cstr(ibutton->file_path))) break;
// Write header
if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break;
// Write key type
if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom"))
break;
const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key));
if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break;
// Write data
if(!flipper_format_write_comment_cstr(
file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8"))
break;
if(!flipper_format_write_hex(
file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)))
break;
result = true;
} while(false);
flipper_format_free(file);
if(!result) { //-V547
dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file"); dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file");
} }
return result; return success;
} }
bool ibutton_delete_key(iButton* ibutton) { bool ibutton_delete_key(iButton* ibutton) {
bool result = false; bool result = false;
result = storage_simply_remove(ibutton->storage, furi_string_get_cstr(ibutton->file_path));
Storage* storage = furi_record_open(RECORD_STORAGE);
result = storage_simply_remove(storage, furi_string_get_cstr(ibutton->file_path));
furi_record_close(RECORD_STORAGE);
ibutton_reset_key(ibutton);
return result; return result;
} }
void ibutton_text_store_set(iButton* ibutton, const char* text, ...) { void ibutton_reset_key(iButton* ibutton) {
va_list args; memset(ibutton->key_name, 0, IBUTTON_KEY_NAME_SIZE + 1);
va_start(args, text); furi_string_reset(ibutton->file_path);
ibutton_key_reset(ibutton->key);
vsnprintf(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE, text, args);
va_end(args);
}
void ibutton_text_store_clear(iButton* ibutton) {
memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE + 1);
} }
void ibutton_notification_message(iButton* ibutton, uint32_t message) { void ibutton_notification_message(iButton* ibutton, uint32_t message) {
@@ -310,36 +246,44 @@ void ibutton_notification_message(iButton* ibutton, uint32_t message) {
notification_message(ibutton->notifications, ibutton_notification_sequences[message]); notification_message(ibutton->notifications, ibutton_notification_sequences[message]);
} }
int32_t ibutton_app(void* p) { void ibutton_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_widget_callback(GuiButtonType result, InputType type, void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
int32_t ibutton_app(void* arg) {
iButton* ibutton = ibutton_alloc(); iButton* ibutton = ibutton_alloc();
ibutton_make_app_folder(ibutton); ibutton_make_app_folder(ibutton);
bool key_loaded = false; bool key_loaded = false;
bool rpc_mode = false;
if(p && strlen(p)) { if((arg != NULL) && (strlen(arg) != 0)) {
uint32_t rpc_ctx = 0; if(sscanf(arg, "RPC %lX", (uint32_t*)&ibutton->rpc) == 1) {
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
FURI_LOG_D(TAG, "Running in RPC mode"); FURI_LOG_D(TAG, "Running in RPC mode");
ibutton->rpc_ctx = (void*)rpc_ctx;
rpc_mode = true; rpc_system_app_set_callback(ibutton->rpc, ibutton_rpc_command_callback, ibutton);
rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton); rpc_system_app_send_started(ibutton->rpc);
rpc_system_app_send_started(ibutton->rpc_ctx);
} else { } else {
furi_string_set(ibutton->file_path, (const char*)p); furi_string_set(ibutton->file_path, (const char*)arg);
if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) { key_loaded = ibutton_load_key(ibutton);
key_loaded = true;
// TODO: Display an error if the key from p could not be loaded
}
} }
} }
if(rpc_mode) { if(ibutton->rpc != NULL) {
view_dispatcher_attach_to_gui( view_dispatcher_attach_to_gui(
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate); DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else { } else {
view_dispatcher_attach_to_gui( view_dispatcher_attach_to_gui(
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
@@ -353,9 +297,9 @@ int32_t ibutton_app(void* p) {
view_dispatcher_run(ibutton->view_dispatcher); view_dispatcher_run(ibutton->view_dispatcher);
if(ibutton->rpc_ctx) { if(ibutton->rpc) {
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
rpc_system_app_send_exited(ibutton->rpc_ctx); rpc_system_app_send_exited(ibutton->rpc);
} }
ibutton_free(ibutton); ibutton_free(ibutton);
return 0; return 0;

View File

@@ -1,11 +1,15 @@
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <stdarg.h>
#include <cli/cli.h> #include <cli/cli.h>
#include <lib/toolbox/args.h> #include <toolbox/args.h>
#include <one_wire/ibutton/ibutton_worker.h>
#include <one_wire/one_wire_host.h> #include <one_wire/one_wire_host.h>
#include <one_wire/ibutton/ibutton_key.h>
#include <one_wire/ibutton/ibutton_worker.h>
#include <one_wire/ibutton/ibutton_protocols.h>
static void ibutton_cli(Cli* cli, FuriString* args, void* context); static void ibutton_cli(Cli* cli, FuriString* args, void* context);
static void onewire_cli(Cli* cli, FuriString* args, void* context); static void onewire_cli(Cli* cli, FuriString* args, void* context);
@@ -22,7 +26,7 @@ void ibutton_on_system_start() {
#endif #endif
} }
void ibutton_cli_print_usage() { static void ibutton_cli_print_usage() {
printf("Usage:\r\n"); printf("Usage:\r\n");
printf("ikey read\r\n"); printf("ikey read\r\n");
printf("ikey emulate <key_type> <key_data>\r\n"); printf("ikey emulate <key_type> <key_data>\r\n");
@@ -34,30 +38,52 @@ void ibutton_cli_print_usage() {
printf("\t<key_data> are hex-formatted\r\n"); printf("\t<key_data> are hex-formatted\r\n");
}; };
bool ibutton_cli_get_key_type(FuriString* data, iButtonKeyType* type) { static bool ibutton_cli_parse_key(iButtonProtocols* protocols, iButtonKey* key, FuriString* args) {
bool result = false; bool result = false;
FuriString* name = furi_string_alloc();
if(furi_string_cmp_str(data, "Dallas") == 0 || furi_string_cmp_str(data, "dallas") == 0) { do {
result = true; // Read protocol name
*type = iButtonKeyDS1990; if(!args_read_string_and_trim(args, name)) break;
} else if(furi_string_cmp_str(data, "Cyfral") == 0 || furi_string_cmp_str(data, "cyfral") == 0) {
result = true;
*type = iButtonKeyCyfral;
} else if(furi_string_cmp_str(data, "Metakom") == 0 || furi_string_cmp_str(data, "metakom") == 0) {
result = true;
*type = iButtonKeyMetakom;
}
// Make the protocol name uppercase
const char first = furi_string_get_char(name, 0);
furi_string_set_char(name, 0, toupper((int)first));
const iButtonProtocolId id =
ibutton_protocols_get_id_by_name(protocols, furi_string_get_cstr(name));
if(id == iButtonProtocolIdInvalid) break;
ibutton_key_set_protocol_id(key, id);
// Get the data pointer
iButtonEditableData data;
ibutton_protocols_get_editable_data(protocols, key, &data);
// Read data
if(!args_read_hex_bytes(args, data.ptr, data.size)) break;
result = true;
} while(false);
furi_string_free(name);
return result; return result;
} }
void ibutton_cli_print_key_data(iButtonKey* key) { static void ibutton_cli_print_key(iButtonProtocols* protocols, iButtonKey* key) {
const uint8_t* key_data = ibutton_key_get_data_p(key); const char* name = ibutton_protocols_get_name(protocols, ibutton_key_get_protocol_id(key));
iButtonKeyType type = ibutton_key_get_type(key);
printf("%s ", ibutton_key_get_string_by_type(type)); if(strncmp(name, "DS", 2) == 0) {
for(size_t i = 0; i < ibutton_key_get_size_by_type(type); i++) { name = "Dallas";
printf("%02X", key_data[i]); }
printf("%s ", name);
iButtonEditableData data;
ibutton_protocols_get_editable_data(protocols, key, &data);
for(size_t i = 0; i < data.size; i++) {
printf("%02X", data.ptr[i]);
} }
printf("\r\n"); printf("\r\n");
@@ -71,9 +97,10 @@ static void ibutton_cli_worker_read_cb(void* context) {
furi_event_flag_set(event, EVENT_FLAG_IBUTTON_COMPLETE); furi_event_flag_set(event, EVENT_FLAG_IBUTTON_COMPLETE);
} }
void ibutton_cli_read(Cli* cli) { static void ibutton_cli_read(Cli* cli) {
iButtonKey* key = ibutton_key_alloc(); iButtonProtocols* protocols = ibutton_protocols_alloc();
iButtonWorker* worker = ibutton_worker_alloc(); iButtonWorker* worker = ibutton_worker_alloc(protocols);
iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols));
FuriEventFlag* event = furi_event_flag_alloc(); FuriEventFlag* event = furi_event_flag_alloc();
ibutton_worker_start_thread(worker); ibutton_worker_start_thread(worker);
@@ -81,32 +108,25 @@ void ibutton_cli_read(Cli* cli) {
printf("Reading iButton...\r\nPress Ctrl+C to abort\r\n"); printf("Reading iButton...\r\nPress Ctrl+C to abort\r\n");
ibutton_worker_read_start(worker, key); ibutton_worker_read_start(worker, key);
while(true) { while(true) {
uint32_t flags = uint32_t flags =
furi_event_flag_wait(event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100); furi_event_flag_wait(event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100);
if(flags & EVENT_FLAG_IBUTTON_COMPLETE) { if(flags & EVENT_FLAG_IBUTTON_COMPLETE) {
ibutton_cli_print_key_data(key); ibutton_cli_print_key(protocols, key);
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) {
printf("Warning: invalid CRC\r\n");
}
if(!ibutton_key_dallas_is_1990_key(key)) {
printf("Warning: not a key\r\n");
}
}
break; break;
} }
if(cli_cmd_interrupt_received(cli)) break; if(cli_cmd_interrupt_received(cli)) break;
} }
ibutton_worker_stop(worker);
ibutton_worker_stop(worker);
ibutton_worker_stop_thread(worker); ibutton_worker_stop_thread(worker);
ibutton_worker_free(worker);
ibutton_key_free(key); ibutton_key_free(key);
ibutton_worker_free(worker);
ibutton_protocols_free(protocols);
furi_event_flag_free(event); furi_event_flag_free(event);
}; };
@@ -124,48 +144,33 @@ static void ibutton_cli_worker_write_cb(void* context, iButtonWorkerWriteResult
} }
void ibutton_cli_write(Cli* cli, FuriString* args) { void ibutton_cli_write(Cli* cli, FuriString* args) {
iButtonKey* key = ibutton_key_alloc(); iButtonProtocols* protocols = ibutton_protocols_alloc();
iButtonWorker* worker = ibutton_worker_alloc(); iButtonWorker* worker = ibutton_worker_alloc(protocols);
iButtonKeyType type; iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols));
iButtonWriteContext write_context;
uint8_t key_data[IBUTTON_KEY_DATA_SIZE];
FuriString* data;
iButtonWriteContext write_context;
write_context.event = furi_event_flag_alloc(); write_context.event = furi_event_flag_alloc();
data = furi_string_alloc();
ibutton_worker_start_thread(worker); ibutton_worker_start_thread(worker);
ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context); ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context);
do { do {
if(!args_read_string_and_trim(args, data)) { if(!ibutton_cli_parse_key(protocols, key, args)) {
ibutton_cli_print_usage(); ibutton_cli_print_usage();
break; break;
} }
if(!ibutton_cli_get_key_type(data, &type)) { if(!(ibutton_protocols_get_features(protocols, ibutton_key_get_protocol_id(key)) &
iButtonProtocolFeatureWriteBlank)) {
ibutton_cli_print_usage(); ibutton_cli_print_usage();
break; break;
} }
if(type != iButtonKeyDS1990) {
ibutton_cli_print_usage();
break;
}
if(!args_read_hex_bytes(args, key_data, ibutton_key_get_size_by_type(type))) {
ibutton_cli_print_usage();
break;
}
ibutton_key_set_type(key, type);
ibutton_key_set_data(key, key_data, ibutton_key_get_size_by_type(type));
printf("Writing key "); printf("Writing key ");
ibutton_cli_print_key_data(key); ibutton_cli_print_key(protocols, key);
printf("Press Ctrl+C to abort\r\n"); printf("Press Ctrl+C to abort\r\n");
ibutton_worker_write_start(worker, key); ibutton_worker_write_blank_start(worker, key);
while(true) { while(true) {
uint32_t flags = furi_event_flag_wait( uint32_t flags = furi_event_flag_wait(
write_context.event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100); write_context.event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100);
@@ -183,64 +188,53 @@ void ibutton_cli_write(Cli* cli, FuriString* args) {
if(cli_cmd_interrupt_received(cli)) break; if(cli_cmd_interrupt_received(cli)) break;
} }
ibutton_worker_stop(worker);
} while(false); } while(false);
furi_string_free(data); ibutton_worker_stop(worker);
ibutton_worker_stop_thread(worker); ibutton_worker_stop_thread(worker);
ibutton_worker_free(worker);
ibutton_key_free(key); ibutton_key_free(key);
ibutton_worker_free(worker);
ibutton_protocols_free(protocols);
furi_event_flag_free(write_context.event); furi_event_flag_free(write_context.event);
}; }
void ibutton_cli_emulate(Cli* cli, FuriString* args) { void ibutton_cli_emulate(Cli* cli, FuriString* args) {
iButtonKey* key = ibutton_key_alloc(); iButtonProtocols* protocols = ibutton_protocols_alloc();
iButtonWorker* worker = ibutton_worker_alloc(); iButtonWorker* worker = ibutton_worker_alloc(protocols);
iButtonKeyType type; iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols));
uint8_t key_data[IBUTTON_KEY_DATA_SIZE];
FuriString* data;
data = furi_string_alloc();
ibutton_worker_start_thread(worker); ibutton_worker_start_thread(worker);
do { do {
if(!args_read_string_and_trim(args, data)) { if(!ibutton_cli_parse_key(protocols, key, args)) {
ibutton_cli_print_usage(); ibutton_cli_print_usage();
break; break;
} }
if(!ibutton_cli_get_key_type(data, &type)) {
ibutton_cli_print_usage();
break;
}
if(!args_read_hex_bytes(args, key_data, ibutton_key_get_size_by_type(type))) {
ibutton_cli_print_usage();
break;
}
ibutton_key_set_type(key, type);
ibutton_key_set_data(key, key_data, ibutton_key_get_size_by_type(type));
printf("Emulating key "); printf("Emulating key ");
ibutton_cli_print_key_data(key); ibutton_cli_print_key(protocols, key);
printf("Press Ctrl+C to abort\r\n"); printf("Press Ctrl+C to abort\r\n");
ibutton_worker_emulate_start(worker, key); ibutton_worker_emulate_start(worker, key);
while(!cli_cmd_interrupt_received(cli)) { while(!cli_cmd_interrupt_received(cli)) {
furi_delay_ms(100); furi_delay_ms(100);
}; };
ibutton_worker_stop(worker);
} while(false); } while(false);
furi_string_free(data); ibutton_worker_stop(worker);
ibutton_worker_stop_thread(worker); ibutton_worker_stop_thread(worker);
ibutton_worker_free(worker);
ibutton_key_free(key); ibutton_key_free(key);
ibutton_worker_free(worker);
ibutton_protocols_free(protocols);
}; };
static void ibutton_cli(Cli* cli, FuriString* args, void* context) { void ibutton_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context); UNUSED(context);
FuriString* cmd; FuriString* cmd;
cmd = furi_string_alloc(); cmd = furi_string_alloc();
@@ -264,7 +258,7 @@ static void ibutton_cli(Cli* cli, FuriString* args, void* context) {
furi_string_free(cmd); furi_string_free(cmd);
} }
void onewire_cli_print_usage() { static void onewire_cli_print_usage() {
printf("Usage:\r\n"); printf("Usage:\r\n");
printf("onewire search\r\n"); printf("onewire search\r\n");
}; };
@@ -281,7 +275,7 @@ static void onewire_cli_search(Cli* cli) {
furi_hal_power_enable_otg(); furi_hal_power_enable_otg();
while(!done) { while(!done) {
if(onewire_host_search(onewire, address, NORMAL_SEARCH) != 1) { if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
printf("Search finished\r\n"); printf("Search finished\r\n");
onewire_host_reset_search(onewire); onewire_host_reset_search(onewire);
done = true; done = true;

View File

@@ -6,6 +6,7 @@ enum iButtonCustomEvent {
iButtonCustomEventBack, iButtonCustomEventBack,
iButtonCustomEventTextEditResult, iButtonCustomEventTextEditResult,
iButtonCustomEventByteEditChanged,
iButtonCustomEventByteEditResult, iButtonCustomEventByteEditResult,
iButtonCustomEventWorkerEmulated, iButtonCustomEventWorkerEmulated,
iButtonCustomEventWorkerRead, iButtonCustomEventWorkerRead,

View File

@@ -4,31 +4,40 @@
#include <gui/gui.h> #include <gui/gui.h>
#include <gui/view.h> #include <gui/view.h>
#include <assets_icons.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h> #include <gui/scene_manager.h>
#include <notification/notification_messages.h> #include <gui/view_dispatcher.h>
#include <one_wire/ibutton/ibutton_worker.h> #include <one_wire/ibutton/ibutton_worker.h>
#include <one_wire/ibutton/ibutton_protocols.h>
#include <rpc/rpc_app.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <dialogs/dialogs.h> #include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h> #include <gui/modules/submenu.h>
#include <gui/modules/popup.h> #include <gui/modules/popup.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/text_input.h> #include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h> #include <gui/modules/byte_input.h>
#include <gui/modules/widget.h> #include <gui/modules/widget.h>
#include <gui/modules/loading.h>
#include <assets_icons.h>
#include "ibutton_custom_event.h" #include "ibutton_custom_event.h"
#include "scenes/ibutton_scene.h" #include "scenes/ibutton_scene.h"
#define IBUTTON_FILE_NAME_SIZE 100
#define IBUTTON_TEXT_STORE_SIZE 128
#define IBUTTON_APP_FOLDER ANY_PATH("ibutton") #define IBUTTON_APP_FOLDER ANY_PATH("ibutton")
#define IBUTTON_APP_EXTENSION ".ibtn" #define IBUTTON_APP_EXTENSION ".ibtn"
#define IBUTTON_APP_FILE_TYPE "Flipper iButton key"
#define IBUTTON_KEY_NAME_SIZE 22
typedef enum {
iButtonWriteModeInvalid,
iButtonWriteModeBlank,
iButtonWriteModeCopy,
} iButtonWriteMode;
struct iButton { struct iButton {
SceneManager* scene_manager; SceneManager* scene_manager;
@@ -38,21 +47,22 @@ struct iButton {
Storage* storage; Storage* storage;
DialogsApp* dialogs; DialogsApp* dialogs;
NotificationApp* notifications; NotificationApp* notifications;
RpcAppSystem* rpc;
iButtonWorker* key_worker;
iButtonKey* key; iButtonKey* key;
iButtonWorker* worker;
iButtonProtocols* protocols;
iButtonWriteMode write_mode;
FuriString* file_path; FuriString* file_path;
char text_store[IBUTTON_TEXT_STORE_SIZE + 1]; char key_name[IBUTTON_KEY_NAME_SIZE + 1];
Submenu* submenu; Submenu* submenu;
ByteInput* byte_input; ByteInput* byte_input;
TextInput* text_input; TextInput* text_input;
Popup* popup; Popup* popup;
Widget* widget; Widget* widget;
DialogEx* dialog_ex; Loading* loading;
void* rpc_ctx;
}; };
typedef enum { typedef enum {
@@ -61,7 +71,7 @@ typedef enum {
iButtonViewTextInput, iButtonViewTextInput,
iButtonViewPopup, iButtonViewPopup,
iButtonViewWidget, iButtonViewWidget,
iButtonViewDialogEx, iButtonViewLoading,
} iButtonView; } iButtonView;
typedef enum { typedef enum {
@@ -78,10 +88,12 @@ typedef enum {
iButtonNotificationMessageBlinkStop, iButtonNotificationMessageBlinkStop,
} iButtonNotificationMessage; } iButtonNotificationMessage;
bool ibutton_file_select(iButton* ibutton); bool ibutton_select_and_load_key(iButton* ibutton);
bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog); bool ibutton_load_key(iButton* ibutton);
bool ibutton_save_key(iButton* ibutton, const char* key_name); bool ibutton_save_key(iButton* ibutton);
bool ibutton_delete_key(iButton* ibutton); bool ibutton_delete_key(iButton* ibutton);
void ibutton_text_store_set(iButton* ibutton, const char* text, ...); void ibutton_reset_key(iButton* ibutton);
void ibutton_text_store_clear(iButton* ibutton);
void ibutton_notification_message(iButton* ibutton, uint32_t message); void ibutton_notification_message(iButton* ibutton, uint32_t message);
void ibutton_submenu_callback(void* context, uint32_t index);
void ibutton_widget_callback(GuiButtonType result, InputType type, void* context);

View File

@@ -1,54 +1,57 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
enum SubmenuIndex {
SubmenuIndexCyfral,
SubmenuIndexDallas,
SubmenuIndexMetakom,
};
void ibutton_scene_add_type_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_add_type_on_enter(void* context) { void ibutton_scene_add_type_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Submenu* submenu = ibutton->submenu; Submenu* submenu = ibutton->submenu;
submenu_add_item( FuriString* tmp = furi_string_alloc();
submenu, "Cyfral", SubmenuIndexCyfral, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_add_item(
submenu, "Dallas", SubmenuIndexDallas, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_add_item(
submenu, "Metakom", SubmenuIndexMetakom, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_set_selected_item( for(uint32_t protocol_id = 0; protocol_id < ibutton_protocols_get_protocol_count();
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType)); ++protocol_id) {
if((strcmp(
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
ibutton_protocols_get_name(ibutton->protocols, protocol_id)) != 0) &&
(strcmp(ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), "N/A") !=
0)) {
furi_string_printf(
tmp,
"%s %s",
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id),
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
} else {
furi_string_printf(
tmp, "%s", ibutton_protocols_get_name(ibutton->protocols, protocol_id));
}
submenu_add_item(
submenu, furi_string_get_cstr(tmp), protocol_id, ibutton_submenu_callback, context);
}
const uint32_t prev_protocol_id =
scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType);
submenu_set_selected_item(submenu, prev_protocol_id);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
furi_string_free(tmp);
} }
bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context; iButton* ibutton = context;
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, event.event); const iButtonProtocolId protocol_id = event.event;
consumed = true;
if(event.event == SubmenuIndexCyfral) {
ibutton_key_set_type(key, iButtonKeyCyfral);
} else if(event.event == SubmenuIndexDallas) {
ibutton_key_set_type(key, iButtonKeyDS1990);
} else if(event.event == SubmenuIndexMetakom) {
ibutton_key_set_type(key, iButtonKeyMetakom);
} else {
furi_crash("Unknown key type");
}
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); ibutton_key_reset(key);
ibutton_key_clear_data(key); ibutton_key_set_protocol_id(key, protocol_id);
ibutton_protocols_apply_edits(ibutton->protocols, key);
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, protocol_id);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
consumed = true;
} }
return consumed; return consumed;

View File

@@ -1,42 +1,52 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
void ibutton_scene_add_type_byte_input_callback(void* context) { static void ibutton_scene_add_type_byte_input_callback(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult); view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult);
} }
static void ibutton_scene_add_type_byte_changed_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditChanged);
}
void ibutton_scene_add_value_on_enter(void* context) { void ibutton_scene_add_value_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
iButtonKey* key = ibutton->key; byte_input_set_header_text(ibutton->byte_input, "Enter the key");
uint8_t* new_key_data = malloc(IBUTTON_KEY_DATA_SIZE);
scene_manager_set_scene_state( iButtonEditableData editable_data;
ibutton->scene_manager, iButtonSceneAddValue, (uint32_t)new_key_data); ibutton_protocols_get_editable_data(ibutton->protocols, ibutton->key, &editable_data);
memcpy(new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key));
byte_input_set_result_callback( byte_input_set_result_callback(
ibutton->byte_input, ibutton->byte_input,
ibutton_scene_add_type_byte_input_callback, ibutton_scene_add_type_byte_input_callback,
NULL, ibutton_scene_add_type_byte_changed_callback,
ibutton, context,
new_key_data, editable_data.ptr,
ibutton_key_get_data_size(key)); editable_data.size);
byte_input_set_header_text(ibutton->byte_input, "Enter the key");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewByteInput); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewByteInput);
} }
bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context; iButton* ibutton = context;
uint8_t* new_key_data = SceneManager* scene_manager = ibutton->scene_manager;
(uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue);
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == iButtonCustomEventByteEditResult) { if(event.event == iButtonCustomEventByteEditResult) {
ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); } else if(event.event == iButtonCustomEventByteEditChanged) {
ibutton_protocols_apply_edits(ibutton->protocols, ibutton->key);
}
} else if(event.type == SceneManagerEventTypeBack) {
// User cancelled editing, reload the key from storage
if(scene_manager_has_previous_scene(scene_manager, iButtonSceneSavedKeyMenu)) {
if(!ibutton_load_key(ibutton)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
scene_manager, iButtonSceneStart);
}
} }
} }
@@ -45,10 +55,7 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_add_value_on_exit(void* context) { void ibutton_scene_add_value_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
uint8_t* new_key_data =
(uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue);
byte_input_set_result_callback(ibutton->byte_input, NULL, NULL, NULL, NULL, 0); byte_input_set_result_callback(ibutton->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(ibutton->byte_input, NULL); byte_input_set_header_text(ibutton->byte_input, NULL);
free(new_key_data);
} }

View File

@@ -6,8 +6,7 @@ ADD_SCENE(ibutton, info, Info)
ADD_SCENE(ibutton, read, Read) ADD_SCENE(ibutton, read, Read)
ADD_SCENE(ibutton, read_key_menu, ReadKeyMenu) ADD_SCENE(ibutton, read_key_menu, ReadKeyMenu)
ADD_SCENE(ibutton, read_success, ReadSuccess) ADD_SCENE(ibutton, read_success, ReadSuccess)
ADD_SCENE(ibutton, read_crc_error, ReadCRCError) ADD_SCENE(ibutton, read_error, ReadError)
ADD_SCENE(ibutton, read_not_key_error, ReadNotKeyError)
ADD_SCENE(ibutton, select_key, SelectKey) ADD_SCENE(ibutton, select_key, SelectKey)
ADD_SCENE(ibutton, add_type, AddType) ADD_SCENE(ibutton, add_type, AddType)
ADD_SCENE(ibutton, add_value, AddValue) ADD_SCENE(ibutton, add_value, AddValue)
@@ -18,4 +17,5 @@ ADD_SCENE(ibutton, delete_confirm, DeleteConfirm)
ADD_SCENE(ibutton, delete_success, DeleteSuccess) ADD_SCENE(ibutton, delete_success, DeleteSuccess)
ADD_SCENE(ibutton, retry_confirm, RetryConfirm) ADD_SCENE(ibutton, retry_confirm, RetryConfirm)
ADD_SCENE(ibutton, exit_confirm, ExitConfirm) ADD_SCENE(ibutton, exit_confirm, ExitConfirm)
ADD_SCENE(ibutton, view_data, ViewData)
ADD_SCENE(ibutton, rpc, Rpc) ADD_SCENE(ibutton, rpc, Rpc)

View File

@@ -1,74 +1,29 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
#include <toolbox/path.h> #include <toolbox/path.h>
static void ibutton_scene_delete_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
void ibutton_scene_delete_confirm_on_enter(void* context) { void ibutton_scene_delete_confirm_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key); Widget* widget = ibutton->widget;
FuriString* key_name; FuriString* tmp = furi_string_alloc();
key_name = furi_string_alloc();
path_extract_filename(ibutton->file_path, key_name, true);
ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", furi_string_get_cstr(key_name)); widget_add_button_element(widget, GuiButtonTypeLeft, "Back", ibutton_widget_callback, context);
widget_add_text_box_element(
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true);
widget_add_button_element( widget_add_button_element(
widget, GuiButtonTypeLeft, "Cancel", ibutton_scene_delete_confirm_widget_callback, ibutton); widget, GuiButtonTypeRight, "Delete", ibutton_widget_callback, context);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"Delete",
ibutton_scene_delete_confirm_widget_callback,
ibutton);
switch(ibutton_key_get_type(key)) { furi_string_printf(tmp, "Delete %s?", ibutton->key_name);
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
widget_add_string_element(
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Dallas");
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
widget_add_string_element(
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
widget_add_string_element(
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Metakom");
break;
}
widget_add_string_element( widget_add_string_element(
widget, 64, 46, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store); widget, 128 / 2, 0, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
furi_string_reset(tmp);
ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
widget_add_string_multiline_element(
widget, 128 / 2, 16, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
furi_string_free(key_name);
} }
bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
@@ -81,8 +36,10 @@ bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent even
if(event.event == GuiButtonTypeRight) { if(event.event == GuiButtonTypeRight) {
if(ibutton_delete_key(ibutton)) { if(ibutton_delete_key(ibutton)) {
scene_manager_next_scene(scene_manager, iButtonSceneDeleteSuccess); scene_manager_next_scene(scene_manager, iButtonSceneDeleteSuccess);
} else {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot delete\nkey file");
scene_manager_previous_scene(scene_manager);
} }
//TODO: What if the key could not be deleted?
} else if(event.event == GuiButtonTypeLeft) { } else if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager); scene_manager_previous_scene(scene_manager);
} }
@@ -93,6 +50,5 @@ bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent even
void ibutton_scene_delete_confirm_on_exit(void* context) { void ibutton_scene_delete_confirm_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
ibutton_text_store_clear(ibutton);
widget_reset(ibutton->widget); widget_reset(ibutton->widget);
} }

View File

@@ -14,61 +14,32 @@ static void ibutton_scene_emulate_callback(void* context, bool emulated) {
void ibutton_scene_emulate_on_enter(void* context) { void ibutton_scene_emulate_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key); Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
FuriString* key_name; widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
// check that stored key has name furi_string_printf(
if(!furi_string_empty(key_name)) { tmp,
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); "%s\n[%s]",
} else { furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name,
// if not, show key data ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)));
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990: widget_add_text_box_element(
ibutton_text_store_set( widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
ibutton,
"%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
break;
}
}
widget_add_string_multiline_element( widget_add_string_multiline_element(
widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating"); widget, 88, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating");
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
widget_add_text_box_element(
widget, 54, 39, 75, 22, AlignCenter, AlignCenter, ibutton->text_store, true);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); ibutton_worker_emulate_set_callback(ibutton->worker, ibutton_scene_emulate_callback, ibutton);
ibutton_worker_emulate_start(ibutton->worker, key);
ibutton_worker_emulate_set_callback(
ibutton->key_worker, ibutton_scene_emulate_callback, ibutton);
ibutton_worker_emulate_start(ibutton->key_worker, key);
furi_string_free(key_name);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
} }
bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
@@ -78,8 +49,7 @@ bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeTick) { if(event.type == SceneManagerEventTypeTick) {
uint32_t cnt = scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneEmulate); uint32_t cnt = scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneEmulate);
if(cnt > 0) { if(cnt > 0) {
cnt--; if(--cnt == 0) {
if(cnt == 0) {
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink); ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink);
} }
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneEmulate, cnt); scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneEmulate, cnt);
@@ -101,7 +71,7 @@ bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_emulate_on_exit(void* context) { void ibutton_scene_emulate_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
ibutton_worker_stop(ibutton->key_worker); ibutton_worker_stop(ibutton->worker);
widget_reset(ibutton->widget); widget_reset(ibutton->widget);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
} }

View File

@@ -1,66 +1,54 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
#include <toolbox/path.h>
void ibutton_scene_info_on_enter(void* context) { void ibutton_scene_info_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
const uint8_t* key_data = ibutton_key_get_data_p(key); const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
FuriString* key_name; FuriString* tmp = furi_string_alloc();
key_name = furi_string_alloc();
path_extract_filename(ibutton->file_path, key_name, true); furi_string_printf(
tmp,
"\e#%s [%s]\e#",
ibutton->key_name,
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
widget_add_text_box_element( widget_add_text_box_element(
widget, 0, 0, 128, 23, AlignCenter, AlignCenter, ibutton->text_store, true); widget, 0, 2, 128, 12, AlignLeft, AlignTop, furi_string_get_cstr(tmp), true);
switch(ibutton_key_get_type(key)) { furi_string_reset(tmp);
case iButtonKeyDS1990: ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Dallas");
break;
case iButtonKeyMetakom: widget_add_string_multiline_element(
ibutton_text_store_set( widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
widget_add_string_element(
widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Metakom");
break;
case iButtonKeyCyfral: if(ibutton_protocols_get_features(ibutton->protocols, protocol_id) &
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]); iButtonProtocolFeatureExtData) {
widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Cyfral"); widget_add_button_element(
break; widget, GuiButtonTypeRight, "More", ibutton_widget_callback, context);
} }
widget_add_string_element(
widget, 64, 50, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
furi_string_free(key_name);
} }
bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) {
UNUSED(context); iButton* ibutton = context;
UNUSED(event); bool consumed = false;
return false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneViewData);
}
}
return consumed;
} }
void ibutton_scene_info_on_exit(void* context) { void ibutton_scene_info_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
ibutton_text_store_clear(ibutton);
widget_reset(ibutton->widget); widget_reset(ibutton->widget);
} }

View File

@@ -11,14 +11,13 @@ void ibutton_scene_read_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Popup* popup = ibutton->popup; Popup* popup = ibutton->popup;
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
iButtonWorker* worker = ibutton->key_worker; iButtonWorker* worker = ibutton->worker;
popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom);
popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 5, XTREME_ASSETS()->I_DolphinWait_61x59); popup_set_icon(popup, 0, 5, XTREME_ASSETS()->I_DolphinWait_61x59);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton); ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton);
ibutton_worker_read_start(worker, key); ibutton_worker_read_start(worker, key);
@@ -36,25 +35,14 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) {
} else if(event.type == SceneManagerEventTypeCustom) { } else if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == iButtonCustomEventWorkerRead) { if(event.event == iButtonCustomEventWorkerRead) {
bool success = false; if(ibutton_protocols_is_valid(ibutton->protocols, ibutton->key)) {
iButtonKey* key = ibutton->key;
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) {
scene_manager_next_scene(scene_manager, iButtonSceneReadCRCError);
} else if(!ibutton_key_dallas_is_1990_key(key)) {
scene_manager_next_scene(scene_manager, iButtonSceneReadNotKeyError);
} else {
success = true;
}
} else {
success = true;
}
if(success) {
ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess);
scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess);
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
} else {
scene_manager_next_scene(scene_manager, iButtonSceneReadError);
} }
} }
} }
@@ -65,7 +53,7 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_read_on_exit(void* context) { void ibutton_scene_read_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Popup* popup = ibutton->popup; Popup* popup = ibutton->popup;
ibutton_worker_stop(ibutton->key_worker); ibutton_worker_stop(ibutton->worker);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL); popup_set_icon(popup, 0, 0, NULL);

View File

@@ -1,70 +0,0 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
static void ibutton_scene_read_crc_error_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_crc_error_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X\nExpected CRC: %X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7],
maxim_crc8(key_data, 7, MAXIM_CRC8_INIT));
dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_crc_error_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
}
bool ibutton_scene_read_crc_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_read_crc_error_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@@ -0,0 +1,58 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
void ibutton_scene_read_error_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", ibutton_widget_callback, context);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", ibutton_widget_callback, context);
widget_add_string_element(
widget, 128 / 2, 2, AlignCenter, AlignTop, FontPrimary, "Read Error");
ibutton_protocols_render_error(ibutton->protocols, key, tmp);
widget_add_string_multiline_element(
widget, 128 / 2, 16, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
}
bool ibutton_scene_read_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
}
}
return consumed;
}
void ibutton_scene_read_error_on_exit(void* context) {
iButton* ibutton = context;
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
widget_reset(ibutton->widget);
}

View File

@@ -4,7 +4,9 @@
typedef enum { typedef enum {
SubmenuIndexSave, SubmenuIndexSave,
SubmenuIndexEmulate, SubmenuIndexEmulate,
SubmenuIndexWrite, SubmenuIndexViewData,
SubmenuIndexWriteBlank,
SubmenuIndexWriteCopy,
} SubmenuIndex; } SubmenuIndex;
void ibutton_scene_read_key_menu_submenu_callback(void* context, uint32_t index) { void ibutton_scene_read_key_menu_submenu_callback(void* context, uint32_t index) {
@@ -16,6 +18,9 @@ void ibutton_scene_read_key_menu_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Submenu* submenu = ibutton->submenu; Submenu* submenu = ibutton->submenu;
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(ibutton->key);
const uint32_t features = ibutton_protocols_get_features(ibutton->protocols, protocol_id);
submenu_add_item( submenu_add_item(
submenu, "Save", SubmenuIndexSave, ibutton_scene_read_key_menu_submenu_callback, ibutton); submenu, "Save", SubmenuIndexSave, ibutton_scene_read_key_menu_submenu_callback, ibutton);
submenu_add_item( submenu_add_item(
@@ -24,36 +29,66 @@ void ibutton_scene_read_key_menu_on_enter(void* context) {
SubmenuIndexEmulate, SubmenuIndexEmulate,
ibutton_scene_read_key_menu_submenu_callback, ibutton_scene_read_key_menu_submenu_callback,
ibutton); ibutton);
if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) {
if(features & iButtonProtocolFeatureExtData) {
submenu_add_item( submenu_add_item(
submenu, submenu,
"Write", "View Data",
SubmenuIndexWrite, SubmenuIndexViewData,
ibutton_scene_read_key_menu_submenu_callback, ibutton_scene_read_key_menu_submenu_callback,
ibutton); ibutton);
} }
if(features & iButtonProtocolFeatureWriteBlank) {
submenu_add_item(
submenu,
"Write Blank",
SubmenuIndexWriteBlank,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
}
if(features & iButtonProtocolFeatureWriteCopy) {
submenu_add_item(
submenu,
"Write Copy",
SubmenuIndexWriteCopy,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
}
submenu_set_selected_item( submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneReadKeyMenu)); submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneReadKeyMenu));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
} }
bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context; iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state( scene_manager_set_scene_state(scene_manager, iButtonSceneReadKeyMenu, event.event);
ibutton->scene_manager, iButtonSceneReadKeyMenu, event.event);
consumed = true; consumed = true;
if(event.event == SubmenuIndexSave) { if(event.event == SubmenuIndexSave) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
} else if(event.event == SubmenuIndexEmulate) { } else if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate); DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else if(event.event == SubmenuIndexWrite) { } else if(event.event == SubmenuIndexViewData) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); scene_manager_next_scene(scene_manager, iButtonSceneViewData);
} else if(event.event == SubmenuIndexWriteBlank) {
ibutton->write_mode = iButtonWriteModeBlank;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexWriteCopy) {
ibutton->write_mode = iButtonWriteModeCopy;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} }
} else if(event.event == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneReadKeyMenu, SubmenuIndexSave);
// Event is not consumed
} }
return consumed; return consumed;

View File

@@ -1,71 +0,0 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
static void
ibutton_scene_read_not_key_error_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_not_key_error_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
ibutton_text_store_set(
ibutton,
"THIS IS NOT A KEY\n%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7],
maxim_crc8(key_data, 7, MAXIM_CRC8_INIT));
dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_not_key_error_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
}
bool ibutton_scene_read_not_key_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_read_not_key_error_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@@ -1,55 +1,40 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
#include <dolphin/dolphin.h>
static void ibutton_scene_read_success_dialog_ex_callback(DialogExResult result, void* context) { #include <dolphin/dolphin.h>
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_success_on_enter(void* context) { void ibutton_scene_read_success_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key); Widget* widget = ibutton->widget;
switch(ibutton_key_get_type(key)) { FuriString* tmp = furi_string_alloc();
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"Dallas\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "Cyfral\n%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton,
"Metakom\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3]);
break;
}
dialog_ex_set_text(dialog_ex, ibutton->text_store, 95, 30, AlignCenter, AlignCenter); const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63);
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_success_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx); widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", ibutton_widget_callback, context);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", ibutton_widget_callback, context);
furi_string_printf(
tmp,
"%s[%s]",
ibutton_protocols_get_name(ibutton->protocols, protocol_id),
ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id));
widget_add_string_element(
widget, 0, 2, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
furi_string_reset(tmp);
ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
widget_add_string_multiline_element(
widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn);
furi_string_free(tmp);
} }
bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event) {
@@ -62,9 +47,9 @@ bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event)
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm); scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) { } else if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == DialogExResultRight) { if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu); scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) { } else if(event.event == GuiButtonTypeLeft) {
scene_manager_next_scene(scene_manager, iButtonSceneRetryConfirm); scene_manager_next_scene(scene_manager, iButtonSceneRetryConfirm);
} }
} }
@@ -74,11 +59,8 @@ bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event)
void ibutton_scene_read_success_on_exit(void* context) { void ibutton_scene_read_success_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton); widget_reset(ibutton->widget);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff); ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff);
} }

View File

@@ -1,6 +1,4 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
#include <toolbox/path.h>
#include <rpc/rpc_app.h>
void ibutton_scene_rpc_on_enter(void* context) { void ibutton_scene_rpc_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
@@ -17,8 +15,6 @@ void ibutton_scene_rpc_on_enter(void* context) {
} }
bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
iButton* ibutton = context; iButton* ibutton = context;
Popup* popup = ibutton->popup; Popup* popup = ibutton->popup;
@@ -26,40 +22,32 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == iButtonCustomEventRpcLoad) {
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
bool result = false;
if(arg && (furi_string_empty(ibutton->file_path))) {
furi_string_set(ibutton->file_path, arg);
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
FuriString* key_name;
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
if(!furi_string_empty(key_name)) { if(event.event == iButtonCustomEventRpcLoad) {
ibutton_text_store_set( bool result = false;
ibutton, "emulating\n%s", furi_string_get_cstr(key_name)); const char* file_path = rpc_system_app_get_data(ibutton->rpc);
} else {
ibutton_text_store_set(ibutton, "emulating"); if(file_path && (furi_string_empty(ibutton->file_path))) {
} furi_string_set(ibutton->file_path, file_path);
popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop);
if(ibutton_load_key(ibutton)) {
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
ibutton_worker_emulate_start(ibutton->worker, ibutton->key);
furi_string_free(key_name);
result = true; result = true;
} else {
furi_string_reset(ibutton->file_path);
} }
} }
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
rpc_system_app_confirm(ibutton->rpc, RpcAppEventLoadFile, result);
} else if(event.event == iButtonCustomEventRpcExit) { } else if(event.event == iButtonCustomEventRpcExit) {
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); rpc_system_app_confirm(ibutton->rpc, RpcAppEventAppExit, true);
scene_manager_stop(ibutton->scene_manager); scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher); view_dispatcher_stop(ibutton->view_dispatcher);
} else if(event.event == iButtonCustomEventRpcSessionClose) { } else if(event.event == iButtonCustomEventRpcSessionClose) {
scene_manager_stop(ibutton->scene_manager); scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher); view_dispatcher_stop(ibutton->view_dispatcher);

View File

@@ -1,6 +1,8 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
#include <lib/toolbox/random_name.h>
#include <toolbox/random_name.h>
#include <toolbox/path.h> #include <toolbox/path.h>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
static void ibutton_scene_save_name_text_input_callback(void* context) { static void ibutton_scene_save_name_text_input_callback(void* context) {
@@ -12,17 +14,10 @@ void ibutton_scene_save_name_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
TextInput* text_input = ibutton->text_input; TextInput* text_input = ibutton->text_input;
FuriString* key_name; const bool is_new_file = furi_string_empty(ibutton->file_path);
key_name = furi_string_alloc();
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
const bool key_name_is_empty = furi_string_empty(key_name); if(is_new_file) {
if(key_name_is_empty) { set_random_name(ibutton->key_name, IBUTTON_KEY_NAME_SIZE);
set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE);
} else {
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
} }
text_input_set_header_text(text_input, "Name the key"); text_input_set_header_text(text_input, "Name the key");
@@ -30,23 +25,15 @@ void ibutton_scene_save_name_on_enter(void* context) {
text_input, text_input,
ibutton_scene_save_name_text_input_callback, ibutton_scene_save_name_text_input_callback,
ibutton, ibutton,
ibutton->text_store, ibutton->key_name,
IBUTTON_KEY_NAME_SIZE, IBUTTON_KEY_NAME_SIZE,
key_name_is_empty); is_new_file);
FuriString* folder_path; ValidatorIsFile* validator_is_file =
folder_path = furi_string_alloc(); validator_is_file_alloc_init(IBUTTON_APP_FOLDER, IBUTTON_APP_EXTENSION, ibutton->key_name);
path_extract_dirname(furi_string_get_cstr(ibutton->file_path), folder_path);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
furi_string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, furi_string_get_cstr(key_name));
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput);
furi_string_free(key_name);
furi_string_free(folder_path);
} }
bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
@@ -56,8 +43,16 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == iButtonCustomEventTextEditResult) { if(event.event == iButtonCustomEventTextEditResult) {
if(ibutton_save_key(ibutton, ibutton->text_store)) { furi_string_printf(
ibutton->file_path,
"%s/%s%s",
IBUTTON_APP_FOLDER,
ibutton->key_name,
IBUTTON_APP_EXTENSION);
if(ibutton_save_key(ibutton)) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess);
if(scene_manager_has_previous_scene( if(scene_manager_has_previous_scene(
ibutton->scene_manager, iButtonSceneSavedKeyMenu)) { ibutton->scene_manager, iButtonSceneSavedKeyMenu)) {
// Nothing, do not count editing as saving // Nothing, do not count editing as saving
@@ -67,6 +62,7 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
} else { } else {
DOLPHIN_DEED(DolphinDeedIbuttonSave); DOLPHIN_DEED(DolphinDeedIbuttonSave);
} }
} else { } else {
const uint32_t possible_scenes[] = { const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};

View File

@@ -3,72 +3,70 @@
enum SubmenuIndex { enum SubmenuIndex {
SubmenuIndexEmulate, SubmenuIndexEmulate,
SubmenuIndexWrite, SubmenuIndexWriteBlank,
SubmenuIndexWriteCopy,
SubmenuIndexEdit, SubmenuIndexEdit,
SubmenuIndexDelete, SubmenuIndexDelete,
SubmenuIndexInfo, SubmenuIndexInfo,
}; };
void ibutton_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_saved_key_menu_on_enter(void* context) { void ibutton_scene_saved_key_menu_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Submenu* submenu = ibutton->submenu; Submenu* submenu = ibutton->submenu;
submenu_add_item( const uint32_t features = ibutton_protocols_get_features(
submenu, ibutton->protocols, ibutton_key_get_protocol_id(ibutton->key));
"Emulate",
SubmenuIndexEmulate, submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, ibutton_submenu_callback, ibutton);
ibutton_scene_saved_key_menu_submenu_callback,
ibutton); if(features & iButtonProtocolFeatureWriteBlank) {
if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) {
submenu_add_item( submenu_add_item(
submenu, submenu, "Write Blank", SubmenuIndexWriteBlank, ibutton_submenu_callback, ibutton);
"Write",
SubmenuIndexWrite,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
} }
submenu_add_item(
submenu, "Edit", SubmenuIndexEdit, ibutton_scene_saved_key_menu_submenu_callback, ibutton); if(features & iButtonProtocolFeatureWriteCopy) {
submenu_add_item( submenu_add_item(
submenu, submenu, "Write Copy", SubmenuIndexWriteCopy, ibutton_submenu_callback, ibutton);
"Delete", }
SubmenuIndexDelete,
ibutton_scene_saved_key_menu_submenu_callback, submenu_add_item(submenu, "Edit", SubmenuIndexEdit, ibutton_submenu_callback, ibutton);
ibutton); submenu_add_item(submenu, "Delete", SubmenuIndexDelete, ibutton_submenu_callback, ibutton);
submenu_add_item( submenu_add_item(submenu, "Info", SubmenuIndexInfo, ibutton_submenu_callback, ibutton);
submenu, "Info", SubmenuIndexInfo, ibutton_scene_saved_key_menu_submenu_callback, ibutton);
submenu_set_selected_item( submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneSavedKeyMenu)); submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneSavedKeyMenu));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
} }
bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context; iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state( scene_manager_set_scene_state(scene_manager, iButtonSceneSavedKeyMenu, event.event);
ibutton->scene_manager, iButtonSceneSavedKeyMenu, event.event);
consumed = true; consumed = true;
if(event.event == SubmenuIndexEmulate) { if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); scene_manager_next_scene(scene_manager, iButtonSceneEmulate);
DOLPHIN_DEED(DolphinDeedIbuttonEmulate); DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
} else if(event.event == SubmenuIndexWrite) { } else if(event.event == SubmenuIndexWriteBlank) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); ibutton->write_mode = iButtonWriteModeBlank;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexWriteCopy) {
ibutton->write_mode = iButtonWriteModeCopy;
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexEdit) { } else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); scene_manager_next_scene(scene_manager, iButtonSceneAddValue);
} else if(event.event == SubmenuIndexDelete) { } else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneDeleteConfirm); scene_manager_next_scene(scene_manager, iButtonSceneDeleteConfirm);
} else if(event.event == SubmenuIndexInfo) { } else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneInfo); scene_manager_next_scene(scene_manager, iButtonSceneInfo);
} }
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(
scene_manager, iButtonSceneSavedKeyMenu, SubmenuIndexEmulate);
// Event is not consumed
} }
return consumed; return consumed;

View File

@@ -3,11 +3,11 @@
void ibutton_scene_select_key_on_enter(void* context) { void ibutton_scene_select_key_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
if(!ibutton_file_select(ibutton)) { if(ibutton_select_and_load_key(ibutton)) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu);
} else {
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(
ibutton->scene_manager, iButtonSceneStart); ibutton->scene_manager, iButtonSceneStart);
} else {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu);
} }
} }

View File

@@ -8,21 +8,15 @@ enum SubmenuIndex {
SubmenuIndexAdd, SubmenuIndexAdd,
}; };
void ibutton_scene_start_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_start_on_enter(void* context) { void ibutton_scene_start_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
Submenu* submenu = ibutton->submenu; Submenu* submenu = ibutton->submenu;
submenu_add_item( ibutton_reset_key(ibutton);
submenu, "Read", SubmenuIndexRead, ibutton_scene_start_submenu_callback, ibutton);
submenu_add_item( submenu_add_item(submenu, "Read", SubmenuIndexRead, ibutton_submenu_callback, ibutton);
submenu, "Saved", SubmenuIndexSaved, ibutton_scene_start_submenu_callback, ibutton); submenu_add_item(submenu, "Saved", SubmenuIndexSaved, ibutton_submenu_callback, ibutton);
submenu_add_item( submenu_add_item(submenu, "Add Manually", SubmenuIndexAdd, ibutton_submenu_callback, ibutton);
submenu, "Add Manually", SubmenuIndexAdd, ibutton_scene_start_submenu_callback, ibutton);
submenu_set_selected_item( submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneStart)); submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneStart));
@@ -41,7 +35,6 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
DOLPHIN_DEED(DolphinDeedIbuttonRead); DOLPHIN_DEED(DolphinDeedIbuttonRead);
} else if(event.event == SubmenuIndexSaved) { } else if(event.event == SubmenuIndexSaved) {
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
} else if(event.event == SubmenuIndexAdd) { } else if(event.event == SubmenuIndexAdd) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType);

View File

@@ -0,0 +1,26 @@
#include "../ibutton_i.h"
void ibutton_scene_view_data_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
Widget* widget = ibutton->widget;
FuriString* tmp = furi_string_alloc();
ibutton_protocols_render_data(ibutton->protocols, key, tmp);
widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(tmp));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
}
bool ibutton_scene_view_data_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void ibutton_scene_view_data_on_exit(void* context) {
iButton* ibutton = context;
widget_reset(ibutton->widget);
}

View File

@@ -1,5 +1,4 @@
#include "../ibutton_i.h" #include "../ibutton_i.h"
#include "toolbox/path.h"
typedef enum { typedef enum {
iButtonSceneWriteStateDefault, iButtonSceneWriteStateDefault,
@@ -13,61 +12,46 @@ static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult
void ibutton_scene_write_on_enter(void* context) { void ibutton_scene_write_on_enter(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
furi_assert(ibutton->write_mode != iButtonWriteModeInvalid);
iButtonKey* key = ibutton->key; iButtonKey* key = ibutton->key;
iButtonWorker* worker = ibutton->worker;
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
Widget* widget = ibutton->widget; Widget* widget = ibutton->widget;
iButtonWorker* worker = ibutton->key_worker; FuriString* tmp = furi_string_alloc();
const uint8_t* key_data = ibutton_key_get_data_p(key); widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
FuriString* key_name; furi_string_printf(
key_name = furi_string_alloc(); tmp,
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) { "%s\n[%s]",
path_extract_filename(ibutton->file_path, key_name, true); ibutton->key_name,
} ibutton_protocols_get_name(ibutton->protocols, protocol_id));
// check that stored key has name widget_add_text_box_element(
if(!furi_string_empty(key_name)) { widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
} else { ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
// if not, show key data
switch(ibutton_key_get_type(key)) { furi_string_set(tmp, "iButton\nwriting ");
case iButtonKeyDS1990:
ibutton_text_store_set( if(ibutton->write_mode == iButtonWriteModeBlank) {
ibutton, furi_string_cat(tmp, "Blank");
"%02X %02X %02X %02X\n%02X %02X %02X %02X", ibutton_worker_write_blank_start(worker, key);
key_data[0],
key_data[1], } else if(ibutton->write_mode == iButtonWriteModeCopy) {
key_data[2], furi_string_cat(tmp, "Copy");
key_data[3], ibutton_worker_write_copy_start(worker, key);
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
break;
}
} }
widget_add_string_multiline_element( widget_add_string_multiline_element(
widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nwriting"); widget, 88, 10, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
widget_add_text_box_element(
widget, 54, 39, 75, 22, AlignCenter, AlignCenter, ibutton->text_store, true);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
ibutton_worker_write_start(worker, key);
furi_string_free(key_name);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
furi_string_free(tmp);
} }
bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) { bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) {
@@ -94,7 +78,9 @@ bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) {
void ibutton_scene_write_on_exit(void* context) { void ibutton_scene_write_on_exit(void* context) {
iButton* ibutton = context; iButton* ibutton = context;
ibutton_worker_stop(ibutton->key_worker); ibutton->write_mode = iButtonWriteModeInvalid;
ibutton_worker_stop(ibutton->worker);
widget_reset(ibutton->widget); widget_reset(ibutton->widget);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);

View File

@@ -54,6 +54,7 @@ typedef enum {
SubGhzLoadKeyStateOK, SubGhzLoadKeyStateOK,
SubGhzLoadKeyStateParseErr, SubGhzLoadKeyStateParseErr,
SubGhzLoadKeyStateOnlyRx, SubGhzLoadKeyStateOnlyRx,
SubGhzLoadKeyStateProtocolDescriptionErr,
} SubGhzLoadKeyState; } SubGhzLoadKeyState;
/** SubGhzLock */ /** SubGhzLock */

View File

@@ -27,8 +27,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
subghz->txrx->receiver, subghz->txrx->receiver,
subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
if(subghz->txrx->decoder_result) { if(subghz->txrx->decoder_result) {
// In this case flipper format was changed to short file content //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
subghz_protocol_decoder_base_deserialize( subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->decoder_result,
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
@@ -138,7 +139,6 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz, subghz,
subghz_history_get_raw_data( subghz_history_get_raw_data(
subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz); subghz_tx_stop(subghz);
} }

View File

@@ -36,8 +36,9 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
do { do {
Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
stream_clean(fff_data_stream); stream_clean(fff_data_stream);
if(!subghz_protocol_decoder_base_serialize( if(subghz_protocol_decoder_base_serialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset)) { subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) !=
SubGhzProtocolStatusOk) {
FURI_LOG_E(TAG, "Unable to serialize"); FURI_LOG_E(TAG, "Unable to serialize");
break; break;
} }
@@ -363,8 +364,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexSomfyTelis: case SubmenuIndexSomfyTelis:
subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME);
subghz_preset_init( subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
subghz_protocol_somfy_telis_create_data( subghz_protocol_somfy_telis_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
@@ -387,8 +387,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexDoorHan_433_92: case SubmenuIndexDoorHan_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init( subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_create_data( subghz_protocol_keeloq_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
@@ -436,8 +435,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexNiceFlorS_433_92: case SubmenuIndexNiceFlorS_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
subghz_preset_init( subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
subghz_protocol_nice_flor_s_create_data( subghz_protocol_nice_flor_s_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
@@ -461,8 +459,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexNiceOne_433_92: case SubmenuIndexNiceOne_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
subghz_preset_init( subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
subghz_protocol_nice_flor_s_create_data( subghz_protocol_nice_flor_s_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
@@ -486,8 +483,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
case SubmenuIndexNiceSmilo_433_92: case SubmenuIndexNiceSmilo_433_92:
subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init( subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_create_data( subghz_protocol_keeloq_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),

View File

@@ -14,9 +14,8 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
} }
bool subghz_scene_transmitter_update_data_show(void* context) { bool subghz_scene_transmitter_update_data_show(void* context) {
//ToDo Fix
SubGhz* subghz = context; SubGhz* subghz = context;
bool ret = false;
if(subghz->txrx->decoder_result) { if(subghz->txrx->decoder_result) {
FuriString* key_str; FuriString* key_str;
FuriString* frequency_str; FuriString* frequency_str;
@@ -27,30 +26,29 @@ bool subghz_scene_transmitter_update_data_show(void* context) {
modulation_str = furi_string_alloc(); modulation_str = furi_string_alloc();
uint8_t show_button = 0; uint8_t show_button = 0;
subghz_protocol_decoder_base_deserialize( if(subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data); subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) {
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
SubGhzProtocolFlag_Send) { SubGhzProtocolFlag_Send) {
show_button = 1; show_button = 1;
}
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
subghz_view_transmitter_add_data_to_show(
subghz->subghz_transmitter,
furi_string_get_cstr(key_str),
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
show_button);
ret = true;
} }
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
subghz_view_transmitter_add_data_to_show(
subghz->subghz_transmitter,
furi_string_get_cstr(key_str),
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
show_button);
furi_string_free(frequency_str); furi_string_free(frequency_str);
furi_string_free(modulation_str); furi_string_free(modulation_str);
furi_string_free(key_str); furi_string_free(key_str);
return true;
} }
return false; return ret;
} }
void subghz_scene_transmitter_on_enter(void* context) { void subghz_scene_transmitter_on_enter(void* context) {

View File

@@ -154,7 +154,6 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
FURI_LOG_E(TAG, "Missing Protocol"); FURI_LOG_E(TAG, "Missing Protocol");
break; break;
} }
//ToDo FIX
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
FURI_LOG_E(TAG, "Unable Repeat"); FURI_LOG_E(TAG, "Unable Repeat");
break; break;
@@ -164,7 +163,8 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
subghz->txrx->environment, furi_string_get_cstr(temp_str)); subghz->txrx->environment, furi_string_get_cstr(temp_str));
if(subghz->txrx->transmitter) { if(subghz->txrx->transmitter) {
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) { if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) ==
SubGhzProtocolStatusOk) {
if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) { if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) {
subghz_begin( subghz_begin(
subghz, subghz,
@@ -187,7 +187,12 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
//Start TX //Start TX
furi_hal_subghz_start_async_tx( furi_hal_subghz_start_async_tx(
subghz_transmitter_yield, subghz->txrx->transmitter); subghz_transmitter_yield, subghz->txrx->transmitter);
} else {
subghz_dialog_message_show_only_rx(subghz);
} }
} else {
dialog_message_show_storage_error(
subghz->dialogs, "Error in protocol\nparameters\ndescription");
} }
} }
if(!ret) { if(!ret) {
@@ -335,8 +340,10 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
subghz->txrx->receiver, furi_string_get_cstr(temp_str)); subghz->txrx->receiver, furi_string_get_cstr(temp_str));
if(subghz->txrx->decoder_result) { if(subghz->txrx->decoder_result) {
if(!subghz_protocol_decoder_base_deserialize( SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
subghz->txrx->decoder_result, subghz->txrx->fff_data)) { subghz->txrx->decoder_result, subghz->txrx->fff_data);
if(status != SubGhzProtocolStatusOk) {
load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
break; break;
} }
} else { } else {
@@ -357,6 +364,12 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile");
} }
return false; return false;
case SubGhzLoadKeyStateProtocolDescriptionErr:
if(show_dialog) {
dialog_message_show_storage_error(
subghz->dialogs, "Error in protocol\nparameters\ndescription");
}
return false;
case SubGhzLoadKeyStateOnlyRx: case SubGhzLoadKeyStateOnlyRx:
if(show_dialog) { if(show_dialog) {

View File

@@ -376,7 +376,17 @@ int32_t hid_ble_app(void* p) {
// Wait 2nd core to update nvm storage // Wait 2nd core to update nvm storage
furi_delay_ms(200); furi_delay_ms(200);
bt_keys_storage_set_storage_path(app->bt, HID_BT_KEYS_STORAGE_PATH); // Migrate data from old sd-card folder
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_migrate(
storage,
EXT_PATH("apps/Tools/" HID_BT_KEYS_STORAGE_NAME),
APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
bt_keys_storage_set_storage_path(app->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
furi_record_close(RECORD_STORAGE);
if(!bt_set_profile(app->bt, BtProfileHidKeyboard)) { if(!bt_set_profile(app->bt, BtProfileHidKeyboard)) {
FURI_LOG_E(TAG, "Failed to switch to HID profile"); FURI_LOG_E(TAG, "Failed to switch to HID profile");

View File

@@ -23,7 +23,7 @@
#include "views/hid_mouse_jiggler.h" #include "views/hid_mouse_jiggler.h"
#include "views/hid_tiktok.h" #include "views/hid_tiktok.h"
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("apps/Tools/.bt_hid.keys") #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
typedef enum { typedef enum {
HidTransportUsb, HidTransportUsb,

View File

@@ -78,7 +78,8 @@ typedef struct {
uint8_t key_index; uint8_t key_index;
iButtonWorker* worker; iButtonWorker* worker;
iButtonKey* key; iButtonKey* key;
iButtonKeyType keytype; iButtonProtocolId keytype;
iButtonProtocols* protocols;
bool workr_rund; bool workr_rund;
bool enter_rerun; bool enter_rerun;
bool attack_stop_called; bool attack_stop_called;

View File

@@ -72,14 +72,15 @@ void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context) {
context->time_between_cards = 8; context->time_between_cards = 8;
context->attack_step = 0; context->attack_step = 0;
context->attack_stop_called = false; context->attack_stop_called = false;
context->key = ibutton_key_alloc(); context->protocols = ibutton_protocols_alloc();
context->worker = ibutton_worker_alloc(); context->key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(context->protocols));
context->worker = ibutton_worker_alloc(context->protocols);
if(context->proto == Metakom) { if(context->proto == Metakom) {
context->keytype = iButtonKeyMetakom; context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "Metakom");
} else if(context->proto == Cyfral) { } else if(context->proto == Cyfral) {
context->keytype = iButtonKeyCyfral; context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "Cyfral");
} else { } else {
context->keytype = iButtonKeyDS1990; context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "DS1990");
} }
context->workr_rund = false; context->workr_rund = false;
} }
@@ -90,8 +91,9 @@ void ibtnfuzzer_scene_run_attack_on_exit(iBtnFuzzerState* context) {
ibutton_worker_stop_thread(context->worker); ibutton_worker_stop_thread(context->worker);
context->workr_rund = false; context->workr_rund = false;
} }
ibutton_worker_free(context->worker);
ibutton_key_free(context->key); ibutton_key_free(context->key);
ibutton_worker_free(context->worker);
ibutton_protocols_free(context->protocols);
notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_blink_stop);
} }
@@ -99,9 +101,14 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) {
if(context->is_attacking) { if(context->is_attacking) {
if(1 == counter) { if(1 == counter) {
ibutton_worker_start_thread(context->worker); ibutton_worker_start_thread(context->worker);
ibutton_key_set_type(context->key, context->keytype); ibutton_key_set_protocol_id(context->key, context->keytype);
ibutton_key_set_data( iButtonEditableData data;
context->key, context->payload, ibutton_key_get_size_by_type(context->keytype)); ibutton_protocols_get_editable_data(context->protocols, context->key, &data);
data.size = sizeof(context->payload);
for(size_t i = 0; i < data.size; i++) {
data.ptr[i] = context->payload[i];
}
ibutton_worker_emulate_start(context->worker, context->key); ibutton_worker_emulate_start(context->worker, context->key);
context->workr_rund = true; context->workr_rund = true;
} else if(0 == counter) { } else if(0 == counter) {

View File

@@ -3,8 +3,8 @@
#include <lib/toolbox/args.h> #include <lib/toolbox/args.h>
#include <lib/flipper_format/flipper_format.h> #include <lib/flipper_format/flipper_format.h>
#define ICLASS_ELITE_DICT_FLIPPER_PATH EXT_PATH("picopass/assets/iclass_elite_dict.txt") #define ICLASS_ELITE_DICT_FLIPPER_NAME APP_DATA_PATH("assets/iclass_elite_dict.txt")
#define ICLASS_ELITE_DICT_USER_PATH EXT_PATH("picopass/assets/iclass_elite_dict_user.txt") #define ICLASS_ELITE_DICT_USER_NAME APP_DATA_PATH("assets/iclass_elite_dict_user.txt")
#define TAG "IclassEliteDict" #define TAG "IclassEliteDict"
@@ -21,10 +21,10 @@ bool iclass_elite_dict_check_presence(IclassEliteDictType dict_type) {
bool dict_present = false; bool dict_present = false;
if(dict_type == IclassEliteDictTypeFlipper) { if(dict_type == IclassEliteDictTypeFlipper) {
dict_present = storage_common_stat(storage, ICLASS_ELITE_DICT_FLIPPER_PATH, NULL) == dict_present =
FSE_OK; (storage_common_stat(storage, ICLASS_ELITE_DICT_FLIPPER_NAME, NULL) == FSE_OK);
} else if(dict_type == IclassEliteDictTypeUser) { } else if(dict_type == IclassEliteDictTypeUser) {
dict_present = storage_common_stat(storage, ICLASS_ELITE_DICT_USER_PATH, NULL) == FSE_OK; dict_present = (storage_common_stat(storage, ICLASS_ELITE_DICT_USER_NAME, NULL) == FSE_OK);
} }
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
@@ -36,27 +36,26 @@ IclassEliteDict* iclass_elite_dict_alloc(IclassEliteDictType dict_type) {
IclassEliteDict* dict = malloc(sizeof(IclassEliteDict)); IclassEliteDict* dict = malloc(sizeof(IclassEliteDict));
Storage* storage = furi_record_open(RECORD_STORAGE); Storage* storage = furi_record_open(RECORD_STORAGE);
dict->stream = buffered_file_stream_alloc(storage); dict->stream = buffered_file_stream_alloc(storage);
furi_record_close(RECORD_STORAGE);
FuriString* next_line = furi_string_alloc(); FuriString* next_line = furi_string_alloc();
bool dict_loaded = false; bool dict_loaded = false;
do { do {
if(dict_type == IclassEliteDictTypeFlipper) { if(dict_type == IclassEliteDictTypeFlipper) {
if(!buffered_file_stream_open( if(!buffered_file_stream_open(
dict->stream, ICLASS_ELITE_DICT_FLIPPER_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { dict->stream, ICLASS_ELITE_DICT_FLIPPER_NAME, FSAM_READ, FSOM_OPEN_EXISTING)) {
buffered_file_stream_close(dict->stream); buffered_file_stream_close(dict->stream);
break; break;
} }
} else if(dict_type == IclassEliteDictTypeUser) { } else if(dict_type == IclassEliteDictTypeUser) {
if(!buffered_file_stream_open( if(!buffered_file_stream_open(
dict->stream, ICLASS_ELITE_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) { dict->stream, ICLASS_ELITE_DICT_USER_NAME, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) {
buffered_file_stream_close(dict->stream); buffered_file_stream_close(dict->stream);
break; break;
} }
} }
// Read total amount of keys // Read total amount of keys
while(true) { while(true) { //-V547
if(!stream_read_line(dict->stream, next_line)) break; if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue; if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != ICLASS_ELITE_KEY_LINE_LEN) continue; if(furi_string_size(next_line) != ICLASS_ELITE_KEY_LINE_LEN) continue;
@@ -69,12 +68,13 @@ IclassEliteDict* iclass_elite_dict_alloc(IclassEliteDictType dict_type) {
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys); FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys);
} while(false); } while(false);
if(!dict_loaded) { if(!dict_loaded) { //-V547
buffered_file_stream_close(dict->stream); buffered_file_stream_close(dict->stream);
free(dict); free(dict);
dict = NULL; dict = NULL;
} }
furi_record_close(RECORD_STORAGE);
furi_string_free(next_line); furi_string_free(next_line);
return dict; return dict;

View File

@@ -171,6 +171,12 @@ void picopass_show_loading_popup(void* context, bool show) {
} }
} }
static void picopass_migrate_from_old_folder() {
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_migrate(storage, "/ext/picopass", STORAGE_APP_DATA_PATH_PREFIX);
furi_record_close(RECORD_STORAGE);
}
bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size) { bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size) {
bool result = size > 0; bool result = size > 0;
while(size > 0) { while(size > 0) {
@@ -183,6 +189,8 @@ bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size)
int32_t picopass_app(void* p) { int32_t picopass_app(void* p) {
UNUSED(p); UNUSED(p);
picopass_migrate_from_old_folder();
Picopass* picopass = picopass_alloc(); Picopass* picopass = picopass_alloc();
scene_manager_next_scene(picopass->scene_manager, PicopassSceneStart); scene_manager_next_scene(picopass->scene_manager, PicopassSceneStart);

View File

@@ -48,13 +48,9 @@ static bool picopass_device_save_file(
if(use_load_path && !furi_string_empty(dev->load_path)) { if(use_load_path && !furi_string_empty(dev->load_path)) {
// Get directory name // Get directory name
path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str); path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str);
// Create picopass directory if necessary
if(!storage_simply_mkdir(dev->storage, furi_string_get_cstr(temp_str))) break;
// Make path to file to save // Make path to file to save
furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension); furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
} else { } else {
// Create picopass directory if necessary
if(!storage_simply_mkdir(dev->storage, PICOPASS_APP_FOLDER)) break;
// First remove picopass device file if it was saved // First remove picopass device file if it was saved
furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
} }
@@ -126,10 +122,11 @@ static bool picopass_device_save_file(
bool picopass_device_save(PicopassDevice* dev, const char* dev_name) { bool picopass_device_save(PicopassDevice* dev, const char* dev_name) {
if(dev->format == PicopassDeviceSaveFormatHF) { if(dev->format == PicopassDeviceSaveFormatHF) {
return picopass_device_save_file( return picopass_device_save_file(
dev, dev_name, PICOPASS_APP_FOLDER, PICOPASS_APP_EXTENSION, true); dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, PICOPASS_APP_EXTENSION, true);
} else if(dev->format == PicopassDeviceSaveFormatLF) { } else if(dev->format == PicopassDeviceSaveFormatLF) {
return picopass_device_save_file(dev, dev_name, ANY_PATH("lfrfid"), ".rfid", true); return picopass_device_save_file(dev, dev_name, ANY_PATH("lfrfid"), ".rfid", true);
} }
return false; return false;
} }
@@ -225,13 +222,12 @@ void picopass_device_free(PicopassDevice* picopass_dev) {
bool picopass_file_select(PicopassDevice* dev) { bool picopass_file_select(PicopassDevice* dev) {
furi_assert(dev); furi_assert(dev);
// Input events and views are managed by file_browser
FuriString* picopass_app_folder; FuriString* picopass_app_folder;
picopass_app_folder = furi_string_alloc_set(PICOPASS_APP_FOLDER); picopass_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
DialogsFileBrowserOptions browser_options; DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, PICOPASS_APP_EXTENSION, &I_Nfc_10px); dialog_file_browser_set_basic_options(&browser_options, PICOPASS_APP_EXTENSION, &I_Nfc_10px);
browser_options.base_path = PICOPASS_APP_FOLDER; browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
bool res = dialog_file_browser_show( bool res = dialog_file_browser_show(
dev->dialogs, dev->load_path, picopass_app_folder, &browser_options); dev->dialogs, dev->load_path, picopass_app_folder, &browser_options);
@@ -274,7 +270,7 @@ bool picopass_device_delete(PicopassDevice* dev, bool use_load_path) {
furi_string_set(file_path, dev->load_path); furi_string_set(file_path, dev->load_path);
} else { } else {
furi_string_printf( furi_string_printf(
file_path, "%s/%s%s", PICOPASS_APP_FOLDER, dev->dev_name, PICOPASS_APP_EXTENSION); file_path, APP_DATA_PATH("%s%s"), dev->dev_name, PICOPASS_APP_EXTENSION);
} }
if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break; if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
deleted = true; deleted = true;

View File

@@ -24,7 +24,6 @@
#define PICOPASS_AIA_BLOCK_INDEX 5 #define PICOPASS_AIA_BLOCK_INDEX 5
#define PICOPASS_PACS_CFG_BLOCK_INDEX 6 #define PICOPASS_PACS_CFG_BLOCK_INDEX 6
#define PICOPASS_APP_FOLDER ANY_PATH("picopass")
#define PICOPASS_APP_EXTENSION ".picopass" #define PICOPASS_APP_EXTENSION ".picopass"
#define PICOPASS_APP_SHADOW_EXTENSION ".pas" #define PICOPASS_APP_SHADOW_EXTENSION ".pas"
@@ -81,7 +80,6 @@ typedef struct {
PicopassDeviceSaveFormat format; PicopassDeviceSaveFormat format;
PicopassLoadingCallback loading_cb; PicopassLoadingCallback loading_cb;
void* loading_cb_ctx; void* loading_cb_ctx;
} PicopassDevice; } PicopassDevice;
PicopassDevice* picopass_device_alloc(); PicopassDevice* picopass_device_alloc();

View File

@@ -31,12 +31,10 @@ void picopass_scene_save_name_on_enter(void* context) {
dev_name_empty); dev_name_empty);
FuriString* folder_path; FuriString* folder_path;
folder_path = furi_string_alloc(); folder_path = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
if(furi_string_end_with(picopass->dev->load_path, PICOPASS_APP_EXTENSION)) { if(furi_string_end_with(picopass->dev->load_path, PICOPASS_APP_EXTENSION)) {
path_extract_dirname(furi_string_get_cstr(picopass->dev->load_path), folder_path); path_extract_dirname(furi_string_get_cstr(picopass->dev->load_path), folder_path);
} else {
furi_string_set(folder_path, PICOPASS_APP_FOLDER);
} }
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(

View File

@@ -21,12 +21,12 @@ void pcsg_block_generic_get_preset_name(const char* preset_name, FuriString* pre
furi_string_set(preset_str, preset_name_temp); furi_string_set(preset_str, preset_name_temp);
} }
bool pcsg_block_generic_serialize( SubGhzProtocolStatus pcsg_block_generic_serialize(
PCSGBlockGeneric* instance, PCSGBlockGeneric* instance,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
furi_assert(instance); furi_assert(instance);
bool res = false; SubGhzProtocolStatus res = SubGhzProtocolStatusError;
FuriString* temp_str; FuriString* temp_str;
temp_str = furi_string_alloc(); temp_str = furi_string_alloc();
do { do {
@@ -75,15 +75,16 @@ bool pcsg_block_generic_serialize(
break; break;
} }
res = true; res = SubGhzProtocolStatusOk;
} while(false); } while(false);
furi_string_free(temp_str); furi_string_free(temp_str);
return res; return res;
} }
bool pcsg_block_generic_deserialize(PCSGBlockGeneric* instance, FlipperFormat* flipper_format) { SubGhzProtocolStatus
pcsg_block_generic_deserialize(PCSGBlockGeneric* instance, FlipperFormat* flipper_format) {
furi_assert(instance); furi_assert(instance);
bool res = false; SubGhzProtocolStatus res = SubGhzProtocolStatusError;
FuriString* temp_data = furi_string_alloc(); FuriString* temp_data = furi_string_alloc();
FuriString* temp_data2 = furi_string_alloc(); FuriString* temp_data2 = furi_string_alloc();
@@ -113,7 +114,7 @@ bool pcsg_block_generic_deserialize(PCSGBlockGeneric* instance, FlipperFormat* f
instance->result_msg = furi_string_alloc_set(temp_data); instance->result_msg = furi_string_alloc_set(temp_data);
} }
res = true; res = SubGhzProtocolStatusOk;
} while(0); } while(0);
furi_string_free(temp_data); furi_string_free(temp_data);

View File

@@ -35,7 +35,7 @@ void pcsg_block_generic_get_preset_name(const char* preset_name, FuriString* pre
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return true On success
*/ */
bool pcsg_block_generic_serialize( SubGhzProtocolStatus pcsg_block_generic_serialize(
PCSGBlockGeneric* instance, PCSGBlockGeneric* instance,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -46,7 +46,8 @@ bool pcsg_block_generic_serialize(
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return true On success
*/ */
bool pcsg_block_generic_deserialize(PCSGBlockGeneric* instance, FlipperFormat* flipper_format); SubGhzProtocolStatus
pcsg_block_generic_deserialize(PCSGBlockGeneric* instance, FlipperFormat* flipper_format);
float pcsg_block_generic_fahrenheit_to_celsius(float fahrenheit); float pcsg_block_generic_fahrenheit_to_celsius(float fahrenheit);

View File

@@ -288,7 +288,7 @@ uint8_t subghz_protocol_decoder_pocsag_get_hash_data(void* context) {
return hash; return hash;
} }
bool subghz_protocol_decoder_pocsag_serialize( SubGhzProtocolStatus subghz_protocol_decoder_pocsag_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -296,31 +296,35 @@ bool subghz_protocol_decoder_pocsag_serialize(
SubGhzProtocolDecoderPocsag* instance = context; SubGhzProtocolDecoderPocsag* instance = context;
uint32_t msg_len; uint32_t msg_len;
if(!pcsg_block_generic_serialize(&instance->generic, flipper_format, preset)) return false; if(SubGhzProtocolStatusOk !=
pcsg_block_generic_serialize(&instance->generic, flipper_format, preset))
return SubGhzProtocolStatusError;
msg_len = furi_string_size(instance->done_msg); msg_len = furi_string_size(instance->done_msg);
if(!flipper_format_write_uint32(flipper_format, "MsgLen", &msg_len, 1)) { if(!flipper_format_write_uint32(flipper_format, "MsgLen", &msg_len, 1)) {
FURI_LOG_E(TAG, "Error adding MsgLen"); FURI_LOG_E(TAG, "Error adding MsgLen");
return false; return SubGhzProtocolStatusError;
} }
uint8_t* s = (uint8_t*)furi_string_get_cstr(instance->done_msg); uint8_t* s = (uint8_t*)furi_string_get_cstr(instance->done_msg);
if(!flipper_format_write_hex(flipper_format, "Msg", s, msg_len)) { if(!flipper_format_write_hex(flipper_format, "Msg", s, msg_len)) {
FURI_LOG_E(TAG, "Error adding Msg"); FURI_LOG_E(TAG, "Error adding Msg");
return false; return SubGhzProtocolStatusError;
} }
return true; return SubGhzProtocolStatusOk;
} }
bool subghz_protocol_decoder_pocsag_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
subghz_protocol_decoder_pocsag_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
SubGhzProtocolDecoderPocsag* instance = context; SubGhzProtocolDecoderPocsag* instance = context;
bool ret = false; SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
uint32_t msg_len; uint32_t msg_len;
uint8_t* buf; uint8_t* buf;
do { do {
if(!pcsg_block_generic_deserialize(&instance->generic, flipper_format)) { if(SubGhzProtocolStatusOk !=
pcsg_block_generic_deserialize(&instance->generic, flipper_format)) {
break; break;
} }
@@ -338,7 +342,7 @@ bool subghz_protocol_decoder_pocsag_deserialize(void* context, FlipperFormat* fl
furi_string_set_strn(instance->done_msg, (const char*)buf, msg_len); furi_string_set_strn(instance->done_msg, (const char*)buf, msg_len);
free(buf); free(buf);
ret = true; ret = SubGhzProtocolStatusOk;
} while(false); } while(false);
return ret; return ret;
} }

View File

@@ -60,7 +60,7 @@ bool spi_mem_scene_start_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect); scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
success = true; success = true;
} else if(event.event == SPIMemSceneStartSubmenuIndexSaved) { } else if(event.event == SPIMemSceneStartSubmenuIndexSaved) {
furi_string_set(app->file_path, SPI_MEM_FILE_FOLDER); furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectFile); scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectFile);
success = true; success = true;
} else if(event.event == SPIMemSceneStartSubmenuIndexErase) { } else if(event.event == SPIMemSceneStartSubmenuIndexErase) {

View File

@@ -16,9 +16,9 @@ static bool spi_mem_back_event_callback(void* context) {
} }
SPIMemApp* spi_mem_alloc(void) { SPIMemApp* spi_mem_alloc(void) {
SPIMemApp* instance = malloc(sizeof(SPIMemApp)); SPIMemApp* instance = malloc(sizeof(SPIMemApp)); //-V799
instance->file_path = furi_string_alloc(); instance->file_path = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
instance->gui = furi_record_open(RECORD_GUI); instance->gui = furi_record_open(RECORD_GUI);
instance->notifications = furi_record_open(RECORD_NOTIFICATION); instance->notifications = furi_record_open(RECORD_NOTIFICATION);
instance->view_dispatcher = view_dispatcher_alloc(); instance->view_dispatcher = view_dispatcher_alloc();
@@ -37,7 +37,8 @@ SPIMemApp* spi_mem_alloc(void) {
instance->text_input = text_input_alloc(); instance->text_input = text_input_alloc();
instance->mode = SPIMemModeUnknown; instance->mode = SPIMemModeUnknown;
furi_string_set(instance->file_path, SPI_MEM_FILE_FOLDER); // Migrate data from old sd-card folder
storage_common_migrate(instance->storage, EXT_PATH("spimem"), STORAGE_APP_DATA_PATH_PREFIX);
view_dispatcher_enable_queue(instance->view_dispatcher); view_dispatcher_enable_queue(instance->view_dispatcher);
view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance);
@@ -70,7 +71,7 @@ SPIMemApp* spi_mem_alloc(void) {
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_external); furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_external);
scene_manager_next_scene(instance->scene_manager, SPIMemSceneStart); scene_manager_next_scene(instance->scene_manager, SPIMemSceneStart);
return instance; return instance;
} } //-V773
void spi_mem_free(SPIMemApp* instance) { void spi_mem_free(SPIMemApp* instance) {
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewSubmenu); view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewSubmenu);
@@ -105,7 +106,6 @@ void spi_mem_free(SPIMemApp* instance) {
int32_t spi_mem_app(void* p) { int32_t spi_mem_app(void* p) {
UNUSED(p); UNUSED(p);
SPIMemApp* instance = spi_mem_alloc(); SPIMemApp* instance = spi_mem_alloc();
spi_mem_file_create_folder(instance);
view_dispatcher_run(instance->view_dispatcher); view_dispatcher_run(instance->view_dispatcher);
spi_mem_free(instance); spi_mem_free(instance);
return 0; return 0;

View File

@@ -24,7 +24,6 @@
#define TAG "SPIMem" #define TAG "SPIMem"
#define SPI_MEM_FILE_EXTENSION ".bin" #define SPI_MEM_FILE_EXTENSION ".bin"
#define SPI_MEM_FILE_FOLDER EXT_PATH("spimem")
#define SPI_MEM_FILE_NAME_SIZE 100 #define SPI_MEM_FILE_NAME_SIZE 100
#define SPI_MEM_TEXT_BUFFER_SIZE 128 #define SPI_MEM_TEXT_BUFFER_SIZE 128

View File

@@ -1,11 +1,5 @@
#include "spi_mem_app_i.h" #include "spi_mem_app_i.h"
void spi_mem_file_create_folder(SPIMemApp* app) {
if(!storage_simply_mkdir(app->storage, SPI_MEM_FILE_FOLDER)) {
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
}
}
bool spi_mem_file_delete(SPIMemApp* app) { bool spi_mem_file_delete(SPIMemApp* app) {
return (storage_simply_remove(app->storage, furi_string_get_cstr(app->file_path))); return (storage_simply_remove(app->storage, furi_string_get_cstr(app->file_path)));
} }
@@ -13,7 +7,7 @@ bool spi_mem_file_delete(SPIMemApp* app) {
bool spi_mem_file_select(SPIMemApp* app) { bool spi_mem_file_select(SPIMemApp* app) {
DialogsFileBrowserOptions browser_options; DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, SPI_MEM_FILE_EXTENSION, &I_Dip8_10px); dialog_file_browser_set_basic_options(&browser_options, SPI_MEM_FILE_EXTENSION, &I_Dip8_10px);
browser_options.base_path = SPI_MEM_FILE_FOLDER; browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
bool success = bool success =
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
return success; return success;

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "spi_mem_app.h" #include "spi_mem_app.h"
void spi_mem_file_create_folder(SPIMemApp* app);
bool spi_mem_file_select(SPIMemApp* app); bool spi_mem_file_select(SPIMemApp* app);
bool spi_mem_file_create(SPIMemApp* app, const char* file_name); bool spi_mem_file_create(SPIMemApp* app, const char* file_name);
bool spi_mem_file_delete(SPIMemApp* app); bool spi_mem_file_delete(SPIMemApp* app);

View File

@@ -3,7 +3,7 @@
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#define WS_VERSION_APP "0.7" #define WS_VERSION_APP "0.8"
#define WS_DEVELOPED "SkorP" #define WS_DEVELOPED "SkorP"
#define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"

View File

@@ -258,7 +258,7 @@ uint8_t ws_protocol_decoder_acurite_592txr_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_acurite_592txr_serialize( SubGhzProtocolStatus ws_protocol_decoder_acurite_592txr_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -267,22 +267,14 @@ bool ws_protocol_decoder_acurite_592txr_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderAcurite_592TXR* instance = context; WSProtocolDecoderAcurite_592TXR* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic,
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { flipper_format,
break; ws_protocol_acurite_592txr_const.min_count_bit_for_found);
}
if(instance->generic.data_count_bit !=
ws_protocol_acurite_592txr_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output) { void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_acurite_592txr_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_acurite_592txr_serialize( SubGhzProtocolStatus ws_protocol_decoder_acurite_592txr_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_acurite_592txr_serialize(
* Deserialize data WSProtocolDecoderAcurite_592TXR. * Deserialize data WSProtocolDecoderAcurite_592TXR.
* @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance * @param context Pointer to a WSProtocolDecoderAcurite_592TXR instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -199,7 +199,7 @@ uint8_t ws_protocol_decoder_acurite_606tx_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_acurite_606tx_serialize( SubGhzProtocolStatus ws_protocol_decoder_acurite_606tx_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -208,22 +208,14 @@ bool ws_protocol_decoder_acurite_606tx_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_acurite_606tx_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_acurite_606tx_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderAcurite_606TX* instance = context; WSProtocolDecoderAcurite_606TX* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic,
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { flipper_format,
break; ws_protocol_acurite_606tx_const.min_count_bit_for_found);
}
if(instance->generic.data_count_bit !=
ws_protocol_acurite_606tx_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* output) { void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_acurite_606tx_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderAcurite_606TX instance * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_acurite_606tx_serialize( SubGhzProtocolStatus ws_protocol_decoder_acurite_606tx_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_acurite_606tx_serialize(
* Deserialize data WSProtocolDecoderAcurite_606TX. * Deserialize data WSProtocolDecoderAcurite_606TX.
* @param context Pointer to a WSProtocolDecoderAcurite_606TX instance * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_acurite_606tx_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_acurite_606tx_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -199,7 +199,7 @@ uint8_t ws_protocol_decoder_acurite_609txc_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_acurite_609txc_serialize( SubGhzProtocolStatus ws_protocol_decoder_acurite_609txc_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -208,22 +208,14 @@ bool ws_protocol_decoder_acurite_609txc_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context; WSProtocolDecoderAcurite_609TXC* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic,
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { flipper_format,
break; ws_protocol_acurite_609txc_const.min_count_bit_for_found);
}
if(instance->generic.data_count_bit !=
ws_protocol_acurite_609txc_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output) { void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_acurite_609txc_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance * @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_acurite_609txc_serialize( SubGhzProtocolStatus ws_protocol_decoder_acurite_609txc_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_acurite_609txc_serialize(
* Deserialize data WSProtocolDecoderAcurite_609TXC. * Deserialize data WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance * @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -228,7 +228,7 @@ uint8_t ws_protocol_decoder_ambient_weather_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_ambient_weather_serialize( SubGhzProtocolStatus ws_protocol_decoder_ambient_weather_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -237,22 +237,14 @@ bool ws_protocol_decoder_ambient_weather_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_ambient_weather_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_ambient_weather_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context; WSProtocolDecoderAmbient_Weather* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic,
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { flipper_format,
break; ws_protocol_ambient_weather_const.min_count_bit_for_found);
}
if(instance->generic.data_count_bit !=
ws_protocol_ambient_weather_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* output) { void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_ambient_weather_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance * @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_ambient_weather_serialize( SubGhzProtocolStatus ws_protocol_decoder_ambient_weather_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_ambient_weather_serialize(
* Deserialize data WSProtocolDecoderAmbient_Weather. * Deserialize data WSProtocolDecoderAmbient_Weather.
* @param context Pointer to a WSProtocolDecoderAmbient_Weather instance * @param context Pointer to a WSProtocolDecoderAmbient_Weather instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_ambient_weather_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_ambient_weather_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -210,7 +210,7 @@ uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_auriol_th_serialize( SubGhzProtocolStatus ws_protocol_decoder_auriol_th_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -219,22 +219,12 @@ bool ws_protocol_decoder_auriol_th_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderAuriol_TH* instance = context; WSProtocolDecoderAuriol_TH* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_auriol_th_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_auriol_th_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) { void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderAuriol_TH instance * @param context Pointer to a WSProtocolDecoderAuriol_TH instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_auriol_th_serialize( SubGhzProtocolStatus ws_protocol_decoder_auriol_th_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_auriol_th_serialize(
* Deserialize data WSProtocolDecoderAuriol_TH. * Deserialize data WSProtocolDecoderAuriol_TH.
* @param context Pointer to a WSProtocolDecoderAuriol_TH instance * @param context Pointer to a WSProtocolDecoderAuriol_TH instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -217,7 +217,7 @@ uint8_t ws_protocol_decoder_gt_wt_02_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_gt_wt_02_serialize( SubGhzProtocolStatus ws_protocol_decoder_gt_wt_02_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -226,22 +226,12 @@ bool ws_protocol_decoder_gt_wt_02_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_gt_wt_02_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_gt_wt_02_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderGT_WT02* instance = context; WSProtocolDecoderGT_WT02* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_gt_wt_02_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_gt_wt_02_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_gt_wt_02_get_string(void* context, FuriString* output) { void ws_protocol_decoder_gt_wt_02_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_gt_wt_02_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderGT_WT02 instance * @param context Pointer to a WSProtocolDecoderGT_WT02 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_gt_wt_02_serialize( SubGhzProtocolStatus ws_protocol_decoder_gt_wt_02_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_gt_wt_02_serialize(
* Deserialize data WSProtocolDecoderGT_WT02. * Deserialize data WSProtocolDecoderGT_WT02.
* @param context Pointer to a WSProtocolDecoderGT_WT02 instance * @param context Pointer to a WSProtocolDecoderGT_WT02 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_gt_wt_02_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_gt_wt_02_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -292,7 +292,7 @@ uint8_t ws_protocol_decoder_gt_wt_03_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_gt_wt_03_serialize( SubGhzProtocolStatus ws_protocol_decoder_gt_wt_03_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -301,22 +301,12 @@ bool ws_protocol_decoder_gt_wt_03_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_gt_wt_03_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_gt_wt_03_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderGT_WT03* instance = context; WSProtocolDecoderGT_WT03* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_gt_wt_03_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_gt_wt_03_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_gt_wt_03_get_string(void* context, FuriString* output) { void ws_protocol_decoder_gt_wt_03_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_gt_wt_03_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderGT_WT03 instance * @param context Pointer to a WSProtocolDecoderGT_WT03 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_gt_wt_03_serialize( SubGhzProtocolStatus ws_protocol_decoder_gt_wt_03_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_gt_wt_03_serialize(
* Deserialize data WSProtocolDecoderGT_WT03. * Deserialize data WSProtocolDecoderGT_WT03.
* @param context Pointer to a WSProtocolDecoderGT_WT03 instance * @param context Pointer to a WSProtocolDecoderGT_WT03 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_gt_wt_03_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_gt_wt_03_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -248,7 +248,7 @@ uint8_t ws_protocol_decoder_infactory_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_infactory_serialize( SubGhzProtocolStatus ws_protocol_decoder_infactory_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -257,22 +257,12 @@ bool ws_protocol_decoder_infactory_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_infactory_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_infactory_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderInfactory* instance = context; WSProtocolDecoderInfactory* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_infactory_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_infactory_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_infactory_get_string(void* context, FuriString* output) { void ws_protocol_decoder_infactory_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_infactory_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderInfactory instance * @param context Pointer to a WSProtocolDecoderInfactory instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_infactory_serialize( SubGhzProtocolStatus ws_protocol_decoder_infactory_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_infactory_serialize(
* Deserialize data WSProtocolDecoderInfactory. * Deserialize data WSProtocolDecoderInfactory.
* @param context Pointer to a WSProtocolDecoderInfactory instance * @param context Pointer to a WSProtocolDecoderInfactory instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_infactory_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_infactory_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -281,7 +281,7 @@ uint8_t ws_protocol_decoder_lacrosse_tx_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_lacrosse_tx_serialize( SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -290,22 +290,12 @@ bool ws_protocol_decoder_lacrosse_tx_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderLaCrosse_TX* instance = context; WSProtocolDecoderLaCrosse_TX* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_lacrosse_tx_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_lacrosse_tx_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output) { void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_lacrosse_tx_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_lacrosse_tx_serialize( SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_lacrosse_tx_serialize(
* Deserialize data WSProtocolDecoderLaCrosse_TX. * Deserialize data WSProtocolDecoderLaCrosse_TX.
* @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -247,7 +247,7 @@ uint8_t ws_protocol_decoder_lacrosse_tx141thbv2_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx141thbv2_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -256,24 +256,15 @@ bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_lacrosse_tx141thbv2_deserialize( SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx141thbv2_deserialize(
void* context, void* context,
FlipperFormat* flipper_format) { FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; WSProtocolDecoderLaCrosse_TX141THBv2* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic,
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { flipper_format,
break; ws_protocol_lacrosse_tx141thbv2_const.min_count_bit_for_found);
}
if(instance->generic.data_count_bit !=
ws_protocol_lacrosse_tx141thbv2_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriString* output) { void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_lacrosse_tx141thbv2_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx141thbv2_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,9 @@ bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize(
* Deserialize data WSProtocolDecoderLaCrosse_TX141THBv2. * Deserialize data WSProtocolDecoderLaCrosse_TX141THBv2.
* @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_lacrosse_tx141thbv2_deserialize( SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx141thbv2_deserialize(
void* context, void* context,
FlipperFormat* flipper_format); FlipperFormat* flipper_format);

View File

@@ -216,7 +216,7 @@ uint8_t ws_protocol_decoder_nexus_th_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_nexus_th_serialize( SubGhzProtocolStatus ws_protocol_decoder_nexus_th_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -225,22 +225,12 @@ bool ws_protocol_decoder_nexus_th_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_nexus_th_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_nexus_th_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderNexus_TH* instance = context; WSProtocolDecoderNexus_TH* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_nexus_th_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_nexus_th_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output) { void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_nexus_th_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderNexus_TH instance * @param context Pointer to a WSProtocolDecoderNexus_TH instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_nexus_th_serialize( SubGhzProtocolStatus ws_protocol_decoder_nexus_th_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_nexus_th_serialize(
* Deserialize data WSProtocolDecoderNexus_TH. * Deserialize data WSProtocolDecoderNexus_TH.
* @param context Pointer to a WSProtocolDecoderNexus_TH instance * @param context Pointer to a WSProtocolDecoderNexus_TH instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_nexus_th_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_nexus_th_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -302,17 +302,19 @@ uint8_t ws_protocol_decoder_oregon2_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_oregon2_serialize( SubGhzProtocolStatus ws_protocol_decoder_oregon2_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderOregon2* instance = context; WSProtocolDecoderOregon2* instance = context;
if(!ws_block_generic_serialize(&instance->generic, flipper_format, preset)) return false; SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
ret = ws_block_generic_serialize(&instance->generic, flipper_format, preset);
if(ret != SubGhzProtocolStatusOk) return ret;
uint32_t temp = instance->var_bits; uint32_t temp = instance->var_bits;
if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) { if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) {
FURI_LOG_E(TAG, "Error adding VarBits"); FURI_LOG_E(TAG, "Error adding VarBits");
return false; return SubGhzProtocolStatusErrorParserOthers;
} }
if(!flipper_format_write_hex( if(!flipper_format_write_hex(
flipper_format, flipper_format,
@@ -320,22 +322,25 @@ bool ws_protocol_decoder_oregon2_serialize(
(const uint8_t*)&instance->var_data, (const uint8_t*)&instance->var_data,
sizeof(instance->var_data))) { sizeof(instance->var_data))) {
FURI_LOG_E(TAG, "Error adding VarData"); FURI_LOG_E(TAG, "Error adding VarData");
return false; return SubGhzProtocolStatusErrorParserOthers;
} }
return true; return ret;
} }
bool ws_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderOregon2* instance = context; WSProtocolDecoderOregon2* instance = context;
bool ret = false;
uint32_t temp_data; uint32_t temp_data;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do { do {
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { ret = ws_block_generic_deserialize(&instance->generic, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
break; break;
} }
if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) {
FURI_LOG_E(TAG, "Missing VarLen"); FURI_LOG_E(TAG, "Missing VarLen");
ret = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->var_bits = (uint8_t)temp_data; instance->var_bits = (uint8_t)temp_data;
@@ -345,13 +350,14 @@ bool ws_protocol_decoder_oregon2_deserialize(void* context, FlipperFormat* flipp
(uint8_t*)&instance->var_data, (uint8_t*)&instance->var_data,
sizeof(instance->var_data))) { //-V1051 sizeof(instance->var_data))) { //-V1051
FURI_LOG_E(TAG, "Missing VarData"); FURI_LOG_E(TAG, "Missing VarData");
ret = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
if(instance->generic.data_count_bit != ws_oregon2_const.min_count_bit_for_found) { if(instance->generic.data_count_bit != ws_oregon2_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit); FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit);
ret = SubGhzProtocolStatusErrorValueBitCount;
break; break;
} }
ret = true;
} while(false); } while(false);
return ret; return ret;
} }

View File

@@ -283,7 +283,7 @@ uint8_t ws_protocol_decoder_oregon_v1_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_oregon_v1_serialize( SubGhzProtocolStatus ws_protocol_decoder_oregon_v1_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -292,22 +292,12 @@ bool ws_protocol_decoder_oregon_v1_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_oregon_v1_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_oregon_v1_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context; WSProtocolDecoderOregon_V1* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_oregon_v1_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_oregon_v1_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_oregon_v1_get_string(void* context, FuriString* output) { void ws_protocol_decoder_oregon_v1_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_oregon_v1_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance * @param context Pointer to a WSProtocolDecoderOregon_V1 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_oregon_v1_serialize( SubGhzProtocolStatus ws_protocol_decoder_oregon_v1_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_oregon_v1_serialize(
* Deserialize data WSProtocolDecoderOregon_V1. * Deserialize data WSProtocolDecoderOregon_V1.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance * @param context Pointer to a WSProtocolDecoderOregon_V1 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_oregon_v1_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_oregon_v1_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -211,7 +211,7 @@ uint8_t ws_protocol_decoder_thermopro_tx4_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_thermopro_tx4_serialize( SubGhzProtocolStatus ws_protocol_decoder_thermopro_tx4_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -220,22 +220,14 @@ bool ws_protocol_decoder_thermopro_tx4_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_thermopro_tx4_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_thermopro_tx4_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderThermoPRO_TX4* instance = context; WSProtocolDecoderThermoPRO_TX4* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic,
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { flipper_format,
break; ws_protocol_thermopro_tx4_const.min_count_bit_for_found);
}
if(instance->generic.data_count_bit !=
ws_protocol_thermopro_tx4_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_thermopro_tx4_get_string(void* context, FuriString* output) { void ws_protocol_decoder_thermopro_tx4_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_thermopro_tx4_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderThermoPRO_TX4 instance * @param context Pointer to a WSProtocolDecoderThermoPRO_TX4 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_thermopro_tx4_serialize( SubGhzProtocolStatus ws_protocol_decoder_thermopro_tx4_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_thermopro_tx4_serialize(
* Deserialize data WSProtocolDecoderThermoPRO_TX4. * Deserialize data WSProtocolDecoderThermoPRO_TX4.
* @param context Pointer to a WSProtocolDecoderThermoPRO_TX4 instance * @param context Pointer to a WSProtocolDecoderThermoPRO_TX4 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_thermopro_tx4_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_thermopro_tx4_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -246,7 +246,7 @@ uint8_t ws_protocol_decoder_tx_8300_get_hash_data(void* context) {
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
} }
bool ws_protocol_decoder_tx_8300_serialize( SubGhzProtocolStatus ws_protocol_decoder_tx_8300_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
@@ -255,21 +255,12 @@ bool ws_protocol_decoder_tx_8300_serialize(
return ws_block_generic_serialize(&instance->generic, flipper_format, preset); return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
} }
bool ws_protocol_decoder_tx_8300_deserialize(void* context, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_protocol_decoder_tx_8300_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context); furi_assert(context);
WSProtocolDecoderTX_8300* instance = context; WSProtocolDecoderTX_8300* instance = context;
bool ret = false; return ws_block_generic_deserialize_check_count_bit(
do { &instance->generic, flipper_format, ws_protocol_tx_8300_const.min_count_bit_for_found);
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit != ws_protocol_tx_8300_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
} }
void ws_protocol_decoder_tx_8300_get_string(void* context, FuriString* output) { void ws_protocol_decoder_tx_8300_get_string(void* context, FuriString* output) {

View File

@@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_tx_8300_get_hash_data(void* context);
* @param context Pointer to a WSProtocolDecoderTX_8300 instance * @param context Pointer to a WSProtocolDecoderTX_8300 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_tx_8300_serialize( SubGhzProtocolStatus ws_protocol_decoder_tx_8300_serialize(
void* context, void* context,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -67,9 +67,10 @@ bool ws_protocol_decoder_tx_8300_serialize(
* Deserialize data WSProtocolDecoderTX_8300. * Deserialize data WSProtocolDecoderTX_8300.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance * @param context Pointer to a WSProtocolDecoderTX_8300 instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_protocol_decoder_tx_8300_deserialize(void* context, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_protocol_decoder_tx_8300_deserialize(void* context, FlipperFormat* flipper_format);
/** /**
* Getting a textual representation of the received data. * Getting a textual representation of the received data.

View File

@@ -21,12 +21,12 @@ void ws_block_generic_get_preset_name(const char* preset_name, FuriString* prese
furi_string_set(preset_str, preset_name_temp); furi_string_set(preset_str, preset_name_temp);
} }
bool ws_block_generic_serialize( SubGhzProtocolStatus ws_block_generic_serialize(
WSBlockGeneric* instance, WSBlockGeneric* instance,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) { SubGhzRadioPreset* preset) {
furi_assert(instance); furi_assert(instance);
bool res = false; SubGhzProtocolStatus res = SubGhzProtocolStatusError;
FuriString* temp_str; FuriString* temp_str;
temp_str = furi_string_alloc(); temp_str = furi_string_alloc();
do { do {
@@ -34,11 +34,13 @@ bool ws_block_generic_serialize(
if(!flipper_format_write_header_cstr( if(!flipper_format_write_header_cstr(
flipper_format, WS_KEY_FILE_TYPE, WS_KEY_FILE_VERSION)) { flipper_format, WS_KEY_FILE_TYPE, WS_KEY_FILE_VERSION)) {
FURI_LOG_E(TAG, "Unable to add header"); FURI_LOG_E(TAG, "Unable to add header");
res = SubGhzProtocolStatusErrorParserHeader;
break; break;
} }
if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) {
FURI_LOG_E(TAG, "Unable to add Frequency"); FURI_LOG_E(TAG, "Unable to add Frequency");
res = SubGhzProtocolStatusErrorParserFrequency;
break; break;
} }
@@ -46,34 +48,40 @@ bool ws_block_generic_serialize(
if(!flipper_format_write_string_cstr( if(!flipper_format_write_string_cstr(
flipper_format, "Preset", furi_string_get_cstr(temp_str))) { flipper_format, "Preset", furi_string_get_cstr(temp_str))) {
FURI_LOG_E(TAG, "Unable to add Preset"); FURI_LOG_E(TAG, "Unable to add Preset");
res = SubGhzProtocolStatusErrorParserPreset;
break; break;
} }
if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
if(!flipper_format_write_string_cstr( if(!flipper_format_write_string_cstr(
flipper_format, "Custom_preset_module", "CC1101")) { flipper_format, "Custom_preset_module", "CC1101")) {
FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); FURI_LOG_E(TAG, "Unable to add Custom_preset_module");
res = SubGhzProtocolStatusErrorParserCustomPreset;
break; break;
} }
if(!flipper_format_write_hex( if(!flipper_format_write_hex(
flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { flipper_format, "Custom_preset_data", preset->data, preset->data_size)) {
FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); FURI_LOG_E(TAG, "Unable to add Custom_preset_data");
res = SubGhzProtocolStatusErrorParserCustomPreset;
break; break;
} }
} }
if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) { if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) {
FURI_LOG_E(TAG, "Unable to add Protocol"); FURI_LOG_E(TAG, "Unable to add Protocol");
res = SubGhzProtocolStatusErrorParserProtocolName;
break; break;
} }
uint32_t temp_data = instance->id; uint32_t temp_data = instance->id;
if(!flipper_format_write_uint32(flipper_format, "Id", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Id", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Id"); FURI_LOG_E(TAG, "Unable to add Id");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
temp_data = instance->data_count_bit; temp_data = instance->data_count_bit;
if(!flipper_format_write_uint32(flipper_format, "Bit", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Bit", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Bit"); FURI_LOG_E(TAG, "Unable to add Bit");
res = SubGhzProtocolStatusErrorParserBitCount;
break; break;
} }
@@ -84,18 +92,21 @@ bool ws_block_generic_serialize(
if(!flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { if(!flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to add Data"); FURI_LOG_E(TAG, "Unable to add Data");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
temp_data = instance->battery_low; temp_data = instance->battery_low;
if(!flipper_format_write_uint32(flipper_format, "Batt", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Batt", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Battery_low"); FURI_LOG_E(TAG, "Unable to add Battery_low");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
temp_data = instance->humidity; temp_data = instance->humidity;
if(!flipper_format_write_uint32(flipper_format, "Hum", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Hum", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Humidity"); FURI_LOG_E(TAG, "Unable to add Humidity");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
@@ -107,52 +118,60 @@ bool ws_block_generic_serialize(
temp_data = curr_ts; temp_data = curr_ts;
if(!flipper_format_write_uint32(flipper_format, "Ts", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Ts", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add timestamp"); FURI_LOG_E(TAG, "Unable to add timestamp");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
temp_data = instance->channel; temp_data = instance->channel;
if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Channel"); FURI_LOG_E(TAG, "Unable to add Channel");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
temp_data = instance->btn; temp_data = instance->btn;
if(!flipper_format_write_uint32(flipper_format, "Btn", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Btn", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Btn"); FURI_LOG_E(TAG, "Unable to add Btn");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
float temp = instance->temp; float temp = instance->temp;
if(!flipper_format_write_float(flipper_format, "Temp", &temp, 1)) { if(!flipper_format_write_float(flipper_format, "Temp", &temp, 1)) {
FURI_LOG_E(TAG, "Unable to add Temperature"); FURI_LOG_E(TAG, "Unable to add Temperature");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
res = true; res = SubGhzProtocolStatusOk;
} while(false); } while(false);
furi_string_free(temp_str); furi_string_free(temp_str);
return res; return res;
} }
bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipper_format) { SubGhzProtocolStatus
ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipper_format) {
furi_assert(instance); furi_assert(instance);
bool res = false; SubGhzProtocolStatus res = SubGhzProtocolStatusError;
uint32_t temp_data = 0; uint32_t temp_data = 0;
do { do {
if(!flipper_format_rewind(flipper_format)) { if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error"); FURI_LOG_E(TAG, "Rewind error");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
if(!flipper_format_read_uint32(flipper_format, "Id", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Id", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Id"); FURI_LOG_E(TAG, "Missing Id");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->id = (uint32_t)temp_data; instance->id = (uint32_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Bit"); FURI_LOG_E(TAG, "Missing Bit");
res = SubGhzProtocolStatusErrorParserBitCount;
break; break;
} }
instance->data_count_bit = (uint8_t)temp_data; instance->data_count_bit = (uint8_t)temp_data;
@@ -160,6 +179,7 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp
uint8_t key_data[sizeof(uint64_t)] = {0}; uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Data"); FURI_LOG_E(TAG, "Missing Data");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
@@ -169,30 +189,35 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp
if(!flipper_format_read_uint32(flipper_format, "Batt", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Batt", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Battery_low"); FURI_LOG_E(TAG, "Missing Battery_low");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->battery_low = (uint8_t)temp_data; instance->battery_low = (uint8_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Hum", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Hum", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Humidity"); FURI_LOG_E(TAG, "Missing Humidity");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->humidity = (uint8_t)temp_data; instance->humidity = (uint8_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Ts", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Ts", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing timestamp"); FURI_LOG_E(TAG, "Missing timestamp");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->timestamp = (uint32_t)temp_data; instance->timestamp = (uint32_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Channel"); FURI_LOG_E(TAG, "Missing Channel");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->channel = (uint8_t)temp_data; instance->channel = (uint8_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Btn", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Btn", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Btn"); FURI_LOG_E(TAG, "Missing Btn");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->btn = (uint8_t)temp_data; instance->btn = (uint8_t)temp_data;
@@ -200,12 +225,32 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp
float temp; float temp;
if(!flipper_format_read_float(flipper_format, "Temp", (float*)&temp, 1)) { if(!flipper_format_read_float(flipper_format, "Temp", (float*)&temp, 1)) {
FURI_LOG_E(TAG, "Missing Temperature"); FURI_LOG_E(TAG, "Missing Temperature");
res = SubGhzProtocolStatusErrorParserOthers;
break; break;
} }
instance->temp = temp; instance->temp = temp;
res = true; res = SubGhzProtocolStatusOk;
} while(0); } while(0);
return res; return res;
} }
SubGhzProtocolStatus ws_block_generic_deserialize_check_count_bit(
WSBlockGeneric* instance,
FlipperFormat* flipper_format,
uint16_t count_bit) {
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = ws_block_generic_deserialize(instance, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
break;
}
if(instance->data_count_bit != count_bit) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
} while(false);
return ret;
}

View File

@@ -48,9 +48,9 @@ void ws_block_generic_get_preset_name(const char* preset_name, FuriString* prese
* @param instance Pointer to a WSBlockGeneric instance * @param instance Pointer to a WSBlockGeneric instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset * @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success * @return status
*/ */
bool ws_block_generic_serialize( SubGhzProtocolStatus ws_block_generic_serialize(
WSBlockGeneric* instance, WSBlockGeneric* instance,
FlipperFormat* flipper_format, FlipperFormat* flipper_format,
SubGhzRadioPreset* preset); SubGhzRadioPreset* preset);
@@ -59,9 +59,22 @@ bool ws_block_generic_serialize(
* Deserialize data WSBlockGeneric. * Deserialize data WSBlockGeneric.
* @param instance Pointer to a WSBlockGeneric instance * @param instance Pointer to a WSBlockGeneric instance
* @param flipper_format Pointer to a FlipperFormat instance * @param flipper_format Pointer to a FlipperFormat instance
* @return true On success * @return status
*/ */
bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipper_format); SubGhzProtocolStatus
ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipper_format);
/**
* Deserialize data WSBlockGeneric.
* @param instance Pointer to a WSBlockGeneric instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param count_bit Count bit protocol
* @return status
*/
SubGhzProtocolStatus ws_block_generic_deserialize_check_count_bit(
WSBlockGeneric* instance,
FlipperFormat* flipper_format,
uint16_t count_bit);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -11,6 +11,7 @@ typedef enum {
typedef struct { typedef struct {
const FuriThreadCallback app; const FuriThreadCallback app;
const char* name; const char* name;
const char* appid;
const size_t stack_size; const size_t stack_size;
const Icon* icon; const Icon* icon;
const FlipperApplicationFlag flags; const FlipperApplicationFlag flags;

View File

@@ -45,7 +45,14 @@ void bt_keys_storage_set_storage_path(Bt* bt, const char* keys_storage_path) {
furi_assert(bt->keys_storage); furi_assert(bt->keys_storage);
furi_assert(keys_storage_path); furi_assert(keys_storage_path);
bt_keys_storage_set_file_path(bt->keys_storage, keys_storage_path); Storage* storage = furi_record_open(RECORD_STORAGE);
FuriString* path = furi_string_alloc_set(keys_storage_path);
storage_common_resolve_path_and_ensure_app_directory(storage, path);
bt_keys_storage_set_file_path(bt->keys_storage, furi_string_get_cstr(path));
furi_string_free(path);
furi_record_close(RECORD_STORAGE);
} }
void bt_keys_storage_set_default_path(Bt* bt) { void bt_keys_storage_set_default_path(Bt* bt) {

View File

@@ -382,11 +382,18 @@ void cli_command_ps(Cli* cli, FuriString* args, void* context) {
FuriThreadId threads_ids[threads_num_max]; FuriThreadId threads_ids[threads_num_max];
uint8_t thread_num = furi_thread_enumerate(threads_ids, threads_num_max); uint8_t thread_num = furi_thread_enumerate(threads_ids, threads_num_max);
printf( printf(
"%-20s %-14s %-8s %-8s %s\r\n", "Name", "Stack start", "Heap", "Stack", "Stack min free"); "%-20s %-20s %-14s %-8s %-8s %s\r\n",
"AppID",
"Name",
"Stack start",
"Heap",
"Stack",
"Stack min free");
for(uint8_t i = 0; i < thread_num; i++) { for(uint8_t i = 0; i < thread_num; i++) {
TaskControlBlock* tcb = (TaskControlBlock*)threads_ids[i]; TaskControlBlock* tcb = (TaskControlBlock*)threads_ids[i];
printf( printf(
"%-20s 0x%-12lx %-8zu %-8lu %-8lu\r\n", "%-20s %-20s 0x%-12lx %-8zu %-8lu %-8lu\r\n",
furi_thread_get_appid(threads_ids[i]),
furi_thread_get_name(threads_ids[i]), furi_thread_get_name(threads_ids[i]),
(uint32_t)tcb->pxStack, (uint32_t)tcb->pxStack,
memmgr_heap_get_thread_memory(threads_ids[i]), memmgr_heap_get_thread_memory(threads_ids[i]),

View File

@@ -2,6 +2,7 @@
#include "dialogs_i.h" #include "dialogs_i.h"
#include <toolbox/api_lock.h> #include <toolbox/api_lock.h>
#include <assets_icons.h> #include <assets_icons.h>
#include <storage/storage.h>
/****************** File browser ******************/ /****************** File browser ******************/
@@ -13,6 +14,22 @@ bool dialog_file_browser_show(
FuriApiLock lock = api_lock_alloc_locked(); FuriApiLock lock = api_lock_alloc_locked();
furi_check(lock != NULL); furi_check(lock != NULL);
Storage* storage = furi_record_open(RECORD_STORAGE);
FuriString* base_path = furi_string_alloc();
if(options && options->base_path) {
furi_string_set(base_path, options->base_path);
storage_common_resolve_path_and_ensure_app_directory(storage, base_path);
}
if(result_path) {
storage_common_resolve_path_and_ensure_app_directory(storage, result_path);
}
if(path) {
storage_common_resolve_path_and_ensure_app_directory(storage, path);
}
DialogsAppData data = { DialogsAppData data = {
.file_browser = { .file_browser = {
.extension = options ? options->extension : "", .extension = options ? options->extension : "",
@@ -24,7 +41,7 @@ bool dialog_file_browser_show(
.preselected_filename = path, .preselected_filename = path,
.item_callback = options ? options->item_loader_callback : NULL, .item_callback = options ? options->item_loader_callback : NULL,
.item_callback_context = options ? options->item_loader_context : NULL, .item_callback_context = options ? options->item_loader_context : NULL,
.base_path = options ? options->base_path : NULL, .base_path = furi_string_get_cstr(base_path),
}}; }};
DialogsAppReturn return_data; DialogsAppReturn return_data;
@@ -39,6 +56,9 @@ bool dialog_file_browser_show(
furi_message_queue_put(context->message_queue, &message, FuriWaitForever) == FuriStatusOk); furi_message_queue_put(context->message_queue, &message, FuriWaitForever) == FuriStatusOk);
api_lock_wait_unlock_and_free(lock); api_lock_wait_unlock_and_free(lock);
furi_record_close(RECORD_STORAGE);
furi_string_free(base_path);
return return_data.bool_value; return return_data.bool_value;
} }

View File

@@ -60,7 +60,7 @@ static bool browser_path_is_file(FuriString* path) {
FileInfo file_info; FileInfo file_info;
Storage* storage = furi_record_open(RECORD_STORAGE); Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) {
if((file_info.flags & FSF_DIRECTORY) == 0) { if(!file_info_is_dir(&file_info)) {
state = true; state = true;
} }
} }
@@ -119,7 +119,7 @@ static bool browser_folder_check_and_switch(FuriString* path) {
while(1) { while(1) {
// Check if folder is existing and navigate back if not // Check if folder is existing and navigate back if not
if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) {
if(file_info.flags & FSF_DIRECTORY) { if(file_info_is_dir(&file_info)) {
break; break;
} }
} }
@@ -161,7 +161,7 @@ static bool browser_folder_init(
if((storage_file_get_error(directory) == FSE_OK) && (name_temp[0] != '\0')) { if((storage_file_get_error(directory) == FSE_OK) && (name_temp[0] != '\0')) {
total_files_cnt++; total_files_cnt++;
furi_string_set(name_str, name_temp); furi_string_set(name_str, name_temp);
if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { if(browser_filter_by_name(browser, name_str, file_info_is_dir(&file_info))) {
if(!furi_string_empty(filename)) { if(!furi_string_empty(filename)) {
if(furi_string_cmp(name_str, filename) == 0) { if(furi_string_cmp(name_str, filename) == 0) {
*file_idx = *item_cnt; *file_idx = *item_cnt;
@@ -218,7 +218,7 @@ static bool browser_folder_load_chunked(
} }
if(storage_file_get_error(directory) == FSE_OK) { if(storage_file_get_error(directory) == FSE_OK) {
furi_string_set(name_str, name_temp); furi_string_set(name_str, name_temp);
if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { if(browser_filter_by_name(browser, name_str, file_info_is_dir(&file_info))) {
items_cnt++; items_cnt++;
} }
} else { } else {
@@ -240,14 +240,14 @@ static bool browser_folder_load_chunked(
} }
if(storage_file_get_error(directory) == FSE_OK) { if(storage_file_get_error(directory) == FSE_OK) {
furi_string_set(name_str, name_temp); furi_string_set(name_str, name_temp);
if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { if(browser_filter_by_name(browser, name_str, file_info_is_dir(&file_info))) {
furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp); furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp);
if(browser->list_item_cb) { if(browser->list_item_cb) {
browser->list_item_cb( browser->list_item_cb(
browser->cb_ctx, browser->cb_ctx,
name_str, name_str,
items_cnt, items_cnt,
(file_info.flags & FSF_DIRECTORY), file_info_is_dir(&file_info),
false); false);
} }
items_cnt++; items_cnt++;
@@ -295,15 +295,11 @@ static bool browser_folder_load_full(BrowserWorker* browser, FuriString* path) {
while(storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX) && while(storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX) &&
storage_file_get_error(directory) == FSE_OK) { storage_file_get_error(directory) == FSE_OK) {
furi_string_set(name_str, name_temp); furi_string_set(name_str, name_temp);
if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { if(browser_filter_by_name(browser, name_str, file_info_is_dir(&file_info))) {
furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp); furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp);
if(browser->list_item_cb) { if(browser->list_item_cb) {
browser->list_item_cb( browser->list_item_cb(
browser->cb_ctx, browser->cb_ctx, name_str, items_cnt, file_info_is_dir(&file_info), false);
name_str,
items_cnt,
(file_info.flags & FSF_DIRECTORY),
false);
} }
items_cnt++; items_cnt++;
} }

View File

@@ -115,6 +115,7 @@ void widget_add_text_box_element(
* @param[in] text Formatted text. Default format: align left, Secondary font. * @param[in] text Formatted text. Default format: align left, Secondary font.
* The following formats are available: * The following formats are available:
* "\e#Bold text" - sets bold font before until next '\n' symbol * "\e#Bold text" - sets bold font before until next '\n' symbol
* "\e*Monospaced text\e*" - sets monospaced font before until next '\n' symbol
* "\ecCenter-aligned text" - sets center horizontal align until the next '\n' symbol * "\ecCenter-aligned text" - sets center horizontal align until the next '\n' symbol
* "\erRight-aligned text" - sets right horizontal align until the next '\n' symbol * "\erRight-aligned text" - sets right horizontal align until the next '\n' symbol
*/ */

View File

@@ -37,6 +37,8 @@ static bool
line->horizontal = AlignRight; line->horizontal = AlignRight;
} else if(ctrl_symbol == '#') { } else if(ctrl_symbol == '#') {
line->font = FontPrimary; line->font = FontPrimary;
} else if(ctrl_symbol == '*') {
line->font = FontKeyboard;
} }
furi_string_right(text, 2); furi_string_right(text, 2);
processed = true; processed = true;

View File

@@ -29,6 +29,8 @@ static bool
} }
furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name);
furi_thread_set_appid(
loader_instance->application_thread, loader_instance->application->appid);
furi_thread_set_stack_size( furi_thread_set_stack_size(
loader_instance->application_thread, loader_instance->application->stack_size); loader_instance->application_thread, loader_instance->application->stack_size);
furi_thread_set_context( furi_thread_set_context(

View File

@@ -201,7 +201,7 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex
if(error == FSE_OK) { if(error == FSE_OK) {
response->which_content = PB_Main_storage_stat_response_tag; response->which_content = PB_Main_storage_stat_response_tag;
response->content.storage_stat_response.has_file = true; response->content.storage_stat_response.has_file = true;
response->content.storage_stat_response.file.type = (fileinfo.flags & FSF_DIRECTORY) ? response->content.storage_stat_response.file.type = file_info_is_dir(&fileinfo) ?
PB_Storage_File_FileType_DIR : PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_FILE; PB_Storage_File_FileType_FILE;
response->content.storage_stat_response.file.size = fileinfo.size; response->content.storage_stat_response.file.size = fileinfo.size;
@@ -291,9 +291,8 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex
rpc_send_and_release(session, &response); rpc_send_and_release(session, &response);
i = 0; i = 0;
} }
list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_DIR : PB_Storage_File_FileType_FILE;
PB_Storage_File_FileType_FILE;
list->file[i].size = fileinfo.size; list->file[i].size = fileinfo.size;
list->file[i].data = NULL; list->file[i].data = NULL;
list->file[i].name = name; list->file[i].name = name;
@@ -458,7 +457,7 @@ static bool rpc_system_storage_is_dir_is_empty(Storage* fs_api, const char* path
FileInfo fileinfo; FileInfo fileinfo;
bool is_dir_is_empty = true; bool is_dir_is_empty = true;
FS_Error error = storage_common_stat(fs_api, path, &fileinfo); FS_Error error = storage_common_stat(fs_api, path, &fileinfo);
if((error == FSE_OK) && (fileinfo.flags & FSF_DIRECTORY)) { if((error == FSE_OK) && file_info_is_dir(&fileinfo)) {
File* dir = storage_file_alloc(fs_api); File* dir = storage_file_alloc(fs_api);
if(storage_dir_open(dir, path)) { if(storage_dir_open(dir, path)) {
char* name = malloc(MAX_NAME_LENGTH); char* name = malloc(MAX_NAME_LENGTH);

View File

@@ -36,3 +36,7 @@ const char* filesystem_api_error_get_desc(FS_Error error_id) {
} }
return result; return result;
} }
bool file_info_is_dir(const FileInfo* file_info) {
return (file_info->flags & FSF_DIRECTORY);
}

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -40,10 +41,10 @@ typedef enum {
FSF_DIRECTORY = (1 << 0), /**< Directory */ FSF_DIRECTORY = (1 << 0), /**< Directory */
} FS_Flags; } FS_Flags;
/** Structure that hold file index and returned api errors */ /** Structure that hold file index and returned api errors */
typedef struct File File; typedef struct File File;
/** Structure that hold file info */ /** Structure that hold file info */
typedef struct { typedef struct {
uint8_t flags; /**< flags from FS_Flags enum */ uint8_t flags; /**< flags from FS_Flags enum */
uint64_t size; /**< file size */ uint64_t size; /**< file size */
@@ -55,6 +56,12 @@ typedef struct {
*/ */
const char* filesystem_api_error_get_desc(FS_Error error_id); const char* filesystem_api_error_get_desc(FS_Error error_id);
/** Checks if file info is directory
* @param file_info file info pointer
* @return bool is directory
*/
bool file_info_is_dir(const FileInfo* file_info);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -10,10 +10,12 @@ extern "C" {
#define STORAGE_INT_PATH_PREFIX "/int" #define STORAGE_INT_PATH_PREFIX "/int"
#define STORAGE_EXT_PATH_PREFIX "/ext" #define STORAGE_EXT_PATH_PREFIX "/ext"
#define STORAGE_ANY_PATH_PREFIX "/any" #define STORAGE_ANY_PATH_PREFIX "/any"
#define STORAGE_APP_DATA_PATH_PREFIX "/app"
#define INT_PATH(path) STORAGE_INT_PATH_PREFIX "/" path #define INT_PATH(path) STORAGE_INT_PATH_PREFIX "/" path
#define EXT_PATH(path) STORAGE_EXT_PATH_PREFIX "/" path #define EXT_PATH(path) STORAGE_EXT_PATH_PREFIX "/" path
#define ANY_PATH(path) STORAGE_ANY_PATH_PREFIX "/" path #define ANY_PATH(path) STORAGE_ANY_PATH_PREFIX "/" path
#define APP_DATA_PATH(path) STORAGE_APP_DATA_PATH_PREFIX "/" path
#define RECORD_STORAGE "storage" #define RECORD_STORAGE "storage"
@@ -175,6 +177,15 @@ bool storage_dir_read(File* file, FileInfo* fileinfo, char* name, uint16_t name_
*/ */
bool storage_dir_rewind(File* file); bool storage_dir_rewind(File* file);
/**
* @brief Check that dir exists
*
* @param storage
* @param path
* @return bool
*/
bool storage_dir_exists(Storage* storage, const char* path);
/******************* Common Functions *******************/ /******************* Common Functions *******************/
/** Retrieves unix timestamp of last access /** Retrieves unix timestamp of last access
@@ -246,6 +257,36 @@ FS_Error storage_common_fs_info(
uint64_t* total_space, uint64_t* total_space,
uint64_t* free_space); uint64_t* free_space);
/**
* @brief Parse aliases in path and replace them with real path
* Also will create special folders if they are not exist
*
* @param storage
* @param path
* @return bool
*/
void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, FuriString* path);
/**
* @brief Move content of one folder to another, with rename of all conflicting files.
* Source folder will be deleted if the migration is successful.
*
* @param storage
* @param source
* @param dest
* @return FS_Error
*/
FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest);
/**
* @brief Check that file or dir exists
*
* @param storage
* @param path
* @return bool
*/
bool storage_common_exists(Storage* storage, const char* path);
/******************* Error Functions *******************/ /******************* Error Functions *******************/
/** Retrieves the error text from the error id /** Retrieves the error text from the error id

Some files were not shown because too many files have changed in this diff Show More