From 777a4d109d723fbe2300d0f66788eed6b24ee208 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 1 Mar 2023 20:57:27 +0300 Subject: [PATCH 01/23] [FL-3055] Getter for application data path (#2181) * Threads: application id * Unit tests: appsdata getter test * Unit tests: moar test cases for appsdata getter * Unit tests: remove folders after test * Storage: dir_is_exist, migrate, + unit_tests * Plugins: migration * Storage: common_exists, moar unit_tests 4 "common_migrate", "common_migrate" and "common_merge" bugfixes * Storage: use FuriString for path handling * Storage API: send caller thread id with path * Storage: remove StorageType field in storage file list * Storage: simplify processing * Storage API: send caller thread id with path everywhere * Storage: /app alias, unit tests and path creation * Storage, path helper: remove unused * Examples: app data example * App plugins: use new VFS path * Storage: file_info_is_dir * Services: handle alias if the service accepts a path. * App plugins: fixes * Make PVS happy * Storage: fix storage_merge_recursive * Storage: rename process_aliases to resolve_path. Rename APPS_DATA to APP_DATA. * Apps: use predefined macro instead of raw paths. Example Apps Data: README fixes. * Storage: rename storage_common_resolve_path to storage_common_resolve_path_and_ensure_app_directory * Api: fix version * Storage: rename alias message * Storage: do not create app folders in path resolving process in certain cases. --------- Co-authored-by: Astra <93453568+Astrrra@users.noreply.github.com> Co-authored-by: Aleksandr Kutuzov --- .pvsconfig | 3 + applications/debug/unit_tests/rpc/rpc_test.c | 9 +- .../debug/unit_tests/storage/dirwalk_test.c | 8 +- .../debug/unit_tests/storage/storage_test.c | 292 ++++++++++++++- .../examples/example_apps_data/README.md | 18 + .../example_apps_data/application.fam | 9 + .../example_apps_data/example_apps_data.c | 40 ++ .../main/archive/helpers/archive_browser.c | 2 +- .../main/archive/helpers/archive_favorites.c | 2 +- .../main/archive/helpers/archive_files.c | 2 +- applications/main/fap_loader/fap_loader_app.c | 7 + applications/plugins/hid_app/hid.c | 12 +- applications/plugins/hid_app/hid.h | 2 +- .../plugins/music_player/music_player.c | 11 +- .../picopass/helpers/iclass_elite_dict.c | 20 +- applications/plugins/picopass/picopass.c | 8 + .../plugins/picopass/picopass_device.c | 14 +- .../plugins/picopass/picopass_device.h | 2 - .../scenes/picopass_scene_save_name.c | 4 +- .../scenes/spi_mem_scene_start.c | 2 +- .../plugins/spi_mem_manager/spi_mem_app.c | 10 +- .../plugins/spi_mem_manager/spi_mem_app_i.h | 1 - .../plugins/spi_mem_manager/spi_mem_files.c | 8 +- .../plugins/spi_mem_manager/spi_mem_files.h | 1 - applications/services/applications.h | 1 + applications/services/bt/bt_service/bt_api.c | 9 +- applications/services/cli/cli_commands.c | 11 +- applications/services/dialogs/dialogs_api.c | 22 +- .../gui/modules/file_browser_worker.c | 12 +- applications/services/loader/loader.c | 2 + applications/services/rpc/rpc_storage.c | 9 +- .../services/storage/filesystem_api.c | 4 + .../services/storage/filesystem_api_defines.h | 11 +- applications/services/storage/storage.h | 41 +++ applications/services/storage/storage_cli.c | 6 +- .../services/storage/storage_external_api.c | 103 ++++-- applications/services/storage/storage_glue.c | 11 +- applications/services/storage/storage_glue.h | 7 +- applications/services/storage/storage_i.h | 2 + .../services/storage/storage_message.h | 13 + .../services/storage/storage_processing.c | 262 ++++++++------ .../services/storage/storage_test_app.c | 341 ------------------ .../storage_move_to_sd/storage_move_to_sd.c | 2 +- .../music_player/Marble_Machine.fmf | 0 .../picopass/assets/iclass_elite_dict.txt | 0 firmware/targets/f7/api_symbols.csv | 9 +- furi/core/thread.c | 40 +- furi/core/thread.h | 37 ++ furi/flipper.c | 1 + lib/toolbox/dir_walk.c | 2 +- lib/toolbox/tar/tar_archive.c | 2 +- scripts/fbt/appmanifest.py | 1 + 52 files changed, 871 insertions(+), 577 deletions(-) create mode 100644 applications/examples/example_apps_data/README.md create mode 100644 applications/examples/example_apps_data/application.fam create mode 100644 applications/examples/example_apps_data/example_apps_data.c delete mode 100644 applications/services/storage/storage_test_app.c rename assets/resources/{ => apps_data}/music_player/Marble_Machine.fmf (100%) rename assets/resources/{ => apps_data}/picopass/assets/iclass_elite_dict.txt (100%) diff --git a/.pvsconfig b/.pvsconfig index a9ab9c9f..49c63ad7 100644 --- a/.pvsconfig +++ b/.pvsconfig @@ -44,3 +44,6 @@ # Functions that always return the same error code //-V:picopass_device_decrypt:1048 + +# Examples +//V_EXCLUDE_PATH applications/examples/ \ No newline at end of file diff --git a/applications/debug/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c index 76acf6be..329f3b74 100644 --- a/applications/debug/unit_tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/rpc/rpc_test.c @@ -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; char* fullname = malloc(size); snprintf(fullname, size, "%s/%s", clean_dir, name); - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { clean_directory(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)) { - list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? - PB_Storage_File_FileType_DIR : - PB_Storage_File_FileType_FILE; + list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; list->file[i].size = fileinfo.size; list->file[i].data = NULL; /* 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) { response->which_content = PB_Main_storage_stat_response_tag; 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_FILE; response->content.storage_stat_response.file.size = fileinfo.size; diff --git a/applications/debug/unit_tests/storage/dirwalk_test.c b/applications/debug/unit_tests/storage/dirwalk_test.c index 97aaa358..e0842a7a 100644 --- a/applications/debug/unit_tests/storage/dirwalk_test.c +++ b/applications/debug/unit_tests/storage/dirwalk_test.c @@ -179,7 +179,7 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) { while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { 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); @@ -204,7 +204,7 @@ MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) { while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { 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); @@ -219,7 +219,7 @@ static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* filein UNUSED(ctx); // only files - if(!(fileinfo->flags & FSF_DIRECTORY)) { + if(!file_info_is_dir(fileinfo)) { // with ".test" in name if(strstr(name, ".test") != NULL) { return true; @@ -243,7 +243,7 @@ MU_TEST_1(test_dirwalk_filter, Storage* storage) { while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) { 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); diff --git a/applications/debug/unit_tests/storage/storage_test.c b/applications/debug/unit_tests/storage/storage_test.c index 11500970..582be790 100644 --- a/applications/debug/unit_tests/storage/storage_test.c +++ b/applications/debug/unit_tests/storage/storage_test.c @@ -2,9 +2,40 @@ #include #include +// DO NOT USE THIS IN PRODUCTION CODE +// This is a hack to access internal storage functions and definitions +#include + +#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path) + #define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test") #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() { Storage* storage = furi_record_open(RECORD_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); furi_check(storage_dir_open(file, STORAGE_LOCKED_DIR)); furi_semaphore_release(semaphore); - furi_delay_ms(1000); + furi_delay_ms(100); furi_check(storage_dir_close(file)); furi_record_close(RECORD_STORAGE); @@ -152,9 +183,21 @@ MU_TEST(storage_dir_open_lock) { 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_RUN_TEST(storage_dir_open_close); MU_RUN_TEST(storage_dir_open_lock); + MU_RUN_TEST(storage_dir_exists_test); } static const char* const storage_copy_test_paths[] = { @@ -303,9 +346,256 @@ MU_TEST_SUITE(storage_rename) { 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() { MU_RUN_SUITE(storage_file); MU_RUN_SUITE(storage_dir); MU_RUN_SUITE(storage_rename); + MU_RUN_SUITE(test_data_path); + MU_RUN_SUITE(test_storage_common); return MU_EXIT_CODE; } diff --git a/applications/examples/example_apps_data/README.md b/applications/examples/example_apps_data/README.md new file mode 100644 index 00000000..fd866607 --- /dev/null +++ b/applications/examples/example_apps_data/README.md @@ -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")`. \ No newline at end of file diff --git a/applications/examples/example_apps_data/application.fam b/applications/examples/example_apps_data/application.fam new file mode 100644 index 00000000..f44dca97 --- /dev/null +++ b/applications/examples/example_apps_data/application.fam @@ -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", +) diff --git a/applications/examples/example_apps_data/example_apps_data.c b/applications/examples/example_apps_data/example_apps_data.c new file mode 100644 index 00000000..d6104c13 --- /dev/null +++ b/applications/examples/example_apps_data/example_apps_data.c @@ -0,0 +1,40 @@ +#include +#include + +// 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/ + // 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; +} diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 1133f6d7..f5efca46 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -436,7 +436,7 @@ static bool archive_is_dir_exists(FuriString* path) { FileInfo file_info; Storage* storage = furi_record_open(RECORD_STORAGE); 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; } } diff --git a/applications/main/archive/helpers/archive_favorites.c b/applications/main/archive/helpers/archive_favorites.c index 8bbcb521..f395ee5a 100644 --- a/applications/main/archive/helpers/archive_favorites.c +++ b/applications/main/archive/helpers/archive_favorites.c @@ -160,7 +160,7 @@ bool archive_favorites_read(void* context) { if(storage_file_exists(storage, furi_string_get_cstr(buffer))) { storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info); 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++; } else { need_refresh = true; diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index 87265a45..a8bd937c 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -91,7 +91,7 @@ void archive_delete_file(void* context, const char* format, ...) { 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)); } else { res = (storage_common_remove(fs_api, furi_string_get_cstr(filename)) == FSE_OK); diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index 7911aa06..e81a3ce4 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "elf_cpp/elf_hashtable.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"); 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_join(thread); diff --git a/applications/plugins/hid_app/hid.c b/applications/plugins/hid_app/hid.c index 7f63f0cc..949ff63b 100644 --- a/applications/plugins/hid_app/hid.c +++ b/applications/plugins/hid_app/hid.c @@ -376,7 +376,17 @@ int32_t hid_ble_app(void* p) { // Wait 2nd core to update nvm storage 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)) { FURI_LOG_E(TAG, "Failed to switch to HID profile"); diff --git a/applications/plugins/hid_app/hid.h b/applications/plugins/hid_app/hid.h index fe32a199..8ed1664a 100644 --- a/applications/plugins/hid_app/hid.h +++ b/applications/plugins/hid_app/hid.h @@ -23,7 +23,7 @@ #include "views/hid_mouse_jiggler.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 { HidTransportUsb, diff --git a/applications/plugins/music_player/music_player.c b/applications/plugins/music_player/music_player.c index 28127a57..2380d7d1 100644 --- a/applications/plugins/music_player/music_player.c +++ b/applications/plugins/music_player/music_player.c @@ -10,7 +10,6 @@ #define TAG "MusicPlayer" -#define MUSIC_PLAYER_APP_PATH_FOLDER ANY_PATH("music_player") #define MUSIC_PLAYER_APP_EXTENSION "*" #define MUSIC_PLAYER_SEMITONE_HISTORY_SIZE 4 @@ -307,18 +306,24 @@ int32_t music_player_app(void* p) { if(p && strlen(p)) { furi_string_set(file_path, (const char*)p); } else { - furi_string_set(file_path, MUSIC_PLAYER_APP_PATH_FOLDER); + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_common_migrate( + storage, EXT_PATH("music_player"), STORAGE_APP_DATA_PATH_PREFIX); + furi_record_close(RECORD_STORAGE); + + furi_string_set(file_path, STORAGE_APP_DATA_PATH_PREFIX); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options( &browser_options, MUSIC_PLAYER_APP_EXTENSION, &I_music_10px); browser_options.hide_ext = false; - browser_options.base_path = MUSIC_PLAYER_APP_PATH_FOLDER; + browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX; DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options); furi_record_close(RECORD_DIALOGS); + if(!res) { FURI_LOG_E(TAG, "No file selected"); break; diff --git a/applications/plugins/picopass/helpers/iclass_elite_dict.c b/applications/plugins/picopass/helpers/iclass_elite_dict.c index 455eb23c..e8c13dd1 100644 --- a/applications/plugins/picopass/helpers/iclass_elite_dict.c +++ b/applications/plugins/picopass/helpers/iclass_elite_dict.c @@ -3,8 +3,8 @@ #include #include -#define ICLASS_ELITE_DICT_FLIPPER_PATH EXT_PATH("picopass/assets/iclass_elite_dict.txt") -#define ICLASS_ELITE_DICT_USER_PATH EXT_PATH("picopass/assets/iclass_elite_dict_user.txt") +#define ICLASS_ELITE_DICT_FLIPPER_NAME APP_DATA_PATH("assets/iclass_elite_dict.txt") +#define ICLASS_ELITE_DICT_USER_NAME APP_DATA_PATH("assets/iclass_elite_dict_user.txt") #define TAG "IclassEliteDict" @@ -21,10 +21,10 @@ bool iclass_elite_dict_check_presence(IclassEliteDictType dict_type) { bool dict_present = false; if(dict_type == IclassEliteDictTypeFlipper) { - dict_present = storage_common_stat(storage, ICLASS_ELITE_DICT_FLIPPER_PATH, NULL) == - FSE_OK; + dict_present = + (storage_common_stat(storage, ICLASS_ELITE_DICT_FLIPPER_NAME, NULL) == FSE_OK); } 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); @@ -36,27 +36,26 @@ IclassEliteDict* iclass_elite_dict_alloc(IclassEliteDictType dict_type) { IclassEliteDict* dict = malloc(sizeof(IclassEliteDict)); Storage* storage = furi_record_open(RECORD_STORAGE); dict->stream = buffered_file_stream_alloc(storage); - furi_record_close(RECORD_STORAGE); FuriString* next_line = furi_string_alloc(); bool dict_loaded = false; do { if(dict_type == IclassEliteDictTypeFlipper) { 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); break; } } else if(dict_type == IclassEliteDictTypeUser) { 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); break; } } // Read total amount of keys - while(true) { + while(true) { //-V547 if(!stream_read_line(dict->stream, next_line)) break; if(furi_string_get_char(next_line, 0) == '#') 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); } while(false); - if(!dict_loaded) { + if(!dict_loaded) { //-V547 buffered_file_stream_close(dict->stream); free(dict); dict = NULL; } + furi_record_close(RECORD_STORAGE); furi_string_free(next_line); return dict; diff --git a/applications/plugins/picopass/picopass.c b/applications/plugins/picopass/picopass.c index 96ea82c3..5d1cee70 100644 --- a/applications/plugins/picopass/picopass.c +++ b/applications/plugins/picopass/picopass.c @@ -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 result = 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) { UNUSED(p); + picopass_migrate_from_old_folder(); + Picopass* picopass = picopass_alloc(); scene_manager_next_scene(picopass->scene_manager, PicopassSceneStart); diff --git a/applications/plugins/picopass/picopass_device.c b/applications/plugins/picopass/picopass_device.c index e3940698..ec0bc5af 100644 --- a/applications/plugins/picopass/picopass_device.c +++ b/applications/plugins/picopass/picopass_device.c @@ -48,13 +48,9 @@ static bool picopass_device_save_file( if(use_load_path && !furi_string_empty(dev->load_path)) { // Get directory name 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 furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension); } 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 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) { if(dev->format == PicopassDeviceSaveFormatHF) { 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) { return picopass_device_save_file(dev, dev_name, ANY_PATH("lfrfid"), ".rfid", true); } + return false; } @@ -225,13 +222,12 @@ void picopass_device_free(PicopassDevice* picopass_dev) { bool picopass_file_select(PicopassDevice* dev) { furi_assert(dev); - // Input events and views are managed by file_browser 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; 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( 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); } else { 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; deleted = true; diff --git a/applications/plugins/picopass/picopass_device.h b/applications/plugins/picopass/picopass_device.h index 99f1ceea..d7d0977d 100644 --- a/applications/plugins/picopass/picopass_device.h +++ b/applications/plugins/picopass/picopass_device.h @@ -24,7 +24,6 @@ #define PICOPASS_AIA_BLOCK_INDEX 5 #define PICOPASS_PACS_CFG_BLOCK_INDEX 6 -#define PICOPASS_APP_FOLDER ANY_PATH("picopass") #define PICOPASS_APP_EXTENSION ".picopass" #define PICOPASS_APP_SHADOW_EXTENSION ".pas" @@ -81,7 +80,6 @@ typedef struct { PicopassDeviceSaveFormat format; PicopassLoadingCallback loading_cb; void* loading_cb_ctx; - } PicopassDevice; PicopassDevice* picopass_device_alloc(); diff --git a/applications/plugins/picopass/scenes/picopass_scene_save_name.c b/applications/plugins/picopass/scenes/picopass_scene_save_name.c index 59f33c79..baf882b8 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_save_name.c +++ b/applications/plugins/picopass/scenes/picopass_scene_save_name.c @@ -31,12 +31,10 @@ void picopass_scene_save_name_on_enter(void* context) { dev_name_empty); 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)) { 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( diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c index b664df68..38d064a4 100644 --- a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c @@ -60,7 +60,7 @@ bool spi_mem_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect); success = true; } 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); success = true; } else if(event.event == SPIMemSceneStartSubmenuIndexErase) { diff --git a/applications/plugins/spi_mem_manager/spi_mem_app.c b/applications/plugins/spi_mem_manager/spi_mem_app.c index 63531b74..96c3632d 100644 --- a/applications/plugins/spi_mem_manager/spi_mem_app.c +++ b/applications/plugins/spi_mem_manager/spi_mem_app.c @@ -16,9 +16,9 @@ static bool spi_mem_back_event_callback(void* context) { } 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->notifications = furi_record_open(RECORD_NOTIFICATION); instance->view_dispatcher = view_dispatcher_alloc(); @@ -37,7 +37,8 @@ SPIMemApp* spi_mem_alloc(void) { instance->text_input = text_input_alloc(); 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_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); scene_manager_next_scene(instance->scene_manager, SPIMemSceneStart); return instance; -} +} //-V773 void spi_mem_free(SPIMemApp* instance) { 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) { UNUSED(p); SPIMemApp* instance = spi_mem_alloc(); - spi_mem_file_create_folder(instance); view_dispatcher_run(instance->view_dispatcher); spi_mem_free(instance); return 0; diff --git a/applications/plugins/spi_mem_manager/spi_mem_app_i.h b/applications/plugins/spi_mem_manager/spi_mem_app_i.h index 4ce05617..285ca66d 100644 --- a/applications/plugins/spi_mem_manager/spi_mem_app_i.h +++ b/applications/plugins/spi_mem_manager/spi_mem_app_i.h @@ -24,7 +24,6 @@ #define TAG "SPIMem" #define SPI_MEM_FILE_EXTENSION ".bin" -#define SPI_MEM_FILE_FOLDER EXT_PATH("spimem") #define SPI_MEM_FILE_NAME_SIZE 100 #define SPI_MEM_TEXT_BUFFER_SIZE 128 diff --git a/applications/plugins/spi_mem_manager/spi_mem_files.c b/applications/plugins/spi_mem_manager/spi_mem_files.c index a7374da1..9b787bd7 100644 --- a/applications/plugins/spi_mem_manager/spi_mem_files.c +++ b/applications/plugins/spi_mem_manager/spi_mem_files.c @@ -1,11 +1,5 @@ #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) { 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) { DialogsFileBrowserOptions browser_options; 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 = dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); return success; diff --git a/applications/plugins/spi_mem_manager/spi_mem_files.h b/applications/plugins/spi_mem_manager/spi_mem_files.h index 0e735d95..6a529d32 100644 --- a/applications/plugins/spi_mem_manager/spi_mem_files.h +++ b/applications/plugins/spi_mem_manager/spi_mem_files.h @@ -1,7 +1,6 @@ #pragma once #include "spi_mem_app.h" -void spi_mem_file_create_folder(SPIMemApp* app); bool spi_mem_file_select(SPIMemApp* app); bool spi_mem_file_create(SPIMemApp* app, const char* file_name); bool spi_mem_file_delete(SPIMemApp* app); diff --git a/applications/services/applications.h b/applications/services/applications.h index acbfea31..871e9af5 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -11,6 +11,7 @@ typedef enum { typedef struct { const FuriThreadCallback app; const char* name; + const char* appid; const size_t stack_size; const Icon* icon; const FlipperApplicationFlag flags; diff --git a/applications/services/bt/bt_service/bt_api.c b/applications/services/bt/bt_service/bt_api.c index e3cf78cc..2f56b50a 100644 --- a/applications/services/bt/bt_service/bt_api.c +++ b/applications/services/bt/bt_service/bt_api.c @@ -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(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) { diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index ca9d8b98..0f042f6c 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -372,11 +372,18 @@ void cli_command_ps(Cli* cli, FuriString* args, void* context) { FuriThreadId threads_ids[threads_num_max]; uint8_t thread_num = furi_thread_enumerate(threads_ids, threads_num_max); 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++) { TaskControlBlock* tcb = (TaskControlBlock*)threads_ids[i]; 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]), (uint32_t)tcb->pxStack, memmgr_heap_get_thread_memory(threads_ids[i]), diff --git a/applications/services/dialogs/dialogs_api.c b/applications/services/dialogs/dialogs_api.c index ca2435b9..4723a1f9 100644 --- a/applications/services/dialogs/dialogs_api.c +++ b/applications/services/dialogs/dialogs_api.c @@ -2,6 +2,7 @@ #include "dialogs_i.h" #include #include +#include /****************** File browser ******************/ @@ -13,6 +14,22 @@ bool dialog_file_browser_show( FuriApiLock lock = api_lock_alloc_locked(); 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 = { .file_browser = { .extension = options ? options->extension : "", @@ -24,7 +41,7 @@ bool dialog_file_browser_show( .preselected_filename = path, .item_callback = options ? options->item_loader_callback : 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; @@ -39,6 +56,9 @@ bool dialog_file_browser_show( furi_message_queue_put(context->message_queue, &message, FuriWaitForever) == FuriStatusOk); api_lock_wait_unlock_and_free(lock); + furi_record_close(RECORD_STORAGE); + furi_string_free(base_path); + return return_data.bool_value; } diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 80c4f4c4..857acbba 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -60,7 +60,7 @@ static bool browser_path_is_file(FuriString* path) { FileInfo file_info; Storage* storage = furi_record_open(RECORD_STORAGE); 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; } } @@ -119,7 +119,7 @@ static bool browser_folder_check_and_switch(FuriString* path) { while(1) { // 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(file_info.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&file_info)) { break; } } @@ -161,7 +161,7 @@ static bool browser_folder_init( if((storage_file_get_error(directory) == FSE_OK) && (name_temp[0] != '\0')) { total_files_cnt++; 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_cmp(name_str, filename) == 0) { *file_idx = *item_cnt; @@ -214,7 +214,7 @@ static bool } if(storage_file_get_error(directory) == FSE_OK) { 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++; } } else { @@ -236,11 +236,11 @@ static bool } if(storage_file_get_error(directory) == FSE_OK) { 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); if(browser->list_item_cb) { browser->list_item_cb( - browser->cb_ctx, name_str, (file_info.flags & FSF_DIRECTORY), false); + browser->cb_ctx, name_str, file_info_is_dir(&file_info), false); } items_cnt++; } diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index caaf9f11..5f2d8a2e 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -29,6 +29,8 @@ static bool } 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( loader_instance->application_thread, loader_instance->application->stack_size); furi_thread_set_context( diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index c4493cc7..c3a4a047 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -201,7 +201,7 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex if(error == FSE_OK) { response->which_content = PB_Main_storage_stat_response_tag; 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_FILE; 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); i = 0; } - list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? - PB_Storage_File_FileType_DIR : - PB_Storage_File_FileType_FILE; + list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; list->file[i].size = fileinfo.size; list->file[i].data = NULL; 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; bool is_dir_is_empty = true; 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); if(storage_dir_open(dir, path)) { char* name = malloc(MAX_NAME_LENGTH); diff --git a/applications/services/storage/filesystem_api.c b/applications/services/storage/filesystem_api.c index b979967a..30b20ede 100644 --- a/applications/services/storage/filesystem_api.c +++ b/applications/services/storage/filesystem_api.c @@ -36,3 +36,7 @@ const char* filesystem_api_error_get_desc(FS_Error error_id) { } return result; } + +bool file_info_is_dir(const FileInfo* file_info) { + return (file_info->flags & FSF_DIRECTORY); +} \ No newline at end of file diff --git a/applications/services/storage/filesystem_api_defines.h b/applications/services/storage/filesystem_api_defines.h index b73e6eb3..cd24b882 100644 --- a/applications/services/storage/filesystem_api_defines.h +++ b/applications/services/storage/filesystem_api_defines.h @@ -1,5 +1,6 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -40,10 +41,10 @@ typedef enum { FSF_DIRECTORY = (1 << 0), /**< Directory */ } FS_Flags; -/** Structure that hold file index and returned api errors */ +/** Structure that hold file index and returned api errors */ typedef struct File File; -/** Structure that hold file info */ +/** Structure that hold file info */ typedef struct { uint8_t flags; /**< flags from FS_Flags enum */ uint64_t size; /**< file size */ @@ -55,6 +56,12 @@ typedef struct { */ 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 } #endif diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index e093cbe0..e35b8164 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -10,10 +10,12 @@ extern "C" { #define STORAGE_INT_PATH_PREFIX "/int" #define STORAGE_EXT_PATH_PREFIX "/ext" #define STORAGE_ANY_PATH_PREFIX "/any" +#define STORAGE_APP_DATA_PATH_PREFIX "/app" #define INT_PATH(path) STORAGE_INT_PATH_PREFIX "/" path #define EXT_PATH(path) STORAGE_EXT_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" @@ -175,6 +177,15 @@ bool storage_dir_read(File* file, FileInfo* fileinfo, char* name, uint16_t name_ */ 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 *******************/ /** Retrieves unix timestamp of last access @@ -246,6 +257,36 @@ FS_Error storage_common_fs_info( uint64_t* total_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 *******************/ /** Retrieves the error text from the error id diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index ff205569..8e2dcdbb 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -131,7 +131,7 @@ static void storage_cli_list(Cli* cli, FuriString* path) { while(storage_dir_read(file, &fileinfo, name, MAX_NAME_LENGTH)) { read_done = true; - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { printf("\t[D] %s\r\n", name); } else { printf("\t[F] %s %lub\r\n", name, (uint32_t)(fileinfo.size)); @@ -169,7 +169,7 @@ static void storage_cli_tree(Cli* cli, FuriString* path) { while(dir_walk_read(dir_walk, name, &fileinfo) == DirWalkOK) { read_done = true; - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { printf("\t[D] %s\r\n", furi_string_get_cstr(name)); } else { printf( @@ -383,7 +383,7 @@ static void storage_cli_stat(Cli* cli, FuriString* path) { FS_Error error = storage_common_stat(api, furi_string_get_cstr(path), &fileinfo); if(error == FSE_OK) { - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { printf("Directory\r\n"); } else { printf("File, size: %lub\r\n", (uint32_t)(fileinfo.size)); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index c5dfd533..8d8220f8 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -39,12 +39,6 @@ .file = file, \ }}; -#define S_API_DATA_PATH \ - SAData data = { \ - .path = { \ - .path = path, \ - }}; - #define S_RETURN_BOOL (return_data.bool_value); #define S_RETURN_UINT16 (return_data.uint16_value); #define S_RETURN_UINT64 (return_data.uint64_value); @@ -70,6 +64,7 @@ static bool storage_file_open_internal( .path = path, .access_mode = access_mode, .open_mode = open_mode, + .thread_id = furi_thread_get_current_id(), }}; file->type = FileTypeOpenFile; @@ -249,7 +244,7 @@ bool storage_file_exists(Storage* storage, const char* path) { FileInfo fileinfo; FS_Error error = storage_common_stat(storage, path, &fileinfo); - if(error == FSE_OK && !(fileinfo.flags & FSF_DIRECTORY)) { + if(error == FSE_OK && !file_info_is_dir(&fileinfo)) { exist = true; } @@ -266,6 +261,7 @@ static bool storage_dir_open_internal(File* file, const char* path) { .dopen = { .file = file, .path = path, + .thread_id = furi_thread_get_current_id(), }}; file->type = FileTypeOpenDir; @@ -349,12 +345,28 @@ bool storage_dir_rewind(File* file) { return S_RETURN_BOOL; } +bool storage_dir_exists(Storage* storage, const char* path) { + bool exist = false; + FileInfo fileinfo; + FS_Error error = storage_common_stat(storage, path, &fileinfo); + + if(error == FSE_OK && file_info_is_dir(&fileinfo)) { + exist = true; + } + + return exist; +} /****************** COMMON ******************/ FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp) { S_API_PROLOGUE; - SAData data = {.ctimestamp = {.path = path, .timestamp = timestamp}}; + SAData data = { + .ctimestamp = { + .path = path, + .timestamp = timestamp, + .thread_id = furi_thread_get_current_id(), + }}; S_API_MESSAGE(StorageCommandCommonTimestamp); S_API_EPILOGUE; @@ -363,8 +375,12 @@ FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo) { S_API_PROLOGUE; - - SAData data = {.cstat = {.path = path, .fileinfo = fileinfo}}; + SAData data = { + .cstat = { + .path = path, + .fileinfo = fileinfo, + .thread_id = furi_thread_get_current_id(), + }}; S_API_MESSAGE(StorageCommandCommonStat); S_API_EPILOGUE; @@ -373,7 +389,12 @@ FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* filei FS_Error storage_common_remove(Storage* storage, const char* path) { S_API_PROLOGUE; - S_API_DATA_PATH; + SAData data = { + .path = { + .path = path, + .thread_id = furi_thread_get_current_id(), + }}; + S_API_MESSAGE(StorageCommandCommonRemove); S_API_EPILOGUE; return S_RETURN_ERROR; @@ -423,7 +444,7 @@ static FS_Error furi_string_right(path, strlen(old_path)); furi_string_printf(tmp_new_path, "%s%s", new_path, furi_string_get_cstr(path)); - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { error = storage_common_mkdir(storage, furi_string_get_cstr(tmp_new_path)); } else { error = storage_common_copy( @@ -452,7 +473,7 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* error = storage_common_stat(storage, old_path, &fileinfo); if(error == FSE_OK) { - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { error = storage_copy_recursive(storage, old_path, new_path); } else { Stream* stream_from = file_stream_alloc(storage); @@ -479,7 +500,7 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* static FS_Error storage_merge_recursive(Storage* storage, const char* old_path, const char* new_path) { - FS_Error error = storage_common_mkdir(storage, new_path); + FS_Error error = FSE_OK; DirWalk* dir_walk = dir_walk_alloc(storage); FuriString *path, *file_basename, *tmp_new_path; FileInfo fileinfo; @@ -488,7 +509,7 @@ static FS_Error tmp_new_path = furi_string_alloc(); do { - if((error != FSE_OK) && (error != FSE_EXIST)) break; + if(!storage_simply_mkdir(storage, new_path)) break; dir_walk_set_recursive(dir_walk, false); if(!dir_walk_open(dir_walk, old_path)) { @@ -508,13 +529,13 @@ static FS_Error path_extract_basename(furi_string_get_cstr(path), file_basename); path_concat(new_path, furi_string_get_cstr(file_basename), tmp_new_path); - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { if(storage_common_stat( storage, furi_string_get_cstr(tmp_new_path), &fileinfo) == FSE_OK) { - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { error = storage_common_mkdir(storage, furi_string_get_cstr(tmp_new_path)); - if(error != FSE_OK) { + if(error != FSE_OK && error != FSE_EXIST) { break; } } @@ -548,7 +569,7 @@ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char error = storage_common_stat(storage, old_path, &fileinfo); if(error == FSE_OK) { - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { error = storage_merge_recursive(storage, old_path, new_path); } else { error = storage_common_stat(storage, new_path, &fileinfo); @@ -556,7 +577,7 @@ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char furi_string_set(new_path_next, new_path); FuriString* dir_path; FuriString* filename; - char extension[MAX_EXT_LEN]; + char extension[MAX_EXT_LEN] = {0}; dir_path = furi_string_alloc(); filename = furi_string_alloc(); @@ -608,7 +629,12 @@ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char FS_Error storage_common_mkdir(Storage* storage, const char* path) { S_API_PROLOGUE; - S_API_DATA_PATH; + SAData data = { + .path = { + .path = path, + .thread_id = furi_thread_get_current_id(), + }}; + S_API_MESSAGE(StorageCommandCommonMkDir); S_API_EPILOGUE; return S_RETURN_ERROR; @@ -626,6 +652,7 @@ FS_Error storage_common_fs_info( .fs_path = fs_path, .total_space = total_space, .free_space = free_space, + .thread_id = furi_thread_get_current_id(), }}; S_API_MESSAGE(StorageCommandCommonFSInfo); @@ -633,6 +660,38 @@ FS_Error storage_common_fs_info( return S_RETURN_ERROR; } +void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, FuriString* path) { + S_API_PROLOGUE; + + SAData data = { + .cresolvepath = { + .path = path, + .thread_id = furi_thread_get_current_id(), + }}; + + S_API_MESSAGE(StorageCommandCommonResolvePath); + S_API_EPILOGUE; +} + +FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest) { + if(!storage_common_exists(storage, source)) { + return FSE_OK; + } + + FS_Error error = storage_common_merge(storage, source, dest); + + if(error == FSE_OK) { + storage_simply_remove_recursive(storage, source); + } + + return error; +} + +bool storage_common_exists(Storage* storage, const char* path) { + FileInfo file_info; + return storage_common_stat(storage, path, &file_info) == FSE_OK; +} + /****************** ERROR ******************/ const char* storage_error_get_desc(FS_Error error_id) { @@ -750,7 +809,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) { } while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { - if(fileinfo.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&fileinfo)) { furi_string_cat_printf(cur_dir, "/%s", name); go_deeper = true; break; diff --git a/applications/services/storage/storage_glue.c b/applications/services/storage/storage_glue.c index cccf4046..5dabfa38 100644 --- a/applications/services/storage/storage_glue.c +++ b/applications/services/storage/storage_glue.c @@ -5,21 +5,18 @@ void storage_file_init(StorageFile* obj) { obj->file = NULL; - obj->type = ST_ERROR; obj->file_data = NULL; obj->path = furi_string_alloc(); } void storage_file_init_set(StorageFile* obj, const StorageFile* src) { obj->file = src->file; - obj->type = src->type; obj->file_data = src->file_data; obj->path = furi_string_alloc_set(src->path); } void storage_file_set(StorageFile* obj, const StorageFile* src) { //-V524 obj->file = src->file; - obj->type = src->type; obj->file_data = src->file_data; furi_string_set(obj->path, src->path); } @@ -150,16 +147,10 @@ void* storage_get_storage_file_data(const File* file, StorageData* storage) { return founded_file->file_data; } -void storage_push_storage_file( - File* file, - FuriString* path, - StorageType type, - StorageData* storage) { +void storage_push_storage_file(File* file, FuriString* path, StorageData* storage) { StorageFile* storage_file = StorageFileList_push_new(storage->files); - file->file_id = (uint32_t)storage_file; storage_file->file = file; - storage_file->type = type; furi_string_set(storage_file->path, path); } diff --git a/applications/services/storage/storage_glue.h b/applications/services/storage/storage_glue.h index 501c26ab..bf0a1c69 100644 --- a/applications/services/storage/storage_glue.h +++ b/applications/services/storage/storage_glue.h @@ -18,7 +18,6 @@ typedef struct { typedef struct { File* file; - StorageType type; void* file_data; FuriString* path; } StorageFile; @@ -66,11 +65,7 @@ bool storage_path_already_open(FuriString* path, StorageFileList_t files); void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage); void* storage_get_storage_file_data(const File* file, StorageData* storage); -void storage_push_storage_file( - File* file, - FuriString* path, - StorageType type, - StorageData* storage); +void storage_push_storage_file(File* file, FuriString* path, StorageData* storage); bool storage_pop_storage_file(File* file, StorageData* storage); #ifdef __cplusplus diff --git a/applications/services/storage/storage_i.h b/applications/services/storage/storage_i.h index 406fc921..85df5d92 100644 --- a/applications/services/storage/storage_i.h +++ b/applications/services/storage/storage_i.h @@ -12,6 +12,8 @@ extern "C" { #define STORAGE_COUNT (ST_INT + 1) +#define APPS_DATA_PATH EXT_PATH("apps_data") + typedef struct { ViewPort* view_port; bool enabled; diff --git a/applications/services/storage/storage_message.h b/applications/services/storage/storage_message.h index 3edb1018..9e13bf83 100644 --- a/applications/services/storage/storage_message.h +++ b/applications/services/storage/storage_message.h @@ -11,6 +11,7 @@ typedef struct { const char* path; FS_AccessMode access_mode; FS_OpenMode open_mode; + FuriThreadId thread_id; } SADataFOpen; typedef struct { @@ -34,6 +35,7 @@ typedef struct { typedef struct { File* file; const char* path; + FuriThreadId thread_id; } SADataDOpen; typedef struct { @@ -46,25 +48,34 @@ typedef struct { typedef struct { const char* path; uint32_t* timestamp; + FuriThreadId thread_id; } SADataCTimestamp; typedef struct { const char* path; FileInfo* fileinfo; + FuriThreadId thread_id; } SADataCStat; typedef struct { const char* fs_path; uint64_t* total_space; uint64_t* free_space; + FuriThreadId thread_id; } SADataCFSInfo; +typedef struct { + FuriString* path; + FuriThreadId thread_id; +} SADataCResolvePath; + typedef struct { uint32_t id; } SADataError; typedef struct { const char* path; + FuriThreadId thread_id; } SADataPath; typedef struct { @@ -87,6 +98,7 @@ typedef union { SADataCTimestamp ctimestamp; SADataCStat cstat; SADataCFSInfo cfsinfo; + SADataCResolvePath cresolvepath; SADataError error; @@ -128,6 +140,7 @@ typedef enum { StorageCommandSDUnmount, StorageCommandSDInfo, StorageCommandSDStatus, + StorageCommandCommonResolvePath, } StorageCommand; typedef struct { diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index b1ea5d29..cab1edff 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -4,17 +4,11 @@ #define FS_CALL(_storage, _fn) ret = _storage->fs_api->_fn; -static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) { - furi_check(type == ST_EXT || type == ST_INT); - StorageData* storage = &app->storage[type]; - return storage; -} - -static bool storage_type_is_not_valid(StorageType type) { +static bool storage_type_is_valid(StorageType type) { #ifdef FURI_RAM_EXEC - return type != ST_EXT; + return type == ST_EXT; #else - return type >= ST_ERROR; + return type < ST_ERROR; #endif } @@ -30,25 +24,21 @@ static StorageData* get_storage_by_file(File* file, StorageData* storages) { return storage_data; } -static const char* remove_vfs(const char* path) { - return path + MIN(4u, strlen(path)); +static const char* cstr_path_without_vfs_prefix(FuriString* path) { + const char* path_cstr = furi_string_get_cstr(path); + return path_cstr + MIN(4u, strlen(path_cstr)); } -static StorageType storage_get_type_by_path(Storage* app, const char* path) { +static StorageType storage_get_type_by_path(FuriString* path) { StorageType type = ST_ERROR; - if(memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) { - type = ST_EXT; - } else if(memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) { - type = ST_INT; - } else if(memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) { - type = ST_ANY; - } + const char* path_cstr = furi_string_get_cstr(path); - if(type == ST_ANY) { + if(memcmp(path_cstr, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) { + type = ST_EXT; + } else if(memcmp(path_cstr, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) { type = ST_INT; - if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) { - type = ST_EXT; - } + } else if(memcmp(path_cstr, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) { + type = ST_ANY; } return type; @@ -71,38 +61,51 @@ static void storage_path_change_to_real_storage(FuriString* path, StorageType re } } +FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) { + StorageType type = storage_get_type_by_path(path); + + if(storage_type_is_valid(type)) { + if(type == ST_ANY) { + type = ST_INT; + if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) { + type = ST_EXT; + } + storage_path_change_to_real_storage(path, type); + } + + furi_assert(type == ST_EXT || type == ST_INT); + *storage = &app->storage[type]; + + return FSE_OK; + } else { + return FSE_INVALID_NAME; + } +} + /******************* File Functions *******************/ bool storage_process_file_open( Storage* app, File* file, - const char* path, + FuriString* path, FS_AccessMode access_mode, FS_OpenMode open_mode) { bool ret = false; - StorageType type = storage_get_type_by_path(app, path); StorageData* storage; - file->error_id = FSE_OK; + file->error_id = storage_get_data(app, path, &storage); - if(storage_type_is_not_valid(type)) { - file->error_id = FSE_INVALID_NAME; - } else { - storage = storage_get_storage_by_type(app, type); - FuriString* real_path; - real_path = furi_string_alloc_set(path); - storage_path_change_to_real_storage(real_path, type); - - if(storage_path_already_open(real_path, storage->files)) { + if(file->error_id == FSE_OK) { + if(storage_path_already_open(path, storage->files)) { file->error_id = FSE_ALREADY_OPEN; } else { if(access_mode & FSAM_WRITE) { storage_data_timestamp(storage); } - storage_push_storage_file(file, real_path, type, storage); - FS_CALL(storage, file.open(storage, file, remove_vfs(path), access_mode, open_mode)); - } + storage_push_storage_file(file, path, storage); - furi_string_free(real_path); + const char* path_cstr_no_vfs = cstr_path_without_vfs_prefix(path); + FS_CALL(storage, file.open(storage, file, path_cstr_no_vfs, access_mode, open_mode)); + } } return ret; @@ -243,27 +246,18 @@ static bool storage_process_file_eof(Storage* app, File* file) { /******************* Dir Functions *******************/ -bool storage_process_dir_open(Storage* app, File* file, const char* path) { +bool storage_process_dir_open(Storage* app, File* file, FuriString* path) { bool ret = false; - StorageType type = storage_get_type_by_path(app, path); StorageData* storage; - file->error_id = FSE_OK; + file->error_id = storage_get_data(app, path, &storage); - if(storage_type_is_not_valid(type)) { - file->error_id = FSE_INVALID_NAME; - } else { - storage = storage_get_storage_by_type(app, type); - FuriString* real_path; - real_path = furi_string_alloc_set(path); - storage_path_change_to_real_storage(real_path, type); - - if(storage_path_already_open(real_path, storage->files)) { + if(file->error_id == FSE_OK) { + if(storage_path_already_open(path, storage->files)) { file->error_id = FSE_ALREADY_OPEN; } else { - storage_push_storage_file(file, real_path, type, storage); - FS_CALL(storage, dir.open(storage, file, remove_vfs(path))); + storage_push_storage_file(file, path, storage); + FS_CALL(storage, dir.open(storage, file, cstr_path_without_vfs_prefix(path))); } - furi_string_free(real_path); } return ret; @@ -320,73 +314,52 @@ bool storage_process_dir_rewind(Storage* app, File* file) { /******************* Common FS Functions *******************/ static FS_Error - storage_process_common_timestamp(Storage* app, const char* path, uint32_t* timestamp) { - FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(app, path); + storage_process_common_timestamp(Storage* app, FuriString* path, uint32_t* timestamp) { + StorageData* storage; + FS_Error ret = storage_get_data(app, path, &storage); - if(storage_type_is_not_valid(type)) { - ret = FSE_INVALID_NAME; - } else { - StorageData* storage = storage_get_storage_by_type(app, type); + if(ret == FSE_OK) { *timestamp = storage_data_get_timestamp(storage); } return ret; } -static FS_Error storage_process_common_stat(Storage* app, const char* path, FileInfo* fileinfo) { - FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(app, path); +static FS_Error storage_process_common_stat(Storage* app, FuriString* path, FileInfo* fileinfo) { + StorageData* storage; + FS_Error ret = storage_get_data(app, path, &storage); - if(storage_type_is_not_valid(type)) { - ret = FSE_INVALID_NAME; - } else { - StorageData* storage = storage_get_storage_by_type(app, type); - FS_CALL(storage, common.stat(storage, remove_vfs(path), fileinfo)); + if(ret == FSE_OK) { + FS_CALL(storage, common.stat(storage, cstr_path_without_vfs_prefix(path), fileinfo)); } return ret; } -static FS_Error storage_process_common_remove(Storage* app, const char* path) { - FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(app, path); - - FuriString* real_path; - real_path = furi_string_alloc_set(path); - storage_path_change_to_real_storage(real_path, type); +static FS_Error storage_process_common_remove(Storage* app, FuriString* path) { + StorageData* storage; + FS_Error ret = storage_get_data(app, path, &storage); do { - if(storage_type_is_not_valid(type)) { - ret = FSE_INVALID_NAME; - break; - } - - StorageData* storage = storage_get_storage_by_type(app, type); - if(storage_path_already_open(real_path, storage->files)) { + if(storage_path_already_open(path, storage->files)) { ret = FSE_ALREADY_OPEN; break; } storage_data_timestamp(storage); - FS_CALL(storage, common.remove(storage, remove_vfs(path))); + FS_CALL(storage, common.remove(storage, cstr_path_without_vfs_prefix(path))); } while(false); - furi_string_free(real_path); - return ret; } -static FS_Error storage_process_common_mkdir(Storage* app, const char* path) { - FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(app, path); +static FS_Error storage_process_common_mkdir(Storage* app, FuriString* path) { + StorageData* storage; + FS_Error ret = storage_get_data(app, path, &storage); - if(storage_type_is_not_valid(type)) { - ret = FSE_INVALID_NAME; - } else { - StorageData* storage = storage_get_storage_by_type(app, type); + if(ret == FSE_OK) { storage_data_timestamp(storage); - FS_CALL(storage, common.mkdir(storage, remove_vfs(path))); + FS_CALL(storage, common.mkdir(storage, cstr_path_without_vfs_prefix(path))); } return ret; @@ -394,17 +367,16 @@ static FS_Error storage_process_common_mkdir(Storage* app, const char* path) { static FS_Error storage_process_common_fs_info( Storage* app, - const char* fs_path, + FuriString* path, uint64_t* total_space, uint64_t* free_space) { - FS_Error ret = FSE_OK; - StorageType type = storage_get_type_by_path(app, fs_path); + StorageData* storage; + FS_Error ret = storage_get_data(app, path, &storage); - if(storage_type_is_not_valid(type)) { - ret = FSE_INVALID_NAME; - } else { - StorageData* storage = storage_get_storage_by_type(app, type); - FS_CALL(storage, common.fs_info(storage, remove_vfs(fs_path), total_space, free_space)); + if(ret == FSE_OK) { + FS_CALL( + storage, + common.fs_info(storage, cstr_path_without_vfs_prefix(path), total_space, free_space)); } return ret; @@ -471,14 +443,52 @@ static FS_Error storage_process_sd_status(Storage* app) { return ret; } +/******************** Aliases processing *******************/ + +void storage_process_alias( + Storage* app, + FuriString* path, + FuriThreadId thread_id, + bool create_folders) { + if(furi_string_start_with(path, STORAGE_APP_DATA_PATH_PREFIX)) { + FuriString* apps_data_path_with_appsid = furi_string_alloc_set(APPS_DATA_PATH "/"); + furi_string_cat(apps_data_path_with_appsid, furi_thread_get_appid(thread_id)); + + // "/app" -> "/ext/apps_data/appsid" + furi_string_replace_at( + path, + 0, + strlen(STORAGE_APP_DATA_PATH_PREFIX), + furi_string_get_cstr(apps_data_path_with_appsid)); + + // Create app data folder if not exists + if(create_folders && + storage_process_common_stat(app, apps_data_path_with_appsid, NULL) != FSE_OK) { + furi_string_set(apps_data_path_with_appsid, APPS_DATA_PATH); + storage_process_common_mkdir(app, apps_data_path_with_appsid); + furi_string_cat(apps_data_path_with_appsid, "/"); + furi_string_cat(apps_data_path_with_appsid, furi_thread_get_appid(thread_id)); + storage_process_common_mkdir(app, apps_data_path_with_appsid); + } + + furi_string_free(apps_data_path_with_appsid); + } +} + /****************** API calls processing ******************/ + void storage_process_message_internal(Storage* app, StorageMessage* message) { + FuriString* path = NULL; + switch(message->command) { + // File operations case StorageCommandFileOpen: + path = furi_string_alloc_set(message->data->fopen.path); + storage_process_alias(app, path, message->data->fopen.thread_id, true); message->return_data->bool_value = storage_process_file_open( app, message->data->fopen.file, - message->data->fopen.path, + path, message->data->fopen.access_mode, message->data->fopen.open_mode); break; @@ -527,9 +537,12 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) { message->return_data->bool_value = storage_process_file_eof(app, message->data->file.file); break; + // Dir operations case StorageCommandDirOpen: + path = furi_string_alloc_set(message->data->dopen.path); + storage_process_alias(app, path, message->data->dopen.thread_id, true); message->return_data->bool_value = - storage_process_dir_open(app, message->data->dopen.file, message->data->dopen.path); + storage_process_dir_open(app, message->data->dopen.file, path); break; case StorageCommandDirClose: message->return_data->bool_value = @@ -547,29 +560,42 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) { message->return_data->bool_value = storage_process_dir_rewind(app, message->data->file.file); break; + + // Common operations case StorageCommandCommonTimestamp: - message->return_data->error_value = storage_process_common_timestamp( - app, message->data->ctimestamp.path, message->data->ctimestamp.timestamp); + path = furi_string_alloc_set(message->data->ctimestamp.path); + storage_process_alias(app, path, message->data->ctimestamp.thread_id, false); + message->return_data->error_value = + storage_process_common_timestamp(app, path, message->data->ctimestamp.timestamp); break; case StorageCommandCommonStat: - message->return_data->error_value = storage_process_common_stat( - app, message->data->cstat.path, message->data->cstat.fileinfo); + path = furi_string_alloc_set(message->data->cstat.path); + storage_process_alias(app, path, message->data->cstat.thread_id, false); + message->return_data->error_value = + storage_process_common_stat(app, path, message->data->cstat.fileinfo); break; case StorageCommandCommonRemove: - message->return_data->error_value = - storage_process_common_remove(app, message->data->path.path); + path = furi_string_alloc_set(message->data->path.path); + storage_process_alias(app, path, message->data->path.thread_id, false); + message->return_data->error_value = storage_process_common_remove(app, path); break; case StorageCommandCommonMkDir: - message->return_data->error_value = - storage_process_common_mkdir(app, message->data->path.path); + path = furi_string_alloc_set(message->data->path.path); + storage_process_alias(app, path, message->data->path.thread_id, true); + message->return_data->error_value = storage_process_common_mkdir(app, path); break; case StorageCommandCommonFSInfo: + path = furi_string_alloc_set(message->data->cfsinfo.fs_path); + storage_process_alias(app, path, message->data->cfsinfo.thread_id, false); message->return_data->error_value = storage_process_common_fs_info( - app, - message->data->cfsinfo.fs_path, - message->data->cfsinfo.total_space, - message->data->cfsinfo.free_space); + app, path, message->data->cfsinfo.total_space, message->data->cfsinfo.free_space); break; + case StorageCommandCommonResolvePath: + storage_process_alias( + app, message->data->cresolvepath.path, message->data->cresolvepath.thread_id, true); + break; + + // SD operations case StorageCommandSDFormat: message->return_data->error_value = storage_process_sd_format(app); break; @@ -585,6 +611,10 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) { break; } + if(path != NULL) { //-V547 + furi_string_free(path); + } + api_lock_unlock(message->lock); } diff --git a/applications/services/storage/storage_test_app.c b/applications/services/storage/storage_test_app.c deleted file mode 100644 index 852953e9..00000000 --- a/applications/services/storage/storage_test_app.c +++ /dev/null @@ -1,341 +0,0 @@ -#include -#include -#include - -#define TAG "StorageTest" -#define BYTES_COUNT 16 -#define TEST_STRING "TestDataStringProvidedByDiceRoll" -#define SEEK_OFFSET_FROM_START 10 -#define SEEK_OFFSET_INCREASE 12 -#define SEEK_OFFSET_SUM (SEEK_OFFSET_FROM_START + SEEK_OFFSET_INCREASE) - -static void do_file_test(Storage* api, const char* path) { - File* file = storage_file_alloc(api); - bool result; - uint8_t bytes[BYTES_COUNT + 1]; - uint8_t bytes_count; - uint64_t position; - uint64_t size; - - FURI_LOG_I(TAG, "--------- FILE \"%s\" ---------", path); - - // open - result = storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS); - if(result) { - FURI_LOG_I(TAG, "open"); - } else { - FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(file)); - } - - // write - bytes_count = storage_file_write(file, TEST_STRING, strlen(TEST_STRING)); - if(bytes_count == 0) { - FURI_LOG_E(TAG, "write, %s", storage_file_get_error_desc(file)); - } else { - FURI_LOG_I(TAG, "write"); - } - - // sync - result = storage_file_sync(file); - if(result) { - FURI_LOG_I(TAG, "sync"); - } else { - FURI_LOG_E(TAG, "sync, %s", storage_file_get_error_desc(file)); - } - - // eof #1 - result = storage_file_eof(file); - if(result) { - FURI_LOG_I(TAG, "eof #1"); - } else { - FURI_LOG_E(TAG, "eof #1, %s", storage_file_get_error_desc(file)); - } - - // seek from start and tell - result = storage_file_seek(file, SEEK_OFFSET_FROM_START, true); - if(result) { - FURI_LOG_I(TAG, "seek #1"); - } else { - FURI_LOG_E(TAG, "seek #1, %s", storage_file_get_error_desc(file)); - } - position = storage_file_tell(file); - if(position != SEEK_OFFSET_FROM_START) { - FURI_LOG_E(TAG, "tell #1, %s", storage_file_get_error_desc(file)); - } else { - FURI_LOG_I(TAG, "tell #1"); - } - - // size - size = storage_file_size(file); - if(size != strlen(TEST_STRING)) { - FURI_LOG_E(TAG, "size #1, %s", storage_file_get_error_desc(file)); - } else { - FURI_LOG_I(TAG, "size #1"); - } - - // seek and tell - result = storage_file_seek(file, SEEK_OFFSET_INCREASE, false); - if(result) { - FURI_LOG_I(TAG, "seek #2"); - } else { - FURI_LOG_E(TAG, "seek #2, %s", storage_file_get_error_desc(file)); - } - position = storage_file_tell(file); - if(position != SEEK_OFFSET_SUM) { - FURI_LOG_E(TAG, "tell #2, %s", storage_file_get_error_desc(file)); - } else { - FURI_LOG_I(TAG, "tell #2"); - } - - // eof #2 - result = storage_file_eof(file); - if(!result) { - FURI_LOG_I(TAG, "eof #2"); - } else { - FURI_LOG_E(TAG, "eof #2, %s", storage_file_get_error_desc(file)); - } - - // truncate - result = storage_file_truncate(file); - if(result) { - FURI_LOG_I(TAG, "truncate"); - } else { - FURI_LOG_E(TAG, "truncate, %s", storage_file_get_error_desc(file)); - } - size = storage_file_size(file); - if(size != SEEK_OFFSET_SUM) { - FURI_LOG_E(TAG, "size #2, %s", storage_file_get_error_desc(file)); - } else { - FURI_LOG_I(TAG, "size #2"); - } - - // close - result = storage_file_close(file); - if(result) { - FURI_LOG_I(TAG, "close"); - } else { - FURI_LOG_E(TAG, "close, error"); - } - - // open - result = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); - if(result) { - FURI_LOG_I(TAG, "open"); - } else { - FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(file)); - } - - // read - memset(bytes, 0, BYTES_COUNT + 1); - bytes_count = storage_file_read(file, bytes, BYTES_COUNT); - if(bytes_count == 0) { - FURI_LOG_E(TAG, "read, %s", storage_file_get_error_desc(file)); - } else { - if(memcmp(TEST_STRING, bytes, bytes_count) == 0) { - FURI_LOG_I(TAG, "read"); - } else { - FURI_LOG_E(TAG, "read, garbage"); - } - } - - // close - result = storage_file_close(file); - if(result) { - FURI_LOG_I(TAG, "close"); - } else { - FURI_LOG_E(TAG, "close, error"); - } - - storage_file_free(file); -} - -static void do_dir_test(Storage* api, const char* path) { - File* file = storage_file_alloc(api); - bool result; - - FURI_LOG_I(TAG, "--------- DIR \"%s\" ---------", path); - - // open - result = storage_dir_open(file, path); - if(result) { - FURI_LOG_I(TAG, "open"); - } else { - FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(file)); - } - - // read - const uint8_t filename_size = 100; - char* filename = malloc(filename_size); - FileInfo fileinfo; - - do { - result = storage_dir_read(file, &fileinfo, filename, filename_size); - if(result) { - if(strlen(filename)) { - FURI_LOG_I( - TAG, - "read #1, [%s]%s", - ((fileinfo.flags & FSF_DIRECTORY) ? "D" : "F"), - filename); - } - } else if(storage_file_get_error(file) != FSE_NOT_EXIST) { - FURI_LOG_E(TAG, "read #1, %s", storage_file_get_error_desc(file)); - break; - } - - } while(result); - - // rewind - result = storage_dir_rewind(file); - if(result) { - FURI_LOG_I(TAG, "rewind"); - } else { - FURI_LOG_E(TAG, "rewind, %s", storage_file_get_error_desc(file)); - } - - // read - do { - result = storage_dir_read(file, &fileinfo, filename, filename_size); - if(result) { - if(strlen(filename)) { - FURI_LOG_I( - TAG, - "read #2, [%s]%s", - ((fileinfo.flags & FSF_DIRECTORY) ? "D" : "F"), - filename); - } - } else if(storage_file_get_error(file) != FSE_NOT_EXIST) { - FURI_LOG_E(TAG, "read #2, %s", storage_file_get_error_desc(file)); - break; - } - - } while((strlen(filename))); - - // close - result = storage_dir_close(file); - if(result) { - FURI_LOG_I(TAG, "close"); - } else { - FURI_LOG_E(TAG, "close, error"); - } - - storage_file_free(file); - free(filename); -} - -static void do_test_start(Storage* api, const char* path) { - FuriString* str_path = furi_string_alloc_printf("%s/test-folder", path); - - FURI_LOG_I(TAG, "--------- START \"%s\" ---------", path); - - // mkdir - FS_Error result = storage_common_mkdir(api, furi_string_get_cstr(str_path)); - - if(result == FSE_OK) { - FURI_LOG_I(TAG, "mkdir ok"); - } else { - FURI_LOG_E(TAG, "mkdir, %s", storage_error_get_desc(result)); - } - - // stat - FileInfo fileinfo; - result = storage_common_stat(api, furi_string_get_cstr(str_path), &fileinfo); - - if(result == FSE_OK) { - if(fileinfo.flags & FSF_DIRECTORY) { - FURI_LOG_I(TAG, "stat #1 ok"); - } else { - FURI_LOG_E(TAG, "stat #1, %s", storage_error_get_desc(result)); - } - } else { - FURI_LOG_E(TAG, "stat #1, %s", storage_error_get_desc(result)); - } - - furi_string_free(str_path); -} - -static void do_test_end(Storage* api, const char* path) { - uint64_t total_space; - uint64_t free_space; - FuriString* str_path_1 = furi_string_alloc_printf("%s/test-folder", path); - FuriString* str_path_2 = furi_string_alloc_printf("%s/test-folder2", path); - - FURI_LOG_I(TAG, "--------- END \"%s\" ---------", path); - - // fs stat - FS_Error result = storage_common_fs_info(api, path, &total_space, &free_space); - - if(result == FSE_OK) { - uint32_t total_kb = total_space / 1024; - uint32_t free_kb = free_space / 1024; - FURI_LOG_I(TAG, "fs_info: total %luk, free %luk", total_kb, free_kb); - } else { - FURI_LOG_E(TAG, "fs_info, %s", storage_error_get_desc(result)); - } - - // rename #1 - result = storage_common_rename( - api, furi_string_get_cstr(str_path_1), furi_string_get_cstr(str_path_2)); - if(result == FSE_OK) { - FURI_LOG_I(TAG, "rename #1 ok"); - } else { - FURI_LOG_E(TAG, "rename #1, %s", storage_error_get_desc(result)); - } - - // remove #1 - result = storage_common_remove(api, furi_string_get_cstr(str_path_2)); - if(result == FSE_OK) { - FURI_LOG_I(TAG, "remove #1 ok"); - } else { - FURI_LOG_E(TAG, "remove #1, %s", storage_error_get_desc(result)); - } - - // rename #2 - furi_string_printf(str_path_1, "%s/test.txt", path); - furi_string_printf(str_path_2, "%s/test2.txt", path); - - result = storage_common_rename( - api, furi_string_get_cstr(str_path_1), furi_string_get_cstr(str_path_2)); - if(result == FSE_OK) { - FURI_LOG_I(TAG, "rename #2 ok"); - } else { - FURI_LOG_E(TAG, "rename #2, %s", storage_error_get_desc(result)); - } - - // remove #2 - result = storage_common_remove(api, furi_string_get_cstr(str_path_2)); - if(result == FSE_OK) { - FURI_LOG_I(TAG, "remove #2 ok"); - } else { - FURI_LOG_E(TAG, "remove #2, %s", storage_error_get_desc(result)); - } - - furi_string_free(str_path_1); - furi_string_free(str_path_2); -} - -int32_t storage_test_app(void* p) { - UNUSED(p); - Storage* api = furi_record_open(RECORD_STORAGE); - do_test_start(api, STORAGE_INT_PATH_PREFIX); - do_test_start(api, STORAGE_ANY_PATH_PREFIX); - do_test_start(api, STORAGE_EXT_PATH_PREFIX); - - do_file_test(api, INT_PATH("test.txt")); - do_file_test(api, ANY_PATH("test.txt")); - do_file_test(api, EXT_PATH("test.txt")); - - do_dir_test(api, STORAGE_INT_PATH_PREFIX); - do_dir_test(api, STORAGE_ANY_PATH_PREFIX); - do_dir_test(api, STORAGE_EXT_PATH_PREFIX); - - do_test_end(api, STORAGE_INT_PATH_PREFIX); - do_test_end(api, STORAGE_ANY_PATH_PREFIX); - do_test_end(api, STORAGE_EXT_PATH_PREFIX); - - while(true) { - furi_delay_ms(1000); - } - - return 0; -} diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c index 2027bd23..9c91b926 100644 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.c +++ b/applications/system/storage_move_to_sd/storage_move_to_sd.c @@ -13,7 +13,7 @@ static bool storage_move_to_sd_check_entry(const char* name, FileInfo* fileinfo, void* ctx) { UNUSED(ctx); - if((fileinfo->flags & FSF_DIRECTORY) != 0) { + if(file_info_is_dir(fileinfo)) { return true; } diff --git a/assets/resources/music_player/Marble_Machine.fmf b/assets/resources/apps_data/music_player/Marble_Machine.fmf similarity index 100% rename from assets/resources/music_player/Marble_Machine.fmf rename to assets/resources/apps_data/music_player/Marble_Machine.fmf diff --git a/assets/resources/picopass/assets/iclass_elite_dict.txt b/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt similarity index 100% rename from assets/resources/picopass/assets/iclass_elite_dict.txt rename to assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 8152095d..33bca491 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,15.0,, +Version,+,15.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -847,6 +847,7 @@ Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, Browser Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" Function,+,file_browser_worker_set_long_load_callback,void,"BrowserWorker*, BrowserWorkerLongLoadCallback" +Function,+,file_info_is_dir,_Bool,const FileInfo* Function,+,file_stream_alloc,Stream*,Storage* Function,+,file_stream_close,_Bool,Stream* Function,+,file_stream_get_error,FS_Error,Stream* @@ -1521,6 +1522,7 @@ Function,+,furi_thread_flags_get,uint32_t, Function,+,furi_thread_flags_set,uint32_t,"FuriThreadId, uint32_t" Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" Function,+,furi_thread_free,void,FuriThread* +Function,+,furi_thread_get_appid,const char*,FuriThreadId Function,+,furi_thread_get_current,FuriThread*, Function,+,furi_thread_get_current_id,FuriThreadId, Function,+,furi_thread_get_current_priority,FuriThreadPriority, @@ -1535,6 +1537,7 @@ Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* Function,+,furi_thread_mark_as_service,void,FuriThread* Function,+,furi_thread_resume,void,FuriThreadId +Function,+,furi_thread_set_appid,void,"FuriThread*, const char*" Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" Function,+,furi_thread_set_context,void,"FuriThread*, void*" Function,+,furi_thread_set_current_priority,void,FuriThreadPriority @@ -2430,14 +2433,18 @@ Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*" Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*" Function,+,storage_common_remove,FS_Error,"Storage*, const char*" Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_resolve_path_and_ensure_app_directory,void,"Storage*, FuriString*" Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" Function,+,storage_common_timestamp,FS_Error,"Storage*, const char*, uint32_t*" Function,+,storage_dir_close,_Bool,File* +Function,+,storage_dir_exists,_Bool,"Storage*, const char*" Function,+,storage_dir_open,_Bool,"File*, const char*" Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" Function,-,storage_dir_rewind,_Bool,File* diff --git a/furi/core/thread.c b/furi/core/thread.c index ea9f45e8..b45651c2 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -35,6 +35,8 @@ struct FuriThread { void* state_context; char* name; + char* appid; + configSTACK_DEPTH_TYPE stack_size; FuriThreadPriority priority; @@ -122,11 +124,25 @@ FuriThread* furi_thread_alloc() { thread->output.buffer = furi_string_alloc(); thread->is_service = false; + FuriThread* parent = NULL; + if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + // TLS is not available, if we called not from thread context + parent = pvTaskGetThreadLocalStoragePointer(NULL, 0); + + if(parent && parent->appid) { + furi_thread_set_appid(thread, parent->appid); + } else { + furi_thread_set_appid(thread, "unknown"); + } + } else { + // if scheduler is not started, we are starting driver thread + furi_thread_set_appid(thread, "driver"); + } + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); if(mode == FuriHalRtcHeapTrackModeAll) { thread->heap_trace_enabled = true; } else if(mode == FuriHalRtcHeapTrackModeTree && furi_thread_get_current_id()) { - FuriThread* parent = pvTaskGetThreadLocalStoragePointer(NULL, 0); if(parent) thread->heap_trace_enabled = parent->heap_trace_enabled; } else { thread->heap_trace_enabled = false; @@ -153,6 +169,7 @@ void furi_thread_free(FuriThread* thread) { furi_assert(thread->state == FuriThreadStateStopped); if(thread->name) free((void*)thread->name); + if(thread->appid) free((void*)thread->appid); furi_string_free(thread->output.buffer); free(thread); @@ -165,6 +182,13 @@ void furi_thread_set_name(FuriThread* thread, const char* name) { thread->name = name ? strdup(name) : NULL; } +void furi_thread_set_appid(FuriThread* thread, const char* appid) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + if(thread->appid) free((void*)thread->appid); + thread->appid = appid ? strdup(appid) : NULL; +} + void furi_thread_mark_as_service(FuriThread* thread) { thread->is_service = true; } @@ -498,6 +522,20 @@ const char* furi_thread_get_name(FuriThreadId thread_id) { return (name); } +const char* furi_thread_get_appid(FuriThreadId thread_id) { + TaskHandle_t hTask = (TaskHandle_t)thread_id; + const char* appid = "system"; + + if(!FURI_IS_IRQ_MODE() && (hTask != NULL)) { + FuriThread* thread = (FuriThread*)pvTaskGetThreadLocalStoragePointer(hTask, 0); + if(thread) { + appid = thread->appid; + } + } + + return (appid); +} + uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) { TaskHandle_t hTask = (TaskHandle_t)thread_id; uint32_t sz; diff --git a/furi/core/thread.h b/furi/core/thread.h index 2675f7ce..8f439841 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -87,6 +87,16 @@ void furi_thread_free(FuriThread* thread); */ void furi_thread_set_name(FuriThread* thread, const char* name); +/** + * @brief Set FuriThread appid + * Technically, it is like a "process id", but it is not a system-wide unique identifier. + * All threads spawned by the same app will have the same appid. + * + * @param thread + * @param appid + */ +void furi_thread_set_appid(FuriThread* thread, const char* appid); + /** Mark thread as service * The service cannot be stopped or removed, and cannot exit from the thread body * @@ -233,10 +243,37 @@ uint32_t furi_thread_flags_get(void); uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout); +/** + * @brief Enumerate threads + * + * @param thread_array array of FuriThreadId, where thread ids will be stored + * @param array_items array size + * @return uint32_t threads count + */ uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items); +/** + * @brief Get thread name + * + * @param thread_id + * @return const char* name or NULL + */ const char* furi_thread_get_name(FuriThreadId thread_id); +/** + * @brief Get thread appid + * + * @param thread_id + * @return const char* appid + */ +const char* furi_thread_get_appid(FuriThreadId thread_id); + +/** + * @brief Get thread stack watermark + * + * @param thread_id + * @return uint32_t + */ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); /** Get STDOUT callback for thead diff --git a/furi/flipper.c b/furi/flipper.c index d16a84a1..f0147c06 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -41,6 +41,7 @@ void flipper_init() { FLIPPER_SERVICES[i].app, NULL); furi_thread_mark_as_service(thread); + furi_thread_set_appid(thread, FLIPPER_SERVICES[i].appid); furi_thread_start(thread); } diff --git a/lib/toolbox/dir_walk.c b/lib/toolbox/dir_walk.c index e5a3cf32..509ceb5b 100644 --- a/lib/toolbox/dir_walk.c +++ b/lib/toolbox/dir_walk.c @@ -83,7 +83,7 @@ static DirWalkResult end = true; } - if((info.flags & FSF_DIRECTORY) && dir_walk->recursive) { + if(file_info_is_dir(&info) && dir_walk->recursive) { // step into DirIndexList_push_back(dir_walk->index_list, dir_walk->current_index); dir_walk->current_index = 0; diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index 01969b47..fcfc22a7 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -344,7 +344,7 @@ bool tar_archive_add_dir(TarArchive* archive, const char* fs_full_path, const ch furi_string_set(element_name, name); } - if(file_info.flags & FSF_DIRECTORY) { + if(file_info_is_dir(&file_info)) { success = tar_archive_dir_add_element(archive, furi_string_get_cstr(element_name)) && tar_archive_add_dir( diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index aa03d265..64b9f6f3 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -321,6 +321,7 @@ class ApplicationsCGenerator: return f""" {{.app = {app.entry_point}, .name = "{app.name}", + .appid = "{app.appid}", .stack_size = {app.stack_size}, .icon = {f"&{app.icon}" if app.icon else "NULL"}, .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" From 4359e2eaa9fd42ff66200b6dbc82d67034c40a90 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 2 Mar 2023 13:56:23 +0200 Subject: [PATCH 02/23] [FL-3103] New pin reset splashscreen (#2405) * New pin reset splashscreen * Recovery: optimize drawing routine * Recovery: increase erase confirmation time * Change the required button Co-authored-by: Aleksandr Kutuzov --- assets/icons/ErasePin/Erase_pin_128x64.png | Bin 0 -> 5220 bytes firmware/targets/f7/src/recovery.c | 34 +++++++++++++-------- 2 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 assets/icons/ErasePin/Erase_pin_128x64.png diff --git a/assets/icons/ErasePin/Erase_pin_128x64.png b/assets/icons/ErasePin/Erase_pin_128x64.png new file mode 100644 index 0000000000000000000000000000000000000000..92ca5f91cbb528563ced1b4f585c40ca3e8c27c6 GIT binary patch literal 5220 zcmbVP2T)U6w?1^FO1+{8ktT?w5=t~m6_Ac}1PMumKpIJ;2^c}7ND&bgQK>&g5EKvr zDJop4A}ZZNN06>GrM+PL-<`Sl&7GH-le5p>-}?6Y)>?bbInh=YMuL31`2YYAG%+@? zVcnUmONW=8_3v6Xq0G8*dg_|%0>Fa={&fr&0PrCR`ubLM8zViCiJ`s*Oj|=k4Gx9@ zfN|sPYyP&jJ(7_xYy5*UUO-<<1to!@%tbJ0FQ@gc)7-mSfO-LQVpN`vfrtp3;pKED zTULf~VU)){(3reD+_CQC!GVEuV`D3gH3R*gbM%$IvuO{(fP$qg7{Yap z9h94N~9@p>(OV$w1< ze9Q86p=~VyG@WV~Ct9FP8@|d}w1{WN%pl})o-4#i9g9wZ9JgwqdBnSn{wFO&vd_A0 z8Ykn@FnsGoUo#Q55*2Xv;$?Y{2BQWpsgo8tQIt!L2$LIa5(_TAM0jM15D=qK&aYJ% zAd(t&qd{1RA+kUNsM!?|t#N)yY6<7Cer0y{=`WSO3+z>3(*&|N=|%ck8azph{d~sJ zq~xa2(n+vNbH16I25`x9^PrS3X);sJ<)*WX^X{8cDWTSRTUD!?inB9vHGHe@5K-ML zku$~XHlG0ZwixfyDPfnkPykiV4)Wg;P95I|C>VzL)GhoO=rtS|{RgiNDK-v)K*Uu@ zUrVe=ubVoDS{DpiK+7-q)m@LAZHdP7C2=x*-#e<9sOTL*qm!G5I|R25H*9Im7k_cw z-4s1GuYK6sAkV9%qFT%PaUijXnffe?9=Mesy#<}NbiU=2sJxU0AX|8i->0*Wemug= z+{q>yX!UMsU~N2Hm}@xoj~vtkt(7#cjkO|b^lD;z+?w=9(OqVqJHAR?@)`Eo(ZK{1 z*d&@bB+}U!=l4N5?4L+#v1{IEUp?=>Q>dF=GK!~}DGb*I_X_aoi1czThaI=#_@pcE z#kOCEM@taQY#l^Z?3iWpxO2vae{|=rX8W>}6SEI)aDH^3oiRV0*#_dq30LYKu>y$; z8S4A)6c*L1?2ydkJrHpq!#PjnnF20#DryL30RjaTiWu*L>$*A=}2T9ur{)u$&=|+>s0pU zUfN-POf^HWL&FQQcz_{|5_4sOjWpBWc3ki9?--fT+$C`F;;W~Qn8UE48=P$@GuSwg zBSDuzFs16-JRUd(7P55TCtCwD9#v)kfq{ z`!Kh!SVds9xEntue5Jm0p>I_*7+uSMj^k*2+J0j(2Cv@*cRh9tA|tFrufia}IKWUr zv@5#10g$_15$&jZ*rHlbTCrBX`SPL(INSKj<+3Ek1;!ml!eWe>l26j!W)U1);Qq?Q z;KcPC>-J%C7=-Fq z`#}GJ5^;VBOXUv^Vabch?8)6Kd+k4+xM^o^y=-M+_n|o0I?y>HXE^Ulx=jwv9)CPJ z)4RCEPVEFb_ggI3)IW3oE7b|~q7+gQX^G5mzUN%mUtJX+6cuzQsNkEtU>LW)ynU8g zmJ9aS3A;BA2!~RqFSU|xmog-ZA6gbT_*l3Y9Wpzc>KD139e*qSx<$N2X}i8_Nl`fY zCi(U(2^}k=53!zOelQPl9MC)JR(E{sA{)`2@C2#l4!tj4(;1{fA-sQ$(Z7?* z9m*4V(bTB?GOvCj;z5q@g$446+lZx-q>_o!l9I3)-pt{~c#2=jrgskIIlKV=m}H^h zuQ}lLfv`zSc?xeY32&WswmKNBR_?@b2`(!u8FeXlv~VIg8@kxJ2qN+X&K-k|#31|o z`+~BT2vhzV*EHBu#Wd=AclRsxYxG%wdz{*x-0FhcEZ)Zx9DFoAEFUG5AH^LVP9J~5 z$fE}g=M6Ra5vjMRuj$9BsPV;TeGMsd@5T>*^cX4mFjlQP{AtK}qJK_lL~_`Ea=F*_ zJ-WT7FXVasGwkigK+Ce+M<2;AF%UfDnnPAk8()FMl*3{`QgwK>YE9be#M*pFRWN2i zqV{aCY*D9kvrFF)&wBOx@+$gs&w}Nbts{Wgpsba|yn2T^RP(-Ol&H8wr}&~$uXcsP zs%{iH3YvY$7OoC2gE7Eu$U=1@E_vbZQbAFq>IHiJA^H0v86turr3LTp=UmY;1QDm5 z+GWQ)&AV?F_(*gs-9w8hO8ps&l8TELx&pJAw;C3O^E!{G`st zU>jA&%o_Uty!PDUdEcKi(Wx>1QILeR@hYlnB}DA7n78P-=!R&50$3qJ@uAYlm8>Mo z1zbRM^&Ro#tA$t3+lF_BbtbB(memjt!IV&a)YV$0niDz_8)i#8&P2FGWJxVc*-23l z`UuO@CY}o=-%6HB{c)C~6(56ZgdWB}EIQ<%=1-rU2+Cc0xF=l@wx>$do7gs>Rojex z^XkQg7tyKbnh?#ZFV5B|5=|XyX`4Cg5AMmhr1C59t#Z}BB|hpR8j(Jd=LRsf*sXZW zi0NlOhDwHGhO#kEfA-YEH|`D>MBILGXwCGXsnG1R>EW5({WJI1yz&_Yi^*P@0rU)h zvE*4v&)KYHH?>ptZlwwLEh{M5&vG;Ab>o|^Ye#LLJABBe6?xyYzx%-&?avHxpHClo zdTsaE&CHuCkrk1%-9eq@J%pZQ+2_*jTI*#;%4%19p7+EF@(CIW$|lUm$4Uzx?tkOe z)!UohY5Q70lRq^#-caW8*SIOo+iDlp9^NbK&Kw!6m|rcWWYz6O4TWT`DU9G+{hbHw z9$EMEz0FvjUQUT$jZbW!Z$E!R)#8kQpWnj}%Hl@i8}HnL_NF^3+NN5m=lq6FwpaFj z$^V!OX>i>&75^!e>f80_TQnPb<9ap3wQ@T2t4HyPxk^<(2a8h=D}z4m9&v6w(>gU1 zA{jzD>bTy~P3ap5t^aiFqxn>-D@Q9&yAVpitzs-_>NBbMZO>d`H3BLQXZUN;0!G1W zv!gZHXCZT*@6yiQpWOEiGbEpHG?tJo)3cGcf}M&QYf7>1c~!e#*HR|-!Sg#?S2y28 zF0AK{=8lQo6^lzcos^sVE|+}7WrMgL`02~n$*{EloGS{=SQ~zPO8VSnsuL2id1Z?> z)HCexxj4SsZMo`f_qpYT)KSeZ^a#q>fJ{hZK+oEd>5Ycqah~bOn1mqN$43Is1yx+G zzCXWb<-(UWR7LFx)(a&FYiwf<06|Kum(2?R@QpRaoB)6`PyqPk4gjbd0PqL(R+aT( z*1`^|u@fBt_{Fv_HsI#1T>!w1RPq<0cj33r|RRq2*yD){D~k7TWpXIRvRaG^a$v10E$IG!ZR?S z01}Z*M+KnezVo735QQ-~BAD{!pnBDTw(rEc3_JdNOo z#~q_lNTBcKh$8$=1b!;e`)36|Y;pgrUjH9$A-|n5CeT?m6ZrE~pTPV691#gD-&oa- z!eF;gC|Zt=VfifgbMo&T{&y++LF(^?XHovDxW6f*A22%QG{YZ5!|Qso()+hH4gYIR z|1iUPVaT3%R^NokZ3~5Lcb6Z^AU`tjU(w&!{#PgZ1!uLl?cwj<%6jy6GxAFBL0fXkPa}0-q@I=Q=|9 z^@|Ao-DI98uQocmt8(%u?$nj16b9K(2lM1qZkY;~pftK)*o@a^ zPs1r)3BD)1Q;jaOySYG#p;tCdd|HYc1$dzC-<~daMLG{>$Fl+RL?G*)?4;pdjwb;- zc{&6qT+{gD*!;QY*8`uJJtlG=WF8L~^c1dW;ZBdW*0Q=OL&|R%7HGRx1Lcd;&$BrB zhVm7mbWVh6>TIlOoP0_}yYJqvTZZf=u9q+H6iP9~%<~}~kT1n|54}$E=mM+QnE~0+ zyNXSqiVM{ctwU?;eA&92BJn*f>{RkQ9^fT51bCu$No-d8X=4L(1$cDf39pREik{O> zVbHT^Ti#%x9~vi%Yj$9|z3}R6+cmfXn6x6D26zV7Xu;$8G>*&Hf}e)ICja00Z&k zr`~5|W-a0d?Z#Sxw$8|f1Iy~SlY8{S!ZXEy%Htz>a4BY)F5Aobu2E>&i)J3CgHR!` zYokFVj0(w_l`bf4KWJQX6)A`(m-O$v@oprvR zx`GK~AoTTeule(A0m0xGRSK;a4g=Cdg`BbNfo7M|&OfRPMlzSTQf1Ak>P1g9O;hfK zT+Y1$98fc*$6^?gQh4zY4PCY(5)#RQJbCeuB{8Kw>bbXF|;r! I(sK{{A0@`iOaK4? literal 0 HcmV?d00001 diff --git a/firmware/targets/f7/src/recovery.c b/firmware/targets/f7/src/recovery.c index d56be4fe..db538b0d 100644 --- a/firmware/targets/f7/src/recovery.c +++ b/firmware/targets/f7/src/recovery.c @@ -5,24 +5,20 @@ #include #include -#define COUNTER_VALUE (100U) +#define COUNTER_VALUE (136U) static void flipper_boot_recovery_draw_splash(u8g2_t* fb, size_t progress) { - u8g2_ClearBuffer(fb); - u8g2_SetDrawColor(fb, 0x01); - - u8g2_SetFont(fb, u8g2_font_helvB08_tr); - u8g2_DrawStr(fb, 2, 8, "PIN and Factory Reset"); - u8g2_SetFont(fb, u8g2_font_haxrcorp4089_tr); - u8g2_DrawStr(fb, 2, 21, "Hold Right to confirm"); - u8g2_DrawStr(fb, 2, 31, "Press Down to cancel"); - if(progress < COUNTER_VALUE) { - size_t width = progress / (COUNTER_VALUE / 100); - u8g2_DrawBox(fb, 14 + (50 - width / 2), 54, width, 3); + // Fill the progress bar while the progress is going down + u8g2_SetDrawColor(fb, 0x01); + u8g2_DrawRFrame(fb, 59, 41, 69, 8, 2); + size_t width = (COUNTER_VALUE - progress) * 68 / COUNTER_VALUE; + u8g2_DrawBox(fb, 60, 42, width, 6); + } else { + u8g2_SetDrawColor(fb, 0x00); + u8g2_DrawRBox(fb, 59, 41, 69, 8, 2); } - u8g2_SetPowerSave(fb, 0); u8g2_SendBuffer(fb); } @@ -31,6 +27,18 @@ void flipper_boot_recovery_exec() { u8g2_Setup_st756x_flipper(fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); u8g2_InitDisplay(fb); + furi_hal_compress_icon_init(); + uint8_t* splash_data = NULL; + furi_hal_compress_icon_decode(icon_get_data(&I_Erase_pin_128x64), &splash_data); + + u8g2_ClearBuffer(fb); + u8g2_SetDrawColor(fb, 0x01); + + // Draw the recovery picture + u8g2_DrawXBM(fb, 0, 0, 128, 64, splash_data); + u8g2_SendBuffer(fb); + u8g2_SetPowerSave(fb, 0); + size_t counter = COUNTER_VALUE; while(counter) { if(!furi_hal_gpio_read(&gpio_button_down)) { From 806428efeb172a9e5adaf72955098a50fe22fadb Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:23:33 +0300 Subject: [PATCH 03/23] [FL-3070] iButton system and app refactoring (#2388) * Add 1-wire thermometer example app stub * Working 1-wire thermometer app * Refactor app to use threads * Clean up code, add comments * Add CRC checking * Increase update period * Fix error in fbt * Revert the old update period * Use settable pin in onewire_host * Use settable pin for onewire_slave * Clear EXTI flag after callback, make private methods static in onewire_slave * Do not hardcode GPIO pin number * Remove iButton hal from furi_hal_rfid * Remove most of furi_hal_ibutton * Add some of furi_hal_ibutton back * Slightly neater code * Update CODEOWNERS * Add furi_hal_gpio_get_ext_pin_number * Create README.md * Temporary get Metakom and Cyfral keys out of the way * Better enum name * Syncing work, does not compile * Syncing work, now compiles * Working read impl for DS1990 and DS1992 * Add the ability to display extended key data * Get rid of DialogEx * Add save and load API * Better iButtonKey encapsulation * Fix crash * Load key code boilerplate * More load key code boilerplate * Minor code cleanup * Implement loading and saving DS1990 keys * Implement the Info scene * Implement loading & saving for DS1992 * Implement read error scene stub * Implement delete confirmation screen * Better error messages (protocol-dependent) * Minor old code cleanup * Remove iButtonDevice, add command callback to iButtonSlave * Implement draft emulation for DS1990 * Better emulation for DS1990 * Initial emulation implementation for DS1992 * Better common command definitions * Use common submenu callback, add protocol list * Improve ViewData screen * Improve scene_add_type * Add stubs for write functionality * Improve naming consistency * Implement writing a DS1992 onto another one * Improve DS1992 write code * Improve DS1992 write code once more * Prepare write_blank for DS1990, delete ibutton_writer * Implement writing DS1990 onto blanks * Fix reading DS1990 * Partially implement writing DS1992 onto blanks * Implement GUI for writing keys * Implement GUI for emulating keys * Reduce memory usage for pretty_format * Automatically truncate data more than 256 bytes * Initial implementation of DS1996 (not tested) * Fix crash due to missing virtual function * Improve emulation code * Improve DS1992 emulation code * Correct return value for onewire_slave_send * Correct return value for onewire_slave_receive * Implement emulation for DS1992 & DS1996 * Better constant names * Simplify & optimise the emulation code * Remove duplicate code * Add skip rom command emulation * Show loading animation for large keys * Implement manual adding & editing of keys * Use buffered file streams to speed up saving & loading * Reset key name before adding a new one * Sync a buffered file stream before saving * Use the DSGeneric protocol as a fallback option * Implement emulation via RPC * Refactor iButton code in preparation for comparator keys * Refactor iButton code in preparation for comparator keys once more * Make some functions static * Make protocols not rely on one_wire classes * Improve ProtocolDict usage * Improve ProtocolDict usage more * Implement reading Metakom & Cyfral keys * Rename some files * Better file structure * Implement a unified interface for misc protocols * Implement a unified interface for dallas protocols * Concrete types for Dallas protocols * Implement a unified interface for all key types * Improved type naming * Improved private types * Proper types in protocol definitions * Implement emulation for Cyfral & Metakom keys * Implement save&load for Metakom & Cyfral keys * Better type names * Rename files, better names * Allocate iButtonProtocols like a normal class * Reset the key each time the start scene is selected * Improve comments and constants * Add ibutton_protocols to SDK headers * Add ibutton_key to SDK headers * Add ibutton_key to SDK headers * Implement reading via cli * Implement emulation via cli * Implement writing Dallas blanks via cli * Correctly revert the editing if cancelled by the user * Correct committing mishap * Elide the long text on the info screen * Change key name for data in Misc keys * Update iButtonFileFormat.md * Remember the key's folder * Save menu position in ReadKeyMenu and SavedKeyMenu * Correct use of preselected path in file browser Co-authored-by: Aleksandr Kutuzov --- applications/main/ibutton/ibutton.c | 236 +++++------- applications/main/ibutton/ibutton_cli.c | 178 +++++---- .../main/ibutton/ibutton_custom_event.h | 1 + applications/main/ibutton/ibutton_i.h | 50 ++- .../ibutton/scenes/ibutton_scene_add_type.c | 58 ++- .../ibutton/scenes/ibutton_scene_add_value.c | 43 ++- .../ibutton/scenes/ibutton_scene_config.h | 4 +- .../scenes/ibutton_scene_delete_confirm.c | 76 +--- .../ibutton/scenes/ibutton_scene_emulate.c | 68 +--- .../main/ibutton/scenes/ibutton_scene_info.c | 72 ++-- .../main/ibutton/scenes/ibutton_scene_read.c | 26 +- .../scenes/ibutton_scene_read_crc_error.c | 70 ---- .../ibutton/scenes/ibutton_scene_read_error.c | 58 +++ .../scenes/ibutton_scene_read_key_menu.c | 57 ++- .../scenes/ibutton_scene_read_not_key_error.c | 71 ---- .../scenes/ibutton_scene_read_success.c | 76 ++-- .../main/ibutton/scenes/ibutton_scene_rpc.c | 44 +-- .../ibutton/scenes/ibutton_scene_save_name.c | 44 +-- .../scenes/ibutton_scene_saved_key_menu.c | 72 ++-- .../ibutton/scenes/ibutton_scene_select_key.c | 6 +- .../main/ibutton/scenes/ibutton_scene_start.c | 17 +- .../ibutton/scenes/ibutton_scene_view_data.c | 26 ++ .../main/ibutton/scenes/ibutton_scene_write.c | 80 ++-- .../scenes/infrared_scene_universal.c | 2 +- applications/services/gui/modules/widget.h | 1 + .../widget_element_text_scroll.c | 2 + .../file_formats/iButtonFileFormat.md | 47 ++- firmware/targets/f18/api_symbols.csv | 2 +- firmware/targets/f7/api_symbols.csv | 67 ++-- lib/flipper_format/flipper_format.c | 6 + lib/flipper_format/flipper_format.h | 11 +- lib/one_wire/SConscript | 3 +- lib/one_wire/ibutton/ibutton_key.c | 111 ++---- lib/one_wire/ibutton/ibutton_key.h | 120 +----- lib/one_wire/ibutton/ibutton_key_command.h | 28 -- lib/one_wire/ibutton/ibutton_key_i.h | 9 + lib/one_wire/ibutton/ibutton_protocols.c | 309 +++++++++++++++ lib/one_wire/ibutton/ibutton_protocols.h | 197 ++++++++++ lib/one_wire/ibutton/ibutton_worker.c | 73 ++-- lib/one_wire/ibutton/ibutton_worker.h | 15 +- lib/one_wire/ibutton/ibutton_worker_i.h | 31 +- lib/one_wire/ibutton/ibutton_worker_modes.c | 312 +++------------ lib/one_wire/ibutton/ibutton_writer.c | 298 -------------- lib/one_wire/ibutton/ibutton_writer.h | 60 --- .../ibutton/protocols/blanks/rw1990.c | 95 +++++ .../ibutton/protocols/blanks/rw1990.h | 9 + .../ibutton/protocols/blanks/tm2004.c | 42 ++ .../ibutton/protocols/blanks/tm2004.h | 7 + .../ibutton/protocols/dallas/dallas_common.c | 250 ++++++++++++ .../ibutton/protocols/dallas/dallas_common.h | 107 ++++++ .../protocols/dallas/protocol_dallas_base.h | 39 ++ .../protocols/dallas/protocol_ds1990.c | 144 +++++++ .../protocols/dallas/protocol_ds1990.h | 5 + .../protocols/dallas/protocol_ds1992.c | 218 +++++++++++ .../protocols/dallas/protocol_ds1992.h | 5 + .../protocols/dallas/protocol_ds1996.c | 212 ++++++++++ .../protocols/dallas/protocol_ds1996.h | 5 + .../protocols/dallas/protocol_ds_generic.c | 133 +++++++ .../protocols/dallas/protocol_ds_generic.h | 5 + .../protocols/dallas/protocol_group_dallas.c | 310 +++++++++++++++ .../protocols/dallas/protocol_group_dallas.h | 5 + .../dallas/protocol_group_dallas_defs.c | 16 + .../dallas/protocol_group_dallas_defs.h | 16 + .../ibutton/protocols/ibutton_protocols.c | 8 - .../ibutton/protocols/ibutton_protocols.h | 11 - .../protocols/{ => misc}/protocol_cyfral.c | 10 +- .../ibutton/protocols/misc/protocol_cyfral.h | 4 + .../protocols/misc/protocol_group_misc.c | 295 ++++++++++++++ .../protocols/misc/protocol_group_misc.h | 5 + .../protocols/misc/protocol_group_misc_defs.c | 10 + .../protocols/misc/protocol_group_misc_defs.h | 11 + .../protocols/{ => misc}/protocol_metakom.c | 10 +- .../ibutton/protocols/misc/protocol_metakom.h | 4 + .../ibutton/protocols/protocol_common.h | 21 + .../ibutton/protocols/protocol_common_i.h | 6 + .../ibutton/protocols/protocol_cyfral.h | 4 - .../ibutton/protocols/protocol_group_base.h | 104 +++++ .../ibutton/protocols/protocol_group_defs.c | 9 + .../ibutton/protocols/protocol_group_defs.h | 11 + .../ibutton/protocols/protocol_metakom.h | 4 - lib/one_wire/one_wire_device.c | 59 --- lib/one_wire/one_wire_device.h | 74 ---- lib/one_wire/one_wire_host.c | 10 +- lib/one_wire/one_wire_host.h | 12 +- lib/one_wire/one_wire_slave.c | 363 +++++++++--------- lib/one_wire/one_wire_slave.h | 58 ++- lib/one_wire/one_wire_slave_i.h | 38 -- lib/toolbox/SConscript | 1 + lib/toolbox/pretty_format.c | 60 +++ lib/toolbox/pretty_format.h | 29 ++ lib/toolbox/stream/buffered_file_stream.c | 1 + 91 files changed, 3826 insertions(+), 2166 deletions(-) delete mode 100644 applications/main/ibutton/scenes/ibutton_scene_read_crc_error.c create mode 100644 applications/main/ibutton/scenes/ibutton_scene_read_error.c delete mode 100644 applications/main/ibutton/scenes/ibutton_scene_read_not_key_error.c create mode 100644 applications/main/ibutton/scenes/ibutton_scene_view_data.c delete mode 100644 lib/one_wire/ibutton/ibutton_key_command.h create mode 100644 lib/one_wire/ibutton/ibutton_key_i.h create mode 100644 lib/one_wire/ibutton/ibutton_protocols.c create mode 100644 lib/one_wire/ibutton/ibutton_protocols.h delete mode 100644 lib/one_wire/ibutton/ibutton_writer.c delete mode 100644 lib/one_wire/ibutton/ibutton_writer.h create mode 100644 lib/one_wire/ibutton/protocols/blanks/rw1990.c create mode 100644 lib/one_wire/ibutton/protocols/blanks/rw1990.h create mode 100644 lib/one_wire/ibutton/protocols/blanks/tm2004.c create mode 100644 lib/one_wire/ibutton/protocols/blanks/tm2004.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/dallas_common.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/dallas_common.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_dallas_base.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.h create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c create mode 100644 lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h delete mode 100644 lib/one_wire/ibutton/protocols/ibutton_protocols.c delete mode 100644 lib/one_wire/ibutton/protocols/ibutton_protocols.h rename lib/one_wire/ibutton/protocols/{ => misc}/protocol_cyfral.c (96%) create mode 100644 lib/one_wire/ibutton/protocols/misc/protocol_cyfral.h create mode 100644 lib/one_wire/ibutton/protocols/misc/protocol_group_misc.c create mode 100644 lib/one_wire/ibutton/protocols/misc/protocol_group_misc.h create mode 100644 lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.c create mode 100644 lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.h rename lib/one_wire/ibutton/protocols/{ => misc}/protocol_metakom.c (96%) create mode 100644 lib/one_wire/ibutton/protocols/misc/protocol_metakom.h create mode 100644 lib/one_wire/ibutton/protocols/protocol_common.h create mode 100644 lib/one_wire/ibutton/protocols/protocol_common_i.h delete mode 100644 lib/one_wire/ibutton/protocols/protocol_cyfral.h create mode 100644 lib/one_wire/ibutton/protocols/protocol_group_base.h create mode 100644 lib/one_wire/ibutton/protocols/protocol_group_defs.c create mode 100644 lib/one_wire/ibutton/protocols/protocol_group_defs.h delete mode 100644 lib/one_wire/ibutton/protocols/protocol_metakom.h delete mode 100644 lib/one_wire/one_wire_device.c delete mode 100644 lib/one_wire/one_wire_device.h delete mode 100644 lib/one_wire/one_wire_slave_i.h create mode 100644 lib/toolbox/pretty_format.c create mode 100644 lib/toolbox/pretty_format.h diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index 85212f42..79999adb 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -1,10 +1,6 @@ -#include "ibutton.h" -#include "assets_icons.h" #include "ibutton_i.h" -#include "ibutton/scenes/ibutton_scene.h" + #include -#include -#include #include #define TAG "iButtonApp" @@ -34,50 +30,13 @@ static const NotificationSequence* ibutton_notification_sequences[] = { }; 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"); } -} -bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog) { - 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; + furi_record_close(RECORD_STORAGE); } 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) { view_dispatcher_send_custom_event( ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); - rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); - ibutton->rpc_ctx = NULL; + rpc_system_app_set_callback(ibutton->rpc, NULL, NULL); + ibutton->rpc = NULL; } else if(event == RpcAppEventAppExit) { view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); } else if(event == RpcAppEventLoadFile) { view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad); } 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->storage = furi_record_open(RECORD_STORAGE); ibutton->dialogs = furi_record_open(RECORD_DIALOGS); ibutton->notifications = furi_record_open(RECORD_NOTIFICATION); - ibutton->key = ibutton_key_alloc(); - ibutton->key_worker = ibutton_worker_alloc(); - ibutton_worker_start_thread(ibutton->key_worker); + ibutton->protocols = ibutton_protocols_alloc(); + ibutton->key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(ibutton->protocols)); + ibutton->worker = ibutton_worker_alloc(ibutton->protocols); + ibutton_worker_start_thread(ibutton->worker); ibutton->submenu = submenu_alloc(); view_dispatcher_add_view( @@ -163,9 +122,9 @@ iButton* ibutton_alloc() { view_dispatcher_add_view( ibutton->view_dispatcher, iButtonViewWidget, widget_get_view(ibutton->widget)); - ibutton->dialog_ex = dialog_ex_alloc(); + ibutton->loading = loading_alloc(); 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; } @@ -173,8 +132,8 @@ iButton* ibutton_alloc() { void ibutton_free(iButton* ibutton) { furi_assert(ibutton); - view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewDialogEx); - dialog_ex_free(ibutton->dialog_ex); + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewLoading); + loading_free(ibutton->loading); view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewWidget); widget_free(ibutton->widget); @@ -194,9 +153,6 @@ void ibutton_free(iButton* ibutton) { view_dispatcher_free(ibutton->view_dispatcher); scene_manager_free(ibutton->scene_manager); - furi_record_close(RECORD_STORAGE); - ibutton->storage = NULL; - furi_record_close(RECORD_NOTIFICATION); ibutton->notifications = NULL; @@ -206,103 +162,83 @@ void ibutton_free(iButton* ibutton) { furi_record_close(RECORD_GUI); ibutton->gui = NULL; - ibutton_worker_stop_thread(ibutton->key_worker); - ibutton_worker_free(ibutton->key_worker); + ibutton_worker_stop_thread(ibutton->worker); + ibutton_worker_free(ibutton->worker); ibutton_key_free(ibutton->key); + ibutton_protocols_free(ibutton->protocols); furi_string_free(ibutton->file_path); free(ibutton); } -bool ibutton_file_select(iButton* ibutton) { - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px); - browser_options.base_path = IBUTTON_APP_FOLDER; +bool ibutton_load_key(iButton* ibutton) { + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading); - bool success = dialog_file_browser_show( - ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options); + const bool success = ibutton_protocols_load( + ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path)); - if(success) { - success = ibutton_load_key_data(ibutton, ibutton->file_path, true); + if(!success) { + 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; } -bool ibutton_save_key(iButton* ibutton, const char* key_name) { - // Create ibutton directory if necessary +bool ibutton_select_and_load_key(iButton* ibutton) { + 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); - FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); iButtonKey* key = ibutton->key; + const bool success = + ibutton_protocols_save(ibutton->protocols, key, furi_string_get_cstr(ibutton->file_path)); - bool result = false; - - 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 + if(!success) { dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file"); } - return result; + return success; } bool ibutton_delete_key(iButton* ibutton) { 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; } -void ibutton_text_store_set(iButton* ibutton, const char* text, ...) { - va_list args; - va_start(args, text); - - 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_reset_key(iButton* ibutton) { + memset(ibutton->key_name, 0, IBUTTON_KEY_NAME_SIZE + 1); + furi_string_reset(ibutton->file_path); + ibutton_key_reset(ibutton->key); } 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]); } -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_make_app_folder(ibutton); bool key_loaded = false; - bool rpc_mode = false; - if(p && strlen(p)) { - uint32_t rpc_ctx = 0; - if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { + if((arg != NULL) && (strlen(arg) != 0)) { + if(sscanf(arg, "RPC %lX", (uint32_t*)&ibutton->rpc) == 1) { FURI_LOG_D(TAG, "Running in RPC mode"); - ibutton->rpc_ctx = (void*)rpc_ctx; - rpc_mode = true; - rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton); - rpc_system_app_send_started(ibutton->rpc_ctx); + + rpc_system_app_set_callback(ibutton->rpc, ibutton_rpc_command_callback, ibutton); + rpc_system_app_send_started(ibutton->rpc); + } else { - furi_string_set(ibutton->file_path, (const char*)p); - if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) { - key_loaded = true; - // TODO: Display an error if the key from p could not be loaded - } + furi_string_set(ibutton->file_path, (const char*)arg); + key_loaded = ibutton_load_key(ibutton); } } - if(rpc_mode) { + if(ibutton->rpc != NULL) { view_dispatcher_attach_to_gui( ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); DOLPHIN_DEED(DolphinDeedIbuttonEmulate); + } else { view_dispatcher_attach_to_gui( ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); @@ -353,9 +297,9 @@ int32_t ibutton_app(void* p) { view_dispatcher_run(ibutton->view_dispatcher); - if(ibutton->rpc_ctx) { - rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); - rpc_system_app_send_exited(ibutton->rpc_ctx); + if(ibutton->rpc) { + rpc_system_app_set_callback(ibutton->rpc, NULL, NULL); + rpc_system_app_send_exited(ibutton->rpc); } ibutton_free(ibutton); return 0; diff --git a/applications/main/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c index 9ddb079d..2b88b200 100644 --- a/applications/main/ibutton/ibutton_cli.c +++ b/applications/main/ibutton/ibutton_cli.c @@ -1,11 +1,15 @@ #include #include -#include + #include -#include -#include +#include + #include +#include +#include +#include + static void ibutton_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 } -void ibutton_cli_print_usage() { +static void ibutton_cli_print_usage() { printf("Usage:\r\n"); printf("ikey read\r\n"); printf("ikey emulate \r\n"); @@ -34,30 +38,52 @@ void ibutton_cli_print_usage() { printf("\t 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; + FuriString* name = furi_string_alloc(); - if(furi_string_cmp_str(data, "Dallas") == 0 || furi_string_cmp_str(data, "dallas") == 0) { - result = true; - *type = iButtonKeyDS1990; - } 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; - } + do { + // Read protocol name + if(!args_read_string_and_trim(args, name)) break; + // 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; } -void ibutton_cli_print_key_data(iButtonKey* key) { - const uint8_t* key_data = ibutton_key_get_data_p(key); - iButtonKeyType type = ibutton_key_get_type(key); +static void ibutton_cli_print_key(iButtonProtocols* protocols, iButtonKey* key) { + const char* name = ibutton_protocols_get_name(protocols, ibutton_key_get_protocol_id(key)); - printf("%s ", ibutton_key_get_string_by_type(type)); - for(size_t i = 0; i < ibutton_key_get_size_by_type(type); i++) { - printf("%02X", key_data[i]); + if(strncmp(name, "DS", 2) == 0) { + name = "Dallas"; + } + + 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"); @@ -71,9 +97,10 @@ static void ibutton_cli_worker_read_cb(void* context) { furi_event_flag_set(event, EVENT_FLAG_IBUTTON_COMPLETE); } -void ibutton_cli_read(Cli* cli) { - iButtonKey* key = ibutton_key_alloc(); - iButtonWorker* worker = ibutton_worker_alloc(); +static void ibutton_cli_read(Cli* cli) { + iButtonProtocols* protocols = ibutton_protocols_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(); 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"); ibutton_worker_read_start(worker, key); + while(true) { uint32_t flags = furi_event_flag_wait(event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100); if(flags & EVENT_FLAG_IBUTTON_COMPLETE) { - ibutton_cli_print_key_data(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"); - } - } + ibutton_cli_print_key(protocols, key); break; } if(cli_cmd_interrupt_received(cli)) break; } - ibutton_worker_stop(worker); + ibutton_worker_stop(worker); ibutton_worker_stop_thread(worker); - ibutton_worker_free(worker); + ibutton_key_free(key); + ibutton_worker_free(worker); + ibutton_protocols_free(protocols); 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) { - iButtonKey* key = ibutton_key_alloc(); - iButtonWorker* worker = ibutton_worker_alloc(); - iButtonKeyType type; - iButtonWriteContext write_context; - uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; - FuriString* data; + iButtonProtocols* protocols = ibutton_protocols_alloc(); + iButtonWorker* worker = ibutton_worker_alloc(protocols); + iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols)); + iButtonWriteContext write_context; write_context.event = furi_event_flag_alloc(); - data = furi_string_alloc(); ibutton_worker_start_thread(worker); ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context); do { - if(!args_read_string_and_trim(args, data)) { + if(!ibutton_cli_parse_key(protocols, key, args)) { ibutton_cli_print_usage(); 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(); 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 "); - ibutton_cli_print_key_data(key); + ibutton_cli_print_key(protocols, key); printf("Press Ctrl+C to abort\r\n"); - ibutton_worker_write_start(worker, key); + ibutton_worker_write_blank_start(worker, key); while(true) { uint32_t flags = furi_event_flag_wait( 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; } - ibutton_worker_stop(worker); } while(false); - furi_string_free(data); + ibutton_worker_stop(worker); ibutton_worker_stop_thread(worker); - ibutton_worker_free(worker); + ibutton_key_free(key); + ibutton_worker_free(worker); + ibutton_protocols_free(protocols); furi_event_flag_free(write_context.event); -}; +} void ibutton_cli_emulate(Cli* cli, FuriString* args) { - iButtonKey* key = ibutton_key_alloc(); - iButtonWorker* worker = ibutton_worker_alloc(); - iButtonKeyType type; - uint8_t key_data[IBUTTON_KEY_DATA_SIZE]; - FuriString* data; + iButtonProtocols* protocols = ibutton_protocols_alloc(); + iButtonWorker* worker = ibutton_worker_alloc(protocols); + iButtonKey* key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(protocols)); - data = furi_string_alloc(); ibutton_worker_start_thread(worker); do { - if(!args_read_string_and_trim(args, data)) { + if(!ibutton_cli_parse_key(protocols, key, args)) { ibutton_cli_print_usage(); 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 "); - ibutton_cli_print_key_data(key); + ibutton_cli_print_key(protocols, key); printf("Press Ctrl+C to abort\r\n"); ibutton_worker_emulate_start(worker, key); + while(!cli_cmd_interrupt_received(cli)) { furi_delay_ms(100); }; - ibutton_worker_stop(worker); + } while(false); - furi_string_free(data); + ibutton_worker_stop(worker); ibutton_worker_stop_thread(worker); - ibutton_worker_free(worker); + 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); FuriString* cmd; cmd = furi_string_alloc(); @@ -264,7 +258,7 @@ static void ibutton_cli(Cli* cli, FuriString* args, void* context) { furi_string_free(cmd); } -void onewire_cli_print_usage() { +static void onewire_cli_print_usage() { printf("Usage:\r\n"); printf("onewire search\r\n"); }; @@ -281,7 +275,7 @@ static void onewire_cli_search(Cli* cli) { furi_hal_power_enable_otg(); while(!done) { - if(onewire_host_search(onewire, address, NORMAL_SEARCH) != 1) { + if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) { printf("Search finished\r\n"); onewire_host_reset_search(onewire); done = true; diff --git a/applications/main/ibutton/ibutton_custom_event.h b/applications/main/ibutton/ibutton_custom_event.h index 1e2f0300..28bcb94a 100644 --- a/applications/main/ibutton/ibutton_custom_event.h +++ b/applications/main/ibutton/ibutton_custom_event.h @@ -6,6 +6,7 @@ enum iButtonCustomEvent { iButtonCustomEventBack, iButtonCustomEventTextEditResult, + iButtonCustomEventByteEditChanged, iButtonCustomEventByteEditResult, iButtonCustomEventWorkerEmulated, iButtonCustomEventWorkerRead, diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index 0a809935..8ad0b90e 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -4,31 +4,40 @@ #include #include -#include -#include #include -#include +#include #include +#include + +#include #include #include +#include +#include #include #include -#include #include #include #include +#include + +#include #include "ibutton_custom_event.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_EXTENSION ".ibtn" -#define IBUTTON_APP_FILE_TYPE "Flipper iButton key" + +#define IBUTTON_KEY_NAME_SIZE 22 + +typedef enum { + iButtonWriteModeInvalid, + iButtonWriteModeBlank, + iButtonWriteModeCopy, +} iButtonWriteMode; struct iButton { SceneManager* scene_manager; @@ -38,21 +47,22 @@ struct iButton { Storage* storage; DialogsApp* dialogs; NotificationApp* notifications; + RpcAppSystem* rpc; - iButtonWorker* key_worker; iButtonKey* key; + iButtonWorker* worker; + iButtonProtocols* protocols; + iButtonWriteMode write_mode; FuriString* file_path; - char text_store[IBUTTON_TEXT_STORE_SIZE + 1]; + char key_name[IBUTTON_KEY_NAME_SIZE + 1]; Submenu* submenu; ByteInput* byte_input; TextInput* text_input; Popup* popup; Widget* widget; - DialogEx* dialog_ex; - - void* rpc_ctx; + Loading* loading; }; typedef enum { @@ -61,7 +71,7 @@ typedef enum { iButtonViewTextInput, iButtonViewPopup, iButtonViewWidget, - iButtonViewDialogEx, + iButtonViewLoading, } iButtonView; typedef enum { @@ -78,10 +88,12 @@ typedef enum { iButtonNotificationMessageBlinkStop, } iButtonNotificationMessage; -bool ibutton_file_select(iButton* ibutton); -bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog); -bool ibutton_save_key(iButton* ibutton, const char* key_name); +bool ibutton_select_and_load_key(iButton* ibutton); +bool ibutton_load_key(iButton* ibutton); +bool ibutton_save_key(iButton* ibutton); bool ibutton_delete_key(iButton* ibutton); -void ibutton_text_store_set(iButton* ibutton, const char* text, ...); -void ibutton_text_store_clear(iButton* ibutton); +void ibutton_reset_key(iButton* ibutton); 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); diff --git a/applications/main/ibutton/scenes/ibutton_scene_add_type.c b/applications/main/ibutton/scenes/ibutton_scene_add_type.c index 38373999..968bbac1 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_add_type.c +++ b/applications/main/ibutton/scenes/ibutton_scene_add_type.c @@ -1,54 +1,48 @@ #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) { iButton* ibutton = context; Submenu* submenu = ibutton->submenu; - submenu_add_item( - 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); + FuriString* tmp = furi_string_alloc(); - submenu_set_selected_item( - submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType)); + for(uint32_t protocol_id = 0; protocol_id < ibutton_protocols_get_protocol_count(); + ++protocol_id) { + furi_string_printf( + tmp, + "%s %s", + ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), + 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); + furi_string_free(tmp); } bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) { iButton* ibutton = context; iButtonKey* key = ibutton->key; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, 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"); - } + const iButtonProtocolId protocol_id = event.event; - furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); - ibutton_key_clear_data(key); + ibutton_key_reset(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); + + consumed = true; } return consumed; diff --git a/applications/main/ibutton/scenes/ibutton_scene_add_value.c b/applications/main/ibutton/scenes/ibutton_scene_add_value.c index ccac7612..dc340771 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_add_value.c +++ b/applications/main/ibutton/scenes/ibutton_scene_add_value.c @@ -1,42 +1,52 @@ #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; 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) { iButton* ibutton = context; - iButtonKey* key = ibutton->key; - uint8_t* new_key_data = malloc(IBUTTON_KEY_DATA_SIZE); + byte_input_set_header_text(ibutton->byte_input, "Enter the key"); - scene_manager_set_scene_state( - ibutton->scene_manager, iButtonSceneAddValue, (uint32_t)new_key_data); - memcpy(new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)); + iButtonEditableData editable_data; + ibutton_protocols_get_editable_data(ibutton->protocols, ibutton->key, &editable_data); byte_input_set_result_callback( ibutton->byte_input, ibutton_scene_add_type_byte_input_callback, - NULL, - ibutton, - new_key_data, - ibutton_key_get_data_size(key)); + ibutton_scene_add_type_byte_changed_callback, + context, + editable_data.ptr, + editable_data.size); - byte_input_set_header_text(ibutton->byte_input, "Enter the key"); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewByteInput); } bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { iButton* ibutton = context; - uint8_t* new_key_data = - (uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue); + SceneManager* scene_manager = ibutton->scene_manager; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == iButtonCustomEventByteEditResult) { - ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); + scene_manager_next_scene(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) { 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_header_text(ibutton->byte_input, NULL); - free(new_key_data); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_config.h b/applications/main/ibutton/scenes/ibutton_scene_config.h index 87fa1a03..79f6791b 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_config.h +++ b/applications/main/ibutton/scenes/ibutton_scene_config.h @@ -6,8 +6,7 @@ ADD_SCENE(ibutton, info, Info) ADD_SCENE(ibutton, read, Read) ADD_SCENE(ibutton, read_key_menu, ReadKeyMenu) ADD_SCENE(ibutton, read_success, ReadSuccess) -ADD_SCENE(ibutton, read_crc_error, ReadCRCError) -ADD_SCENE(ibutton, read_not_key_error, ReadNotKeyError) +ADD_SCENE(ibutton, read_error, ReadError) ADD_SCENE(ibutton, select_key, SelectKey) ADD_SCENE(ibutton, add_type, AddType) 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, retry_confirm, RetryConfirm) ADD_SCENE(ibutton, exit_confirm, ExitConfirm) +ADD_SCENE(ibutton, view_data, ViewData) ADD_SCENE(ibutton, rpc, Rpc) diff --git a/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c index 3d609e83..587cb748 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c +++ b/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c @@ -1,74 +1,29 @@ #include "../ibutton_i.h" #include -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) { iButton* ibutton = context; - Widget* widget = ibutton->widget; iButtonKey* key = ibutton->key; - const uint8_t* key_data = ibutton_key_get_data_p(key); + Widget* widget = ibutton->widget; - FuriString* key_name; - key_name = furi_string_alloc(); - path_extract_filename(ibutton->file_path, key_name, true); + FuriString* tmp = furi_string_alloc(); - ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", furi_string_get_cstr(key_name)); - widget_add_text_box_element( - widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true); + widget_add_button_element(widget, GuiButtonTypeLeft, "Back", ibutton_widget_callback, context); widget_add_button_element( - widget, GuiButtonTypeLeft, "Cancel", ibutton_scene_delete_confirm_widget_callback, ibutton); - widget_add_button_element( - widget, - GuiButtonTypeRight, - "Delete", - ibutton_scene_delete_confirm_widget_callback, - ibutton); + widget, GuiButtonTypeRight, "Delete", ibutton_widget_callback, context); - switch(ibutton_key_get_type(key)) { - 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; - } + furi_string_printf(tmp, "Delete %s?", ibutton->key_name); 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); - - furi_string_free(key_name); + furi_string_free(tmp); } 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(ibutton_delete_key(ibutton)) { 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) { 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) { iButton* ibutton = context; - ibutton_text_store_clear(ibutton); widget_reset(ibutton->widget); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_emulate.c b/applications/main/ibutton/scenes/ibutton_scene_emulate.c index 6f6ffcf5..713b8331 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_emulate.c +++ b/applications/main/ibutton/scenes/ibutton_scene_emulate.c @@ -14,61 +14,32 @@ static void ibutton_scene_emulate_callback(void* context, bool emulated) { void ibutton_scene_emulate_on_enter(void* context) { iButton* ibutton = context; - Widget* widget = ibutton->widget; 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; - 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); - } + widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44); - // check that stored key has name - if(!furi_string_empty(key_name)) { - ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); - } else { - // if not, show key data - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - ibutton_text_store_set( - 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; - } - } + furi_string_printf( + tmp, + "%s\n[%s]", + furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name, + ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key))); + + widget_add_text_box_element( + widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true); widget_add_string_multiline_element( - widget, 90, 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); + widget, 88, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating"); - view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); - - 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_worker_emulate_set_callback(ibutton->worker, ibutton_scene_emulate_callback, ibutton); + ibutton_worker_emulate_start(ibutton->worker, key); 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) { @@ -78,8 +49,7 @@ bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeTick) { uint32_t cnt = scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneEmulate); if(cnt > 0) { - cnt--; - if(cnt == 0) { + if(--cnt == 0) { ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink); } 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) { iButton* ibutton = context; - ibutton_worker_stop(ibutton->key_worker); + ibutton_worker_stop(ibutton->worker); widget_reset(ibutton->widget); ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_info.c b/applications/main/ibutton/scenes/ibutton_scene_info.c index 15648f6f..cf44d6a8 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_info.c +++ b/applications/main/ibutton/scenes/ibutton_scene_info.c @@ -1,66 +1,54 @@ #include "../ibutton_i.h" -#include void ibutton_scene_info_on_enter(void* context) { iButton* ibutton = context; - Widget* widget = ibutton->widget; 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; - key_name = furi_string_alloc(); - path_extract_filename(ibutton->file_path, key_name, true); + FuriString* tmp = furi_string_alloc(); + + 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, 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)) { - 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, 36, AlignCenter, AlignBottom, FontPrimary, "Dallas"); - break; + furi_string_reset(tmp); + ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp); - 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, 36, AlignCenter, AlignBottom, FontPrimary, "Metakom"); - break; + widget_add_string_multiline_element( + widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp)); - case iButtonKeyCyfral: - ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]); - widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Cyfral"); - break; + if(ibutton_protocols_get_features(ibutton->protocols, protocol_id) & + iButtonProtocolFeatureExtData) { + widget_add_button_element( + 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); - - furi_string_free(key_name); + furi_string_free(tmp); } bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; + iButton* ibutton = context; + bool consumed = 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) { iButton* ibutton = context; - ibutton_text_store_clear(ibutton); widget_reset(ibutton->widget); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c index b5ee08e6..2c43b82b 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read.c @@ -10,14 +10,13 @@ void ibutton_scene_read_on_enter(void* context) { iButton* ibutton = context; Popup* popup = ibutton->popup; iButtonKey* key = ibutton->key; - iButtonWorker* worker = ibutton->key_worker; + iButtonWorker* worker = ibutton->worker; popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); 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_start(worker, key); @@ -35,25 +34,14 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { } else if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == iButtonCustomEventWorkerRead) { - bool success = false; - 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) { + if(ibutton_protocols_is_valid(ibutton->protocols, ibutton->key)) { ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); + DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); + + } else { + scene_manager_next_scene(scene_manager, iButtonSceneReadError); } } } @@ -64,7 +52,7 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { void ibutton_scene_read_on_exit(void* context) { iButton* ibutton = context; 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_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_icon(popup, 0, 0, NULL); diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_crc_error.c b/applications/main/ibutton/scenes/ibutton_scene_read_crc_error.c deleted file mode 100644 index f822ff6a..00000000 --- a/applications/main/ibutton/scenes/ibutton_scene_read_crc_error.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "../ibutton_i.h" -#include - -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); -} diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_error.c b/applications/main/ibutton/scenes/ibutton_scene_read_error.c new file mode 100644 index 00000000..e966384b --- /dev/null +++ b/applications/main/ibutton/scenes/ibutton_scene_read_error.c @@ -0,0 +1,58 @@ +#include "../ibutton_i.h" +#include + +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); +} diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c index 0a8ecfa5..716f72c7 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c @@ -4,7 +4,9 @@ typedef enum { SubmenuIndexSave, SubmenuIndexEmulate, - SubmenuIndexWrite, + SubmenuIndexViewData, + SubmenuIndexWriteBlank, + SubmenuIndexWriteCopy, } SubmenuIndex; 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; 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, "Save", SubmenuIndexSave, ibutton_scene_read_key_menu_submenu_callback, ibutton); submenu_add_item( @@ -24,36 +29,66 @@ void ibutton_scene_read_key_menu_on_enter(void* context) { SubmenuIndexEmulate, ibutton_scene_read_key_menu_submenu_callback, ibutton); - if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) { + + if(features & iButtonProtocolFeatureExtData) { submenu_add_item( submenu, - "Write", - SubmenuIndexWrite, + "View Data", + SubmenuIndexViewData, ibutton_scene_read_key_menu_submenu_callback, 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, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneReadKeyMenu)); - view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); } bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) { iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state( - ibutton->scene_manager, iButtonSceneReadKeyMenu, event.event); + scene_manager_set_scene_state(scene_manager, iButtonSceneReadKeyMenu, event.event); consumed = true; + if(event.event == SubmenuIndexSave) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); + scene_manager_next_scene(scene_manager, iButtonSceneSaveName); } else if(event.event == SubmenuIndexEmulate) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + scene_manager_next_scene(scene_manager, iButtonSceneEmulate); DOLPHIN_DEED(DolphinDeedIbuttonEmulate); - } else if(event.event == SubmenuIndexWrite) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); + } else if(event.event == SubmenuIndexViewData) { + 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; diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_not_key_error.c b/applications/main/ibutton/scenes/ibutton_scene_read_not_key_error.c deleted file mode 100644 index 8a752803..00000000 --- a/applications/main/ibutton/scenes/ibutton_scene_read_not_key_error.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "../ibutton_i.h" -#include - -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); -} diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_success.c b/applications/main/ibutton/scenes/ibutton_scene_read_success.c index 749e7af3..2e50bc99 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read_success.c @@ -1,55 +1,40 @@ #include "../ibutton_i.h" -#include -static void ibutton_scene_read_success_dialog_ex_callback(DialogExResult result, void* context) { - iButton* ibutton = context; - view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); -} +#include void ibutton_scene_read_success_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); + Widget* widget = ibutton->widget; - switch(ibutton_key_get_type(key)) { - 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; - } + FuriString* tmp = furi_string_alloc(); - dialog_ex_set_text(dialog_ex, ibutton->text_store, 95, 30, AlignCenter, AlignCenter); - 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); + const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key); - 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); + + furi_string_free(tmp); } 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); } else if(event.type == SceneManagerEventTypeCustom) { consumed = true; - if(event.event == DialogExResultRight) { + if(event.event == GuiButtonTypeRight) { scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu); - } else if(event.event == DialogExResultLeft) { + } else if(event.event == GuiButtonTypeLeft) { 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) { iButton* ibutton = context; - DialogEx* dialog_ex = ibutton->dialog_ex; - ibutton_text_store_clear(ibutton); - - dialog_ex_reset(dialog_ex); + widget_reset(ibutton->widget); ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_rpc.c b/applications/main/ibutton/scenes/ibutton_scene_rpc.c index b25b1b8d..9205eb4b 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_rpc.c +++ b/applications/main/ibutton/scenes/ibutton_scene_rpc.c @@ -1,6 +1,4 @@ #include "../ibutton_i.h" -#include -#include void ibutton_scene_rpc_on_enter(void* 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) { - UNUSED(context); - UNUSED(event); iButton* ibutton = context; Popup* popup = ibutton->popup; @@ -26,40 +22,32 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { 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)) { - ibutton_text_store_set( - ibutton, "emulating\n%s", furi_string_get_cstr(key_name)); - } else { - ibutton_text_store_set(ibutton, "emulating"); - } - popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop); + if(event.event == iButtonCustomEventRpcLoad) { + bool result = false; + const char* file_path = rpc_system_app_get_data(ibutton->rpc); + + if(file_path && (furi_string_empty(ibutton->file_path))) { + furi_string_set(ibutton->file_path, file_path); + + 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_worker_emulate_start(ibutton->worker, ibutton->key); - furi_string_free(key_name); 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) { - rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); + rpc_system_app_confirm(ibutton->rpc, RpcAppEventAppExit, true); scene_manager_stop(ibutton->scene_manager); view_dispatcher_stop(ibutton->view_dispatcher); + } else if(event.event == iButtonCustomEventRpcSessionClose) { scene_manager_stop(ibutton->scene_manager); view_dispatcher_stop(ibutton->view_dispatcher); diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_name.c b/applications/main/ibutton/scenes/ibutton_scene_save_name.c index 5f25a000..4ad0315e 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_name.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_name.c @@ -1,6 +1,8 @@ #include "../ibutton_i.h" -#include + +#include #include + #include 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; TextInput* text_input = ibutton->text_input; - 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); - } + const bool is_new_file = furi_string_empty(ibutton->file_path); - const bool key_name_is_empty = furi_string_empty(key_name); - if(key_name_is_empty) { - set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE); - } else { - ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); + if(is_new_file) { + set_random_name(ibutton->key_name, IBUTTON_KEY_NAME_SIZE); } 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, ibutton_scene_save_name_text_input_callback, ibutton, - ibutton->text_store, + ibutton->key_name, IBUTTON_KEY_NAME_SIZE, - key_name_is_empty); + is_new_file); - FuriString* folder_path; - folder_path = furi_string_alloc(); - - 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)); + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(IBUTTON_APP_FOLDER, IBUTTON_APP_EXTENSION, ibutton->key_name); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); 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) { @@ -56,8 +43,16 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { consumed = true; 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); + if(scene_manager_has_previous_scene( ibutton->scene_manager, iButtonSceneSavedKeyMenu)) { // Nothing, do not count editing as saving @@ -67,6 +62,7 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { } else { DOLPHIN_DEED(DolphinDeedIbuttonSave); } + } else { const uint32_t possible_scenes[] = { iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; diff --git a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c index e4c9c350..80fca28b 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c @@ -3,72 +3,70 @@ enum SubmenuIndex { SubmenuIndexEmulate, - SubmenuIndexWrite, + SubmenuIndexWriteBlank, + SubmenuIndexWriteCopy, SubmenuIndexEdit, SubmenuIndexDelete, 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) { iButton* ibutton = context; Submenu* submenu = ibutton->submenu; - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - ibutton_scene_saved_key_menu_submenu_callback, - ibutton); - if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) { + const uint32_t features = ibutton_protocols_get_features( + ibutton->protocols, ibutton_key_get_protocol_id(ibutton->key)); + + submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, ibutton_submenu_callback, ibutton); + + if(features & iButtonProtocolFeatureWriteBlank) { submenu_add_item( - submenu, - "Write", - SubmenuIndexWrite, - ibutton_scene_saved_key_menu_submenu_callback, - ibutton); + submenu, "Write Blank", SubmenuIndexWriteBlank, ibutton_submenu_callback, ibutton); } - submenu_add_item( - submenu, "Edit", SubmenuIndexEdit, ibutton_scene_saved_key_menu_submenu_callback, ibutton); - submenu_add_item( - submenu, - "Delete", - SubmenuIndexDelete, - ibutton_scene_saved_key_menu_submenu_callback, - ibutton); - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, ibutton_scene_saved_key_menu_submenu_callback, ibutton); + + if(features & iButtonProtocolFeatureWriteCopy) { + submenu_add_item( + submenu, "Write Copy", SubmenuIndexWriteCopy, ibutton_submenu_callback, ibutton); + } + + submenu_add_item(submenu, "Edit", SubmenuIndexEdit, ibutton_submenu_callback, ibutton); + submenu_add_item(submenu, "Delete", SubmenuIndexDelete, ibutton_submenu_callback, ibutton); + submenu_add_item(submenu, "Info", SubmenuIndexInfo, ibutton_submenu_callback, ibutton); submenu_set_selected_item( submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneSavedKeyMenu)); - view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); } bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) { iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state( - ibutton->scene_manager, iButtonSceneSavedKeyMenu, event.event); + scene_manager_set_scene_state(scene_manager, iButtonSceneSavedKeyMenu, event.event); consumed = true; if(event.event == SubmenuIndexEmulate) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + scene_manager_next_scene(scene_manager, iButtonSceneEmulate); DOLPHIN_DEED(DolphinDeedIbuttonEmulate); - } else if(event.event == SubmenuIndexWrite) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); + } 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 == SubmenuIndexEdit) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); + scene_manager_next_scene(scene_manager, iButtonSceneAddValue); } 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) { - 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; diff --git a/applications/main/ibutton/scenes/ibutton_scene_select_key.c b/applications/main/ibutton/scenes/ibutton_scene_select_key.c index 32169a9c..ebd504b1 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_select_key.c +++ b/applications/main/ibutton/scenes/ibutton_scene_select_key.c @@ -3,11 +3,11 @@ void ibutton_scene_select_key_on_enter(void* 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( ibutton->scene_manager, iButtonSceneStart); - } else { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu); } } diff --git a/applications/main/ibutton/scenes/ibutton_scene_start.c b/applications/main/ibutton/scenes/ibutton_scene_start.c index b8f6b07d..37bf96f3 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_start.c +++ b/applications/main/ibutton/scenes/ibutton_scene_start.c @@ -8,21 +8,15 @@ enum SubmenuIndex { 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) { iButton* ibutton = context; Submenu* submenu = ibutton->submenu; - submenu_add_item( - submenu, "Read", SubmenuIndexRead, ibutton_scene_start_submenu_callback, ibutton); - submenu_add_item( - submenu, "Saved", SubmenuIndexSaved, ibutton_scene_start_submenu_callback, ibutton); - submenu_add_item( - submenu, "Add Manually", SubmenuIndexAdd, ibutton_scene_start_submenu_callback, ibutton); + ibutton_reset_key(ibutton); + + submenu_add_item(submenu, "Read", SubmenuIndexRead, ibutton_submenu_callback, ibutton); + submenu_add_item(submenu, "Saved", SubmenuIndexSaved, ibutton_submenu_callback, ibutton); + submenu_add_item(submenu, "Add Manually", SubmenuIndexAdd, ibutton_submenu_callback, ibutton); submenu_set_selected_item( 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); DOLPHIN_DEED(DolphinDeedIbuttonRead); } else if(event.event == SubmenuIndexSaved) { - furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); } else if(event.event == SubmenuIndexAdd) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType); diff --git a/applications/main/ibutton/scenes/ibutton_scene_view_data.c b/applications/main/ibutton/scenes/ibutton_scene_view_data.c new file mode 100644 index 00000000..7e063d7e --- /dev/null +++ b/applications/main/ibutton/scenes/ibutton_scene_view_data.c @@ -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); +} diff --git a/applications/main/ibutton/scenes/ibutton_scene_write.c b/applications/main/ibutton/scenes/ibutton_scene_write.c index cdea04db..541aa1c5 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_write.c +++ b/applications/main/ibutton/scenes/ibutton_scene_write.c @@ -1,5 +1,4 @@ #include "../ibutton_i.h" -#include "toolbox/path.h" typedef enum { iButtonSceneWriteStateDefault, @@ -13,61 +12,46 @@ static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult void ibutton_scene_write_on_enter(void* context) { iButton* ibutton = context; + furi_assert(ibutton->write_mode != iButtonWriteModeInvalid); + iButtonKey* key = ibutton->key; + iButtonWorker* worker = ibutton->worker; + const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key); + 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; - 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); - } + furi_string_printf( + tmp, + "%s\n[%s]", + ibutton->key_name, + ibutton_protocols_get_name(ibutton->protocols, protocol_id)); - // check that stored key has name - if(!furi_string_empty(key_name)) { - ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name)); - } else { - // if not, show key data - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - ibutton_text_store_set( - 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_text_box_element( + widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true); + + ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton); + + furi_string_set(tmp, "iButton\nwriting "); + + if(ibutton->write_mode == iButtonWriteModeBlank) { + furi_string_cat(tmp, "Blank"); + ibutton_worker_write_blank_start(worker, key); + + } else if(ibutton->write_mode == iButtonWriteModeCopy) { + furi_string_cat(tmp, "Copy"); + ibutton_worker_write_copy_start(worker, key); } widget_add_string_multiline_element( - widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nwriting"); - 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); + widget, 88, 10, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp)); 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) { @@ -94,7 +78,9 @@ bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) { void ibutton_scene_write_on_exit(void* context) { iButton* ibutton = context; - ibutton_worker_stop(ibutton->key_worker); + ibutton->write_mode = iButtonWriteModeInvalid; + + ibutton_worker_stop(ibutton->worker); widget_reset(ibutton->widget); ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); diff --git a/applications/main/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c index 4ef7c5c2..e09abde7 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal.c +++ b/applications/main/infrared/scenes/infrared_scene_universal.c @@ -74,4 +74,4 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { void infrared_scene_universal_on_exit(void* context) { Infrared* infrared = context; submenu_reset(infrared->submenu); -} \ No newline at end of file +} diff --git a/applications/services/gui/modules/widget.h b/applications/services/gui/modules/widget.h index 9076ce7f..d9985167 100644 --- a/applications/services/gui/modules/widget.h +++ b/applications/services/gui/modules/widget.h @@ -115,6 +115,7 @@ void widget_add_text_box_element( * @param[in] text Formatted text. Default format: align left, Secondary font. * The following formats are available: * "\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 * "\erRight-aligned text" - sets right horizontal align until the next '\n' symbol */ diff --git a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c index 5d522c74..4c9c39df 100644 --- a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c +++ b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c @@ -37,6 +37,8 @@ static bool line->horizontal = AlignRight; } else if(ctrl_symbol == '#') { line->font = FontPrimary; + } else if(ctrl_symbol == '*') { + line->font = FontKeyboard; } furi_string_right(text, 2); processed = true; diff --git a/documentation/file_formats/iButtonFileFormat.md b/documentation/file_formats/iButtonFileFormat.md index c0458619..adb493e0 100644 --- a/documentation/file_formats/iButtonFileFormat.md +++ b/documentation/file_formats/iButtonFileFormat.md @@ -4,26 +4,47 @@ ``` Filetype: Flipper iButton key -Version: 1 -# Key type can be Cyfral, Dallas or Metakom -Key type: Dallas -# Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8 -Data: 12 34 56 78 9A BC DE F0 +Version: 2 +Protocol: DS1992 +Rom Data: 08 DE AD BE EF FA CE 4E +Sram Data: 4E 65 76 65 72 47 6F 6E 6E 61 47 69 76 65 59 6F 75 55 70 4E 65 76 65 72 47 6F 6E 6E 61 4C 65 74 59 6F 75 44 6F 77 6E 4E 65 76 65 72 47 6F 6E 6E 61 52 75 6E 41 72 6F 75 6E 64 41 6E 64 44 65 73 65 72 74 59 6F 75 4E 65 76 65 72 47 6F 6E 6E 61 4D 61 6B 65 59 6F 75 43 72 79 4E 65 76 65 72 47 6F 6E 6E 61 53 61 79 47 6F 6F 64 62 79 65 4E 65 76 65 72 47 6F 6E 6E 61 54 65 6C 6C 41 4C 69 65 ``` ## Description Filename extension: `.ibtn` -The file stores a single iButton key of the type defined by the `Key type` parameter. +The file stores a single iButton key, complete with all data required by the protocol. -### Version history +## Version history +### 2. Current version. +Changelog: +- Added support for different Dallas protocols +- Fields after `Protocol` are protocol-dependent for flexibiliy + +#### Format fields + +| Name | Type | Description | +| --------- | ------ | -------------------------------------------- | +| Protocol | string | Currently supported: DS1990, DS1992, DS1996, DSGeneric*, Cyfral, Metakom | +| Rom Data | hex | Read-only memory data (Dallas protocols only) | +| Sram Data | hex | Static RAM data (DS1992 and DS1996 only) +| Data | hex | Key data (Cyfral & Metakom only) | + +NOTE 1: DSGeneric is a catch-all protocol for all unknown 1-Wire devices. It reads only the ROM and does not perform any checks on the read data. +It can also be used if a key with a deliberately invalid family code or checksum is required. + +NOTE 2: When adding new protocols, it is not necessarily to increase the format version, define the format in the protocol implementation instead. + +### 1. Initial version. +Deprecated, will be converted to current version upon saving. + +#### Format fields + +| Name | Type | Description | +| -------- | ------ | -------------------------------------------- | +| Key type | string | Currently supported: Cyfral, Dallas, Metakom | +| Data | hex | Key data | -1. Initial version. -### Format fields -| Name | Description | -| -------- | -------------------------------------------- | -| Key type | Currently supported: Cyfral, Dallas, Metakom | -| Data | Key data (HEX values) | diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 549d3812..f306deb8 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,15.0,, +Version,+,16.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 33bca491..f896dd1b 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,15.1,, +Version,+,16.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -162,9 +162,10 @@ Header,+,lib/mlib/m-rbtree.h,, Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, Header,+,lib/nfc/nfc_device.h,, +Header,+,lib/one_wire/ibutton/ibutton_key.h,, +Header,+,lib/one_wire/ibutton/ibutton_protocols.h,, Header,+,lib/one_wire/ibutton/ibutton_worker.h,, Header,+,lib/one_wire/maxim_crc.h,, -Header,+,lib/one_wire/one_wire_device.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_host_timing.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -191,6 +192,7 @@ Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/md5.h,, Header,+,lib/toolbox/path.h,, +Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/random_name.h,, Header,+,lib/toolbox/saved_struct.h,, @@ -874,6 +876,7 @@ Function,-,flipper_application_preload_status_to_string,const char*,FlipperAppli Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* +Function,+,flipper_format_buffered_file_open_always,_Bool,"FlipperFormat*, const char*" Function,+,flipper_format_buffered_file_open_existing,_Bool,"FlipperFormat*, const char*" Function,+,flipper_format_delete_key,_Bool,"FlipperFormat*, const char*" Function,+,flipper_format_file_alloc,FlipperFormat*,Storage* @@ -1597,22 +1600,33 @@ Function,+,hmac_sha256_update,void,"const hmac_sha256_context*, const uint8_t*, Function,-,hypot,double,"double, double" Function,-,hypotf,float,"float, float" Function,-,hypotl,long double,"long double, long double" -Function,+,ibutton_key_alloc,iButtonKey*, -Function,+,ibutton_key_clear_data,void,iButtonKey* -Function,+,ibutton_key_dallas_crc_is_valid,_Bool,iButtonKey* -Function,+,ibutton_key_dallas_is_1990_key,_Bool,iButtonKey* +Function,+,ibutton_key_alloc,iButtonKey*,size_t Function,+,ibutton_key_free,void,iButtonKey* -Function,+,ibutton_key_get_data_p,const uint8_t*,iButtonKey* -Function,+,ibutton_key_get_data_size,uint8_t,iButtonKey* -Function,+,ibutton_key_get_max_size,uint8_t, -Function,+,ibutton_key_get_size_by_type,uint8_t,iButtonKeyType -Function,+,ibutton_key_get_string_by_type,const char*,iButtonKeyType -Function,+,ibutton_key_get_type,iButtonKeyType,iButtonKey* -Function,+,ibutton_key_get_type_by_string,_Bool,"const char*, iButtonKeyType*" -Function,+,ibutton_key_set,void,"iButtonKey*, const iButtonKey*" -Function,+,ibutton_key_set_data,void,"iButtonKey*, uint8_t*, uint8_t" -Function,+,ibutton_key_set_type,void,"iButtonKey*, iButtonKeyType" -Function,+,ibutton_worker_alloc,iButtonWorker*, +Function,+,ibutton_key_get_protocol_id,iButtonProtocolId,const iButtonKey* +Function,+,ibutton_key_reset,void,iButtonKey* +Function,+,ibutton_key_set_protocol_id,void,"iButtonKey*, iButtonProtocolId" +Function,+,ibutton_protocols_alloc,iButtonProtocols*, +Function,+,ibutton_protocols_apply_edits,void,"iButtonProtocols*, const iButtonKey*" +Function,+,ibutton_protocols_emulate_start,void,"iButtonProtocols*, iButtonKey*" +Function,+,ibutton_protocols_emulate_stop,void,"iButtonProtocols*, iButtonKey*" +Function,+,ibutton_protocols_free,void,iButtonProtocols* +Function,+,ibutton_protocols_get_editable_data,void,"iButtonProtocols*, const iButtonKey*, iButtonEditableData*" +Function,+,ibutton_protocols_get_features,uint32_t,"iButtonProtocols*, iButtonProtocolId" +Function,+,ibutton_protocols_get_id_by_name,iButtonProtocolId,"iButtonProtocols*, const char*" +Function,+,ibutton_protocols_get_manufacturer,const char*,"iButtonProtocols*, iButtonProtocolId" +Function,+,ibutton_protocols_get_max_data_size,size_t,iButtonProtocols* +Function,+,ibutton_protocols_get_name,const char*,"iButtonProtocols*, iButtonProtocolId" +Function,+,ibutton_protocols_get_protocol_count,uint32_t, +Function,+,ibutton_protocols_is_valid,_Bool,"iButtonProtocols*, const iButtonKey*" +Function,+,ibutton_protocols_load,_Bool,"iButtonProtocols*, iButtonKey*, const char*" +Function,+,ibutton_protocols_read,_Bool,"iButtonProtocols*, iButtonKey*" +Function,+,ibutton_protocols_render_brief_data,void,"iButtonProtocols*, const iButtonKey*, FuriString*" +Function,+,ibutton_protocols_render_data,void,"iButtonProtocols*, const iButtonKey*, FuriString*" +Function,+,ibutton_protocols_render_error,void,"iButtonProtocols*, const iButtonKey*, FuriString*" +Function,+,ibutton_protocols_save,_Bool,"iButtonProtocols*, const iButtonKey*, const char*" +Function,+,ibutton_protocols_write_blank,_Bool,"iButtonProtocols*, iButtonKey*" +Function,+,ibutton_protocols_write_copy,_Bool,"iButtonProtocols*, iButtonKey*" +Function,+,ibutton_worker_alloc,iButtonWorker*,iButtonProtocols* Function,+,ibutton_worker_emulate_set_callback,void,"iButtonWorker*, iButtonWorkerEmulateCallback, void*" Function,+,ibutton_worker_emulate_start,void,"iButtonWorker*, iButtonKey*" Function,+,ibutton_worker_free,void,iButtonWorker* @@ -1621,8 +1635,9 @@ Function,+,ibutton_worker_read_start,void,"iButtonWorker*, iButtonKey*" Function,+,ibutton_worker_start_thread,void,iButtonWorker* Function,+,ibutton_worker_stop,void,iButtonWorker* Function,+,ibutton_worker_stop_thread,void,iButtonWorker* +Function,+,ibutton_worker_write_blank_start,void,"iButtonWorker*, iButtonKey*" +Function,+,ibutton_worker_write_copy_start,void,"iButtonWorker*, iButtonKey*" Function,+,ibutton_worker_write_set_callback,void,"iButtonWorker*, iButtonWorkerWriteCallback, void*" -Function,+,ibutton_worker_write_start,void,"iButtonWorker*, iButtonKey*" Function,+,icon_animation_alloc,IconAnimation*,const Icon* Function,+,icon_animation_free,void,IconAnimation* Function,+,icon_animation_get_height,uint8_t,const IconAnimation* @@ -2034,12 +2049,6 @@ Function,+,notification_message,void,"NotificationApp*, const NotificationSequen Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" Function,-,nrand48,long,unsigned short[3] Function,-,on_exit,int,"void (*)(int, void*), void*" -Function,+,onewire_device_alloc,OneWireDevice*,"uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" -Function,+,onewire_device_attach,void,"OneWireDevice*, OneWireSlave*" -Function,+,onewire_device_detach,void,OneWireDevice* -Function,+,onewire_device_free,void,OneWireDevice* -Function,+,onewire_device_get_id_p,uint8_t*,OneWireDevice* -Function,+,onewire_device_send_id,void,OneWireDevice* Function,+,onewire_host_alloc,OneWireHost*,const GpioPin* Function,+,onewire_host_free,void,OneWireHost* Function,+,onewire_host_read,uint8_t,OneWireHost* @@ -2054,10 +2063,15 @@ Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" Function,+,onewire_host_write,void,"OneWireHost*, uint8_t" Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool" +Function,+,onewire_host_write_bytes,void,"OneWireHost*, const uint8_t*, uint16_t" Function,+,onewire_slave_alloc,OneWireSlave*,const GpioPin* -Function,+,onewire_slave_attach,void,"OneWireSlave*, OneWireDevice*" -Function,+,onewire_slave_detach,void,OneWireSlave* Function,+,onewire_slave_free,void,OneWireSlave* +Function,+,onewire_slave_receive,_Bool,"OneWireSlave*, uint8_t*, size_t" +Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave* +Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t" +Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" +Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" +Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_start,void,OneWireSlave* Function,+,onewire_slave_stop,void,OneWireSlave* @@ -2105,6 +2119,7 @@ Function,+,power_off,void,Power* Function,+,power_reboot,void,PowerBootMode Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" +Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" Function,-,printf,int,"const char*, ..." Function,-,prng_successor,uint32_t,"uint32_t, uint32_t" Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." diff --git a/lib/flipper_format/flipper_format.c b/lib/flipper_format/flipper_format.c index 292dab5f..bb1aa59f 100644 --- a/lib/flipper_format/flipper_format.c +++ b/lib/flipper_format/flipper_format.c @@ -91,6 +91,12 @@ bool flipper_format_file_open_always(FlipperFormat* flipper_format, const char* return file_stream_open(flipper_format->stream, path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); } +bool flipper_format_buffered_file_open_always(FlipperFormat* flipper_format, const char* path) { + furi_assert(flipper_format); + return buffered_file_stream_open( + flipper_format->stream, path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); +} + bool flipper_format_file_open_new(FlipperFormat* flipper_format, const char* path) { furi_assert(flipper_format); return file_stream_open(flipper_format->stream, path, FSAM_READ_WRITE, FSOM_CREATE_NEW); diff --git a/lib/flipper_format/flipper_format.h b/lib/flipper_format/flipper_format.h index 743918e3..671ff6fa 100644 --- a/lib/flipper_format/flipper_format.h +++ b/lib/flipper_format/flipper_format.h @@ -131,7 +131,7 @@ bool flipper_format_file_open_existing(FlipperFormat* flipper_format, const char /** * Open existing file, buffered mode. - * Use only if FlipperFormat allocated as a file. + * Use only if FlipperFormat allocated as a buffered file. * @param flipper_format Pointer to a FlipperFormat instance * @param path File path * @return True on success @@ -156,6 +156,15 @@ bool flipper_format_file_open_append(FlipperFormat* flipper_format, const char* */ bool flipper_format_file_open_always(FlipperFormat* flipper_format, const char* path); +/** + * Open file. Creates a new file, or deletes the contents of the file if it already exists, buffered mode. + * Use only if FlipperFormat allocated as a buffered file. + * @param flipper_format Pointer to a FlipperFormat instance + * @param path File path + * @return True on success + */ +bool flipper_format_buffered_file_open_always(FlipperFormat* flipper_format, const char* path); + /** * Open file. Creates a new file, fails if file already exists. * Use only if FlipperFormat allocated as a file. diff --git a/lib/one_wire/SConscript b/lib/one_wire/SConscript index 5e06d21e..56d4759e 100644 --- a/lib/one_wire/SConscript +++ b/lib/one_wire/SConscript @@ -11,8 +11,9 @@ env.Append( File("one_wire_host_timing.h"), File("one_wire_host.h"), File("one_wire_slave.h"), - File("one_wire_device.h"), + File("ibutton/ibutton_key.h"), File("ibutton/ibutton_worker.h"), + File("ibutton/ibutton_protocols.h"), File("maxim_crc.h"), ], ) diff --git a/lib/one_wire/ibutton/ibutton_key.c b/lib/one_wire/ibutton/ibutton_key.c index 7b7571a2..926a826a 100644 --- a/lib/one_wire/ibutton/ibutton_key.c +++ b/lib/one_wire/ibutton/ibutton_key.c @@ -1,110 +1,43 @@ -#include -#include -#include "ibutton_key.h" +#include "ibutton_key_i.h" struct iButtonKey { - uint8_t data[IBUTTON_KEY_DATA_SIZE]; - iButtonKeyType type; + iButtonProtocolId protocol_id; + iButtonProtocolData* protocol_data; + size_t protocol_data_size; }; -iButtonKey* ibutton_key_alloc() { +iButtonKey* ibutton_key_alloc(size_t data_size) { iButtonKey* key = malloc(sizeof(iButtonKey)); - memset(key, 0, sizeof(iButtonKey)); + + key->protocol_id = iButtonProtocolIdInvalid; + key->protocol_data = malloc(data_size); + key->protocol_data_size = data_size; + return key; } void ibutton_key_free(iButtonKey* key) { + free(key->protocol_data); free(key); } -void ibutton_key_set(iButtonKey* to, const iButtonKey* from) { - memcpy(to, from, sizeof(iButtonKey)); +void ibutton_key_reset(iButtonKey* key) { + key->protocol_id = iButtonProtocolIdInvalid; + memset(key->protocol_data, 0, key->protocol_data_size); } -void ibutton_key_set_data(iButtonKey* key, uint8_t* data, uint8_t data_count) { - furi_check(data_count > 0); - furi_check(data_count <= IBUTTON_KEY_DATA_SIZE); - - memset(key->data, 0, IBUTTON_KEY_DATA_SIZE); - memcpy(key->data, data, data_count); +iButtonProtocolId ibutton_key_get_protocol_id(const iButtonKey* key) { + return key->protocol_id; } -void ibutton_key_clear_data(iButtonKey* key) { - memset(key->data, 0, IBUTTON_KEY_DATA_SIZE); +void ibutton_key_set_protocol_id(iButtonKey* key, iButtonProtocolId protocol_id) { + key->protocol_id = protocol_id; } -const uint8_t* ibutton_key_get_data_p(iButtonKey* key) { - return key->data; +iButtonProtocolData* ibutton_key_get_protocol_data(const iButtonKey* key) { + return key->protocol_data; } -uint8_t ibutton_key_get_data_size(iButtonKey* key) { - return ibutton_key_get_size_by_type(key->type); -} - -void ibutton_key_set_type(iButtonKey* key, iButtonKeyType key_type) { - key->type = key_type; -} - -iButtonKeyType ibutton_key_get_type(iButtonKey* key) { - return key->type; -} - -const char* ibutton_key_get_string_by_type(iButtonKeyType key_type) { - switch(key_type) { - case iButtonKeyCyfral: - return "Cyfral"; - break; - case iButtonKeyMetakom: - return "Metakom"; - break; - case iButtonKeyDS1990: - return "Dallas"; - break; - default: - furi_crash("Invalid iButton type"); - } -} - -bool ibutton_key_get_type_by_string(const char* type_string, iButtonKeyType* key_type) { - if(strcmp(type_string, ibutton_key_get_string_by_type(iButtonKeyCyfral)) == 0) { - *key_type = iButtonKeyCyfral; - } else if(strcmp(type_string, ibutton_key_get_string_by_type(iButtonKeyMetakom)) == 0) { - *key_type = iButtonKeyMetakom; - } else if(strcmp(type_string, ibutton_key_get_string_by_type(iButtonKeyDS1990)) == 0) { - *key_type = iButtonKeyDS1990; - } else { - return false; - } - - return true; -} - -uint8_t ibutton_key_get_size_by_type(iButtonKeyType key_type) { - uint8_t size = 0; - - switch(key_type) { - case iButtonKeyCyfral: - size = 2; - break; - case iButtonKeyMetakom: - size = 4; - break; - case iButtonKeyDS1990: - size = 8; - break; - } - - return size; -} - -uint8_t ibutton_key_get_max_size() { - return IBUTTON_KEY_DATA_SIZE; -} - -bool ibutton_key_dallas_crc_is_valid(iButtonKey* key) { - return (maxim_crc8(key->data, 8, MAXIM_CRC8_INIT) == 0); -} - -bool ibutton_key_dallas_is_1990_key(iButtonKey* key) { - return (key->data[0] == 0x01); +size_t ibutton_key_get_protocol_data_size(const iButtonKey* key) { + return key->protocol_data_size; } diff --git a/lib/one_wire/ibutton/ibutton_key.h b/lib/one_wire/ibutton/ibutton_key.h index d682555a..1848cd67 100644 --- a/lib/one_wire/ibutton/ibutton_key.h +++ b/lib/one_wire/ibutton/ibutton_key.h @@ -5,127 +5,49 @@ */ #pragma once -#include + +#include + +#include "protocols/protocol_common.h" #ifdef __cplusplus extern "C" { #endif -#define IBUTTON_KEY_DATA_SIZE 8 -#define IBUTTON_KEY_NAME_SIZE 22 - -typedef enum { - iButtonKeyDS1990, - iButtonKeyCyfral, - iButtonKeyMetakom, -} iButtonKeyType; - typedef struct iButtonKey iButtonKey; /** - * Allocate key - * @return iButtonKey* + * Allocate a key object + * @param [in] data_size maximum data size held by the key + * @return pointer to the key object */ -iButtonKey* ibutton_key_alloc(); +iButtonKey* ibutton_key_alloc(size_t data_size); /** - * Free key - * @param key + * Destroy the key object, free resources + * @param [in] key pointer to the key object */ void ibutton_key_free(iButtonKey* key); /** - * Copy key - * @param to - * @param from + * Get the protocol id held by the key + * @param [in] key pointer to the key object + * @return protocol id held by the key */ -void ibutton_key_set(iButtonKey* to, const iButtonKey* from); +iButtonProtocolId ibutton_key_get_protocol_id(const iButtonKey* key); /** - * Set key data - * @param key - * @param data - * @param data_count + * Set the protocol id held by the key + * @param [in] key pointer to the key object + * @param [in] protocol_id new protocol id */ -void ibutton_key_set_data(iButtonKey* key, uint8_t* data, uint8_t data_count); +void ibutton_key_set_protocol_id(iButtonKey* key, iButtonProtocolId protocol_id); /** - * Clear key data - * @param key + * Reset the protocol id and data held by the key + * @param [in] key pointer to the key object */ -void ibutton_key_clear_data(iButtonKey* key); - -/** - * Get pointer to key data - * @param key - * @return const uint8_t* - */ -const uint8_t* ibutton_key_get_data_p(iButtonKey* key); - -/** - * Get key data size - * @param key - * @return uint8_t - */ -uint8_t ibutton_key_get_data_size(iButtonKey* key); - -/** - * Set key type - * @param key - * @param key_type - */ -void ibutton_key_set_type(iButtonKey* key, iButtonKeyType key_type); - -/** - * Get key type - * @param key - * @return iButtonKeyType - */ -iButtonKeyType ibutton_key_get_type(iButtonKey* key); - -/** - * Get type string from key type - * @param key_type - * @return const char* - */ -const char* ibutton_key_get_string_by_type(iButtonKeyType key_type); - -/** - * Get key type from string - * @param type_string - * @param key_type - * @return bool - */ -bool ibutton_key_get_type_by_string(const char* type_string, iButtonKeyType* key_type); - -/** - * Get key data size from type - * @param key_type - * @return uint8_t - */ -uint8_t ibutton_key_get_size_by_type(iButtonKeyType key_type); - -/** - * Get max key size - * @return uint8_t - */ -uint8_t ibutton_key_get_max_size(); - -/** - * Check if CRC for onewire key is valid - * @param key - * @return true - * @return false - */ -bool ibutton_key_dallas_crc_is_valid(iButtonKey* key); - -/** - * Check if onewire key is a DS1990 key - * @param key - * @return true - * @return false - */ -bool ibutton_key_dallas_is_1990_key(iButtonKey* key); +void ibutton_key_reset(iButtonKey* key); #ifdef __cplusplus } diff --git a/lib/one_wire/ibutton/ibutton_key_command.h b/lib/one_wire/ibutton/ibutton_key_command.h deleted file mode 100644 index 88049d06..00000000 --- a/lib/one_wire/ibutton/ibutton_key_command.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file ibutton_key_command.h - * - * List of misc commands for Dallas and blanks - */ - -#pragma once - -#define RW1990_1_CMD_WRITE_RECORD_FLAG 0xD1 -#define RW1990_1_CMD_READ_RECORD_FLAG 0xB5 -#define RW1990_1_CMD_WRITE_ROM 0xD5 - -#define RW1990_2_CMD_WRITE_RECORD_FLAG 0x1D -#define RW1990_2_CMD_READ_RECORD_FLAG 0x1E -#define RW1990_2_CMD_WRITE_ROM 0xD5 - -#define TM2004_CMD_READ_STATUS 0xAA -#define TM2004_CMD_READ_MEMORY 0xF0 -#define TM2004_CMD_WRITE_ROM 0x3C -#define TM2004_CMD_FINALIZATION 0x35 -#define TM2004_ANSWER_READ_MEMORY 0xF5 - -#define TM01_CMD_WRITE_RECORD_FLAG 0xC1 -#define TM01_CMD_WRITE_ROM 0xC5 -#define TM01_CMD_SWITCH_TO_CYFRAL 0xCA -#define TM01_CMD_SWITCH_TO_METAKOM 0xCB - -#define DS1990_CMD_READ_ROM 0x33 diff --git a/lib/one_wire/ibutton/ibutton_key_i.h b/lib/one_wire/ibutton/ibutton_key_i.h new file mode 100644 index 00000000..b527c65b --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_key_i.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ibutton_key.h" + +#include "protocols/protocol_common_i.h" + +iButtonProtocolData* ibutton_key_get_protocol_data(const iButtonKey* key); + +size_t ibutton_key_get_protocol_data_size(const iButtonKey* key); diff --git a/lib/one_wire/ibutton/ibutton_protocols.c b/lib/one_wire/ibutton/ibutton_protocols.c new file mode 100644 index 00000000..75aa225e --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_protocols.c @@ -0,0 +1,309 @@ +#include "ibutton_protocols.h" + +#include + +#include "ibutton_key_i.h" + +#include "protocols/protocol_group_defs.h" + +#define IBUTTON_FILE_TYPE "Flipper iButton key" + +#define IBUTTON_PROTOCOL_KEY_V1 "Key type" +#define IBUTTON_PROTOCOL_KEY_V2 "Protocol" + +#define IBUTTON_CURRENT_FORMAT_VERSION 2U + +#define GET_PROTOCOL_GROUP(id) \ + iButtonProtocolGroupInfo info; \ + ibutton_protocols_get_group_by_id(protocols, (id), &info); + +#define GROUP_BASE (info.base) +#define GROUP_DATA (info.group) +#define PROTOCOL_ID (info.id) + +struct iButtonProtocols { + iButtonProtocolGroupData** group_datas; +}; + +typedef struct { + const iButtonProtocolGroupBase* base; + iButtonProtocolGroupData* group; + iButtonProtocolLocalId id; +} iButtonProtocolGroupInfo; + +static void ibutton_protocols_get_group_by_id( + iButtonProtocols* protocols, + iButtonProtocolId id, + iButtonProtocolGroupInfo* info) { + iButtonProtocolLocalId local_id = id; + + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + if(local_id < (signed)ibutton_protocol_groups[i]->protocol_count) { + info->base = ibutton_protocol_groups[i]; + info->group = protocols->group_datas[i]; + info->id = local_id; + return; + + } else { + local_id -= ibutton_protocol_groups[i]->protocol_count; + } + } + furi_crash(NULL); +} + +iButtonProtocols* ibutton_protocols_alloc() { + iButtonProtocols* protocols = malloc(sizeof(iButtonProtocols*)); + + protocols->group_datas = malloc(sizeof(iButtonProtocolGroupData*) * iButtonProtocolGroupMax); + + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + protocols->group_datas[i] = ibutton_protocol_groups[i]->alloc(); + } + + return protocols; +} + +void ibutton_protocols_free(iButtonProtocols* protocols) { + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + ibutton_protocol_groups[i]->free(protocols->group_datas[i]); + } + + free(protocols->group_datas); + free(protocols); +} + +uint32_t ibutton_protocols_get_protocol_count() { + uint32_t count = 0; + + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + count += ibutton_protocol_groups[i]->protocol_count; + } + + return count; +} + +iButtonProtocolId ibutton_protocols_get_id_by_name(iButtonProtocols* protocols, const char* name) { + iButtonProtocolLocalId offset = 0; + + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + iButtonProtocolLocalId local_id; + if(ibutton_protocol_groups[i]->get_id_by_name(protocols->group_datas[i], &local_id, name)) { + return local_id + offset; + } + offset += ibutton_protocol_groups[i]->protocol_count; + } + return iButtonProtocolIdInvalid; +} + +uint32_t ibutton_protocols_get_features(iButtonProtocols* protocols, iButtonProtocolId id) { + GET_PROTOCOL_GROUP(id); + return GROUP_BASE->get_features(GROUP_DATA, PROTOCOL_ID); +} + +size_t ibutton_protocols_get_max_data_size(iButtonProtocols* protocols) { + size_t max_size = 0; + + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + const size_t current_max_size = + ibutton_protocol_groups[i]->get_max_data_size(protocols->group_datas[i]); + if(current_max_size > max_size) { + max_size = current_max_size; + } + } + + return max_size; +} + +const char* ibutton_protocols_get_manufacturer(iButtonProtocols* protocols, iButtonProtocolId id) { + GET_PROTOCOL_GROUP(id); + return GROUP_BASE->get_manufacturer(GROUP_DATA, PROTOCOL_ID); +} + +const char* ibutton_protocols_get_name(iButtonProtocols* protocols, iButtonProtocolId id) { + GET_PROTOCOL_GROUP(id); + return GROUP_BASE->get_name(GROUP_DATA, PROTOCOL_ID); +} + +bool ibutton_protocols_read(iButtonProtocols* protocols, iButtonKey* key) { + iButtonProtocolLocalId id = iButtonProtocolIdInvalid; + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + iButtonProtocolLocalId offset = 0; + for(iButtonProtocolGroupId i = 0; i < iButtonProtocolGroupMax; ++i) { + if(ibutton_protocol_groups[i]->read(protocols->group_datas[i], data, &id)) { + id += offset; + break; + } + offset += ibutton_protocol_groups[i]->protocol_count; + } + + ibutton_key_set_protocol_id(key, id); + return id != iButtonProtocolIdInvalid; +} + +bool ibutton_protocols_write_blank(iButtonProtocols* protocols, iButtonKey* key) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + return GROUP_BASE->write_blank(GROUP_DATA, data, PROTOCOL_ID); +} + +bool ibutton_protocols_write_copy(iButtonProtocols* protocols, iButtonKey* key) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + return GROUP_BASE->write_copy(GROUP_DATA, data, PROTOCOL_ID); +} + +void ibutton_protocols_emulate_start(iButtonProtocols* protocols, iButtonKey* key) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->emulate_start(GROUP_DATA, data, PROTOCOL_ID); +} + +void ibutton_protocols_emulate_stop(iButtonProtocols* protocols, iButtonKey* key) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->emulate_stop(GROUP_DATA, data, PROTOCOL_ID); +} + +bool ibutton_protocols_save( + iButtonProtocols* protocols, + const iButtonKey* key, + const char* file_name) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + const iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + bool success = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + + do { + const char* protocol_name = ibutton_protocols_get_name(protocols, id); + + if(!flipper_format_buffered_file_open_always(ff, file_name)) break; + + if(!flipper_format_write_header_cstr(ff, IBUTTON_FILE_TYPE, IBUTTON_CURRENT_FORMAT_VERSION)) + break; + if(!flipper_format_write_string_cstr(ff, IBUTTON_PROTOCOL_KEY_V2, protocol_name)) break; + + GET_PROTOCOL_GROUP(id); + if(!GROUP_BASE->save(GROUP_DATA, data, PROTOCOL_ID, ff)) break; + + success = true; + } while(false); + + flipper_format_free(ff); + furi_record_close(RECORD_STORAGE); + + return success; +} + +bool ibutton_protocols_load(iButtonProtocols* protocols, iButtonKey* key, const char* file_name) { + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + bool success = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + FuriString* tmp = furi_string_alloc(); + + do { + if(!flipper_format_buffered_file_open_existing(ff, file_name)) break; + + uint32_t version; + + if(!flipper_format_read_header(ff, tmp, &version)) break; + if(!furi_string_equal(tmp, IBUTTON_FILE_TYPE)) break; + + if(version == 1) { + if(!flipper_format_read_string(ff, IBUTTON_PROTOCOL_KEY_V1, tmp)) break; + } else if(version == 2) { + if(!flipper_format_read_string(ff, IBUTTON_PROTOCOL_KEY_V2, tmp)) break; + } else { + break; + } + + const iButtonProtocolId id = + ibutton_protocols_get_id_by_name(protocols, furi_string_get_cstr(tmp)); + ibutton_key_set_protocol_id(key, id); + + GET_PROTOCOL_GROUP(id); + if(!GROUP_BASE->load(GROUP_DATA, data, PROTOCOL_ID, version, ff)) break; + + success = true; + } while(false); + + flipper_format_free(ff); + furi_string_free(tmp); + furi_record_close(RECORD_STORAGE); + + return success; +} + +void ibutton_protocols_render_data( + iButtonProtocols* protocols, + const iButtonKey* key, + FuriString* result) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + const iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->render_data(GROUP_DATA, data, PROTOCOL_ID, result); +} + +void ibutton_protocols_render_brief_data( + iButtonProtocols* protocols, + const iButtonKey* key, + FuriString* result) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + const iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->render_brief_data(GROUP_DATA, data, PROTOCOL_ID, result); +} + +void ibutton_protocols_render_error( + iButtonProtocols* protocols, + const iButtonKey* key, + FuriString* result) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + const iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->render_error(GROUP_DATA, data, PROTOCOL_ID, result); +} + +bool ibutton_protocols_is_valid(iButtonProtocols* protocols, const iButtonKey* key) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + const iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + return GROUP_BASE->is_valid(GROUP_DATA, data, PROTOCOL_ID); +} + +void ibutton_protocols_get_editable_data( + iButtonProtocols* protocols, + const iButtonKey* key, + iButtonEditableData* editable) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->get_editable_data(GROUP_DATA, data, PROTOCOL_ID, editable); +} + +void ibutton_protocols_apply_edits(iButtonProtocols* protocols, const iButtonKey* key) { + const iButtonProtocolId id = ibutton_key_get_protocol_id(key); + iButtonProtocolData* data = ibutton_key_get_protocol_data(key); + + GET_PROTOCOL_GROUP(id); + GROUP_BASE->apply_edits(GROUP_DATA, data, PROTOCOL_ID); +} diff --git a/lib/one_wire/ibutton/ibutton_protocols.h b/lib/one_wire/ibutton/ibutton_protocols.h new file mode 100644 index 00000000..0e7ed0a8 --- /dev/null +++ b/lib/one_wire/ibutton/ibutton_protocols.h @@ -0,0 +1,197 @@ +/** + * @file ibutton_protocols.h + * + * Common interface for accessing various iButton protocols + */ + +#pragma once + +#include +#include + +#include "protocols/protocol_common.h" + +#include "ibutton_key.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct iButtonProtocols iButtonProtocols; + +/** + * Allocate an iButtonProtocols object + * @return pointer to an iButtonProtocols object + */ +iButtonProtocols* ibutton_protocols_alloc(); + +/** + * Destroy an iButtonProtocols object, free resources + * @param [in] protocols pointer to an iButtonProtocols object + */ +void ibutton_protocols_free(iButtonProtocols* protocols); + +/** + * Get the total number of available protocols + */ +uint32_t ibutton_protocols_get_protocol_count(); + +/** + * Get maximum data size out of all protocols available + * @param [in] protocols pointer to an iButtonProtocols object + * @return maximum data size in bytes + */ +size_t ibutton_protocols_get_max_data_size(iButtonProtocols* protocols); + +/** + * Get the protocol id based on its name + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] name pointer to a string containing the name + * @return protocol id on success on iButtonProtocolIdInvalid on failure + */ +iButtonProtocolId ibutton_protocols_get_id_by_name(iButtonProtocols* protocols, const char* name); + +/** + * Get the manufacturer name based on the protocol id + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] id id of the protocol in question + * @return pointer to a statically allocated string with manufacturer name + */ +const char* ibutton_protocols_get_manufacturer(iButtonProtocols* protocols, iButtonProtocolId id); + +/** + * Get the protocol name based on the protocol id + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] id id of the protocol in question + * @return pointer to a statically allocated string with protocol name + */ +const char* ibutton_protocols_get_name(iButtonProtocols* protocols, iButtonProtocolId id); + +/** + * Get protocol features bitmask by protocol id + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] id id of the protocol in question + */ +uint32_t ibutton_protocols_get_features(iButtonProtocols* protocols, iButtonProtocolId id); + +/** + * Read a physical device (a key or an emulator) + * @param [in] protocols pointer to an iButtonProtocols object + * @param [out] key pointer to the key to read into (must be allocated before) + * @return true on success, false on failure + */ +bool ibutton_protocols_read(iButtonProtocols* protocols, iButtonKey* key); + +/** + * Write the key to a blank + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be written + * @return true on success, false on failure + */ +bool ibutton_protocols_write_blank(iButtonProtocols* protocols, iButtonKey* key); + +/** + * Write the key to another one of the same type + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be written + * @return true on success, false on failure + */ +bool ibutton_protocols_write_copy(iButtonProtocols* protocols, iButtonKey* key); + +/** + * Start emulating the key + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be emulated + */ +void ibutton_protocols_emulate_start(iButtonProtocols* protocols, iButtonKey* key); + +/** + * Stop emulating the key + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be emulated + */ +void ibutton_protocols_emulate_stop(iButtonProtocols* protocols, iButtonKey* key); + +/** + * Save the key data to a file. + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be saved + * @param [in] file_name full absolute path to the file name + * @return true on success, false on failure + */ +bool ibutton_protocols_save( + iButtonProtocols* protocols, + const iButtonKey* key, + const char* file_name); + +/** + * Load the key from a file. + * @param [in] protocols pointer to an iButtonProtocols object + * @param [out] key pointer to the key to load into (must be allocated before) + * @param [in] file_name full absolute path to the file name + * @return true on success, false on failure + */ +bool ibutton_protocols_load(iButtonProtocols* protocols, iButtonKey* key, const char* file_name); + +/** + * Format a string containing device full data + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be rendered + * @param [out] result pointer to the FuriString instance (must be initialized) + */ +void ibutton_protocols_render_data( + iButtonProtocols* protocols, + const iButtonKey* key, + FuriString* result); + +/** + * Format a string containing device brief data + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be rendered + * @param [out] result pointer to the FuriString instance (must be initialized) + */ +void ibutton_protocols_render_brief_data( + iButtonProtocols* protocols, + const iButtonKey* key, + FuriString* result); + +/** + * Format a string containing error message (for invalid keys) + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be rendered + * @param [out] result pointer to the FuriString instance (must be initialized) + */ +void ibutton_protocols_render_error( + iButtonProtocols* protocols, + const iButtonKey* key, + FuriString* result); + +/** + * Check whether the key data is valid + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be checked + * @return true if data is valid, false otherwise + */ +bool ibutton_protocols_is_valid(iButtonProtocols* protocols, const iButtonKey* key); + +/** + * Get a pointer to the key's editable data (for in-place editing) + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in] key pointer to the key to be checked + * @param [out] editable pointer to a structure to contain the editable data + */ +void ibutton_protocols_get_editable_data( + iButtonProtocols* protocols, + const iButtonKey* key, + iButtonEditableData* editable); + +/** + * Make all necessary internal adjustments after editing the key + * @param [in] protocols pointer to an iButtonProtocols object + * @param [in,out] key pointer to the key to be adjusted + */ +void ibutton_protocols_apply_edits(iButtonProtocols* protocols, const iButtonKey* key); + +#ifdef __cplusplus +} +#endif diff --git a/lib/one_wire/ibutton/ibutton_worker.c b/lib/one_wire/ibutton/ibutton_worker.c index 1fe39b5e..d40dba71 100644 --- a/lib/one_wire/ibutton/ibutton_worker.c +++ b/lib/one_wire/ibutton/ibutton_worker.c @@ -1,13 +1,14 @@ -#include -#include -#include #include "ibutton_worker_i.h" +#include "ibutton_protocols.h" + +#include typedef enum { iButtonMessageEnd, iButtonMessageStop, iButtonMessageRead, - iButtonMessageWrite, + iButtonMessageWriteBlank, + iButtonMessageWriteCopy, iButtonMessageEmulate, iButtonMessageNotifyEmulate, } iButtonMessageType; @@ -21,26 +22,15 @@ typedef struct { static int32_t ibutton_worker_thread(void* thread_context); -iButtonWorker* ibutton_worker_alloc() { +iButtonWorker* ibutton_worker_alloc(iButtonProtocols* protocols) { iButtonWorker* worker = malloc(sizeof(iButtonWorker)); - worker->key_p = NULL; - worker->key_data = malloc(ibutton_key_get_max_size()); - worker->host = onewire_host_alloc(&ibutton_gpio); - worker->slave = onewire_slave_alloc(&ibutton_gpio); - worker->writer = ibutton_writer_alloc(worker->host); - worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0); + + worker->protocols = protocols; worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage)); - worker->mode_index = iButtonWorkerIdle; - worker->read_cb = NULL; - worker->write_cb = NULL; - worker->emulate_cb = NULL; - worker->cb_ctx = NULL; - + worker->mode_index = iButtonWorkerModeIdle; worker->thread = furi_thread_alloc_ex("iButtonWorker", 2048, ibutton_worker_thread, worker); - worker->protocols = protocol_dict_alloc(ibutton_protocols, iButtonProtocolMax); - return worker; } @@ -48,7 +38,7 @@ void ibutton_worker_read_set_callback( iButtonWorker* worker, iButtonWorkerReadCallback callback, void* context) { - furi_check(worker->mode_index == iButtonWorkerIdle); + furi_check(worker->mode_index == iButtonWorkerModeIdle); worker->read_cb = callback; worker->cb_ctx = context; } @@ -57,7 +47,7 @@ void ibutton_worker_write_set_callback( iButtonWorker* worker, iButtonWorkerWriteCallback callback, void* context) { - furi_check(worker->mode_index == iButtonWorkerIdle); + furi_check(worker->mode_index == iButtonWorkerModeIdle); worker->write_cb = callback; worker->cb_ctx = context; } @@ -66,7 +56,7 @@ void ibutton_worker_emulate_set_callback( iButtonWorker* worker, iButtonWorkerEmulateCallback callback, void* context) { - furi_check(worker->mode_index == iButtonWorkerIdle); + furi_check(worker->mode_index == iButtonWorkerModeIdle); worker->emulate_cb = callback; worker->cb_ctx = context; } @@ -77,8 +67,14 @@ void ibutton_worker_read_start(iButtonWorker* worker, iButtonKey* key) { furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk); } -void ibutton_worker_write_start(iButtonWorker* worker, iButtonKey* key) { - iButtonMessage message = {.type = iButtonMessageWrite, .data.key = key}; +void ibutton_worker_write_blank_start(iButtonWorker* worker, iButtonKey* key) { + iButtonMessage message = {.type = iButtonMessageWriteBlank, .data.key = key}; + furi_check( + furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk); +} + +void ibutton_worker_write_copy_start(iButtonWorker* worker, iButtonKey* key) { + iButtonMessage message = {.type = iButtonMessageWriteCopy, .data.key = key}; furi_check( furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk); } @@ -96,19 +92,8 @@ void ibutton_worker_stop(iButtonWorker* worker) { } void ibutton_worker_free(iButtonWorker* worker) { - ibutton_writer_free(worker->writer); - - onewire_slave_free(worker->slave); - - onewire_host_free(worker->host); - onewire_device_free(worker->device); - - protocol_dict_free(worker->protocols); - furi_message_queue_free(worker->messages); - furi_thread_free(worker->thread); - free(worker->key_data); free(worker); } @@ -137,7 +122,7 @@ void ibutton_worker_notify_emulate(iButtonWorker* worker) { } void ibutton_worker_set_key_p(iButtonWorker* worker, iButtonKey* key) { - worker->key_p = key; + worker->key = key; } static int32_t ibutton_worker_thread(void* thread_context) { @@ -154,25 +139,29 @@ static int32_t ibutton_worker_thread(void* thread_context) { if(status == FuriStatusOk) { switch(message.type) { case iButtonMessageEnd: - ibutton_worker_switch_mode(worker, iButtonWorkerIdle); + ibutton_worker_switch_mode(worker, iButtonWorkerModeIdle); ibutton_worker_set_key_p(worker, NULL); running = false; break; case iButtonMessageStop: - ibutton_worker_switch_mode(worker, iButtonWorkerIdle); + ibutton_worker_switch_mode(worker, iButtonWorkerModeIdle); ibutton_worker_set_key_p(worker, NULL); break; case iButtonMessageRead: ibutton_worker_set_key_p(worker, message.data.key); - ibutton_worker_switch_mode(worker, iButtonWorkerRead); + ibutton_worker_switch_mode(worker, iButtonWorkerModeRead); break; - case iButtonMessageWrite: + case iButtonMessageWriteBlank: ibutton_worker_set_key_p(worker, message.data.key); - ibutton_worker_switch_mode(worker, iButtonWorkerWrite); + ibutton_worker_switch_mode(worker, iButtonWorkerModeWriteBlank); + break; + case iButtonMessageWriteCopy: + ibutton_worker_set_key_p(worker, message.data.key); + ibutton_worker_switch_mode(worker, iButtonWorkerModeWriteCopy); break; case iButtonMessageEmulate: ibutton_worker_set_key_p(worker, message.data.key); - ibutton_worker_switch_mode(worker, iButtonWorkerEmulate); + ibutton_worker_switch_mode(worker, iButtonWorkerModeEmulate); break; case iButtonMessageNotifyEmulate: if(worker->emulate_cb) { diff --git a/lib/one_wire/ibutton/ibutton_worker.h b/lib/one_wire/ibutton/ibutton_worker.h index 5c8b1fc3..2a12a319 100644 --- a/lib/one_wire/ibutton/ibutton_worker.h +++ b/lib/one_wire/ibutton/ibutton_worker.h @@ -5,7 +5,9 @@ */ #pragma once + #include "ibutton_key.h" +#include "ibutton_protocols.h" #ifdef __cplusplus extern "C" { @@ -28,7 +30,7 @@ typedef struct iButtonWorker iButtonWorker; * Allocate ibutton worker * @return iButtonWorker* */ -iButtonWorker* ibutton_worker_alloc(); +iButtonWorker* ibutton_worker_alloc(iButtonProtocols* protocols); /** * Free ibutton worker @@ -78,11 +80,18 @@ void ibutton_worker_write_set_callback( void* context); /** - * Start write mode + * Start write blank mode * @param worker * @param key */ -void ibutton_worker_write_start(iButtonWorker* worker, iButtonKey* key); +void ibutton_worker_write_blank_start(iButtonWorker* worker, iButtonKey* key); + +/** + * Start write copy mode + * @param worker + * @param key + */ +void ibutton_worker_write_copy_start(iButtonWorker* worker, iButtonKey* key); /** * Set "emulate success" callback diff --git a/lib/one_wire/ibutton/ibutton_worker_i.h b/lib/one_wire/ibutton/ibutton_worker_i.h index 2396fbd6..5f259a38 100644 --- a/lib/one_wire/ibutton/ibutton_worker_i.h +++ b/lib/one_wire/ibutton/ibutton_worker_i.h @@ -5,13 +5,11 @@ */ #pragma once + +#include +#include + #include "ibutton_worker.h" -#include "ibutton_writer.h" -#include "../one_wire_host.h" -#include "../one_wire_slave.h" -#include "../one_wire_device.h" -#include -#include "protocols/ibutton_protocols.h" #ifdef __cplusplus extern "C" { @@ -25,19 +23,16 @@ typedef struct { } iButtonWorkerModeType; typedef enum { - iButtonWorkerIdle = 0, - iButtonWorkerRead = 1, - iButtonWorkerWrite = 2, - iButtonWorkerEmulate = 3, + iButtonWorkerModeIdle, + iButtonWorkerModeRead, + iButtonWorkerModeWriteBlank, + iButtonWorkerModeWriteCopy, + iButtonWorkerModeEmulate, } iButtonWorkerMode; struct iButtonWorker { - iButtonKey* key_p; - uint8_t* key_data; - OneWireHost* host; - OneWireSlave* slave; - OneWireDevice* device; - iButtonWriter* writer; + iButtonKey* key; + iButtonProtocols* protocols; iButtonWorkerMode mode_index; FuriMessageQueue* messages; FuriThread* thread; @@ -45,10 +40,8 @@ struct iButtonWorker { iButtonWorkerReadCallback read_cb; iButtonWorkerWriteCallback write_cb; iButtonWorkerEmulateCallback emulate_cb; - void* cb_ctx; - ProtocolDict* protocols; - iButtonProtocol protocol_to_encode; + void* cb_ctx; }; extern const iButtonWorkerModeType ibutton_worker_modes[]; diff --git a/lib/one_wire/ibutton/ibutton_worker_modes.c b/lib/one_wire/ibutton/ibutton_worker_modes.c index 4f7f0855..1b8e0a3b 100644 --- a/lib/one_wire/ibutton/ibutton_worker_modes.c +++ b/lib/one_wire/ibutton/ibutton_worker_modes.c @@ -1,23 +1,28 @@ -#include -#include #include "ibutton_worker_i.h" -#include "ibutton_key_command.h" -void ibutton_worker_mode_idle_start(iButtonWorker* worker); -void ibutton_worker_mode_idle_tick(iButtonWorker* worker); -void ibutton_worker_mode_idle_stop(iButtonWorker* worker); +#include -void ibutton_worker_mode_emulate_start(iButtonWorker* worker); -void ibutton_worker_mode_emulate_tick(iButtonWorker* worker); -void ibutton_worker_mode_emulate_stop(iButtonWorker* worker); +#include +#include -void ibutton_worker_mode_read_start(iButtonWorker* worker); -void ibutton_worker_mode_read_tick(iButtonWorker* worker); -void ibutton_worker_mode_read_stop(iButtonWorker* worker); +#include "ibutton_protocols.h" -void ibutton_worker_mode_write_start(iButtonWorker* worker); -void ibutton_worker_mode_write_tick(iButtonWorker* worker); -void ibutton_worker_mode_write_stop(iButtonWorker* worker); +static void ibutton_worker_mode_idle_start(iButtonWorker* worker); +static void ibutton_worker_mode_idle_tick(iButtonWorker* worker); +static void ibutton_worker_mode_idle_stop(iButtonWorker* worker); + +static void ibutton_worker_mode_emulate_start(iButtonWorker* worker); +static void ibutton_worker_mode_emulate_tick(iButtonWorker* worker); +static void ibutton_worker_mode_emulate_stop(iButtonWorker* worker); + +static void ibutton_worker_mode_read_start(iButtonWorker* worker); +static void ibutton_worker_mode_read_tick(iButtonWorker* worker); +static void ibutton_worker_mode_read_stop(iButtonWorker* worker); + +static void ibutton_worker_mode_write_common_start(iButtonWorker* worker); +static void ibutton_worker_mode_write_blank_tick(iButtonWorker* worker); +static void ibutton_worker_mode_write_copy_tick(iButtonWorker* worker); +static void ibutton_worker_mode_write_common_stop(iButtonWorker* worker); const iButtonWorkerModeType ibutton_worker_modes[] = { { @@ -34,9 +39,15 @@ const iButtonWorkerModeType ibutton_worker_modes[] = { }, { .quant = 1000, - .start = ibutton_worker_mode_write_start, - .tick = ibutton_worker_mode_write_tick, - .stop = ibutton_worker_mode_write_stop, + .start = ibutton_worker_mode_write_common_start, + .tick = ibutton_worker_mode_write_blank_tick, + .stop = ibutton_worker_mode_write_common_stop, + }, + { + .quant = 1000, + .start = ibutton_worker_mode_write_common_start, + .tick = ibutton_worker_mode_write_copy_tick, + .stop = ibutton_worker_mode_write_common_stop, }, { .quant = 1000, @@ -62,143 +73,18 @@ void ibutton_worker_mode_idle_stop(iButtonWorker* worker) { /*********************** READ ***********************/ -typedef struct { - uint32_t last_dwt_value; - FuriStreamBuffer* stream; -} iButtonReadContext; - -void ibutton_worker_comparator_callback(bool level, void* context) { - iButtonReadContext* read_context = context; - - uint32_t current_dwt_value = DWT->CYCCNT; - - LevelDuration data = - level_duration_make(level, current_dwt_value - read_context->last_dwt_value); - furi_stream_buffer_send(read_context->stream, &data, sizeof(LevelDuration), 0); - - read_context->last_dwt_value = current_dwt_value; -} - -bool ibutton_worker_read_comparator(iButtonWorker* worker) { - bool result = false; - - protocol_dict_decoders_start(worker->protocols); - - furi_hal_rfid_pins_reset(); - // pulldown pull pin, we sense the signal through the analog part of the RFID schematic - furi_hal_rfid_pin_pull_pulldown(); - - iButtonReadContext read_context = { - .last_dwt_value = DWT->CYCCNT, - .stream = furi_stream_buffer_alloc(sizeof(LevelDuration) * 512, 1), - }; - - furi_hal_rfid_comp_set_callback(ibutton_worker_comparator_callback, &read_context); - furi_hal_rfid_comp_start(); - - uint32_t tick_start = furi_get_tick(); - while(true) { - LevelDuration level; - size_t ret = - furi_stream_buffer_receive(read_context.stream, &level, sizeof(LevelDuration), 100); - - if((furi_get_tick() - tick_start) > 100) { - break; - } - - if(ret > 0) { - ProtocolId decoded_index = protocol_dict_decoders_feed( - worker->protocols, - level_duration_get_level(level), - level_duration_get_duration(level)); - - if(decoded_index == PROTOCOL_NO) continue; - - protocol_dict_get_data( - worker->protocols, decoded_index, worker->key_data, ibutton_key_get_max_size()); - - switch(decoded_index) { - case iButtonProtocolCyfral: - furi_check(worker->key_p != NULL); - ibutton_key_set_type(worker->key_p, iButtonKeyCyfral); - ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); - result = true; - break; - case iButtonProtocolMetakom: - furi_check(worker->key_p != NULL); - ibutton_key_set_type(worker->key_p, iButtonKeyMetakom); - ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); - result = true; - break; - default: - break; - } - } - } - - furi_hal_rfid_comp_stop(); - furi_hal_rfid_comp_set_callback(NULL, NULL); - furi_hal_rfid_pins_reset(); - - furi_stream_buffer_free(read_context.stream); - - return result; -} - -bool ibutton_worker_read_dallas(iButtonWorker* worker) { - bool result = false; - onewire_host_start(worker->host); - furi_delay_ms(100); - FURI_CRITICAL_ENTER(); - if(onewire_host_search(worker->host, worker->key_data, NORMAL_SEARCH)) { - onewire_host_reset_search(worker->host); - - // key found, verify - if(onewire_host_reset(worker->host)) { - onewire_host_write(worker->host, DS1990_CMD_READ_ROM); - bool key_valid = true; - for(uint8_t i = 0; i < ibutton_key_get_max_size(); i++) { - if(onewire_host_read(worker->host) != worker->key_data[i]) { - key_valid = false; - break; - } - } - - if(key_valid) { - result = true; - - furi_check(worker->key_p != NULL); - ibutton_key_set_type(worker->key_p, iButtonKeyDS1990); - ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size()); - } - } - } else { - onewire_host_reset_search(worker->host); - } - onewire_host_stop(worker->host); - FURI_CRITICAL_EXIT(); - return result; -} - void ibutton_worker_mode_read_start(iButtonWorker* worker) { UNUSED(worker); furi_hal_power_enable_otg(); } void ibutton_worker_mode_read_tick(iButtonWorker* worker) { - bool valid = false; - if(ibutton_worker_read_dallas(worker)) { - valid = true; - } else if(ibutton_worker_read_comparator(worker)) { - valid = true; - } - - if(valid) { + if(ibutton_protocols_read(worker->protocols, worker->key)) { if(worker->read_cb != NULL) { worker->read_cb(worker->cb_ctx); } - ibutton_worker_switch_mode(worker, iButtonWorkerIdle); + ibutton_worker_switch_mode(worker, iButtonWorkerModeIdle); } } @@ -208,83 +94,14 @@ void ibutton_worker_mode_read_stop(iButtonWorker* worker) { } /*********************** EMULATE ***********************/ -static void onewire_slave_callback(void* context) { - furi_assert(context); - iButtonWorker* worker = context; - ibutton_worker_notify_emulate(worker); -} - -void ibutton_worker_emulate_dallas_start(iButtonWorker* worker) { - uint8_t* device_id = onewire_device_get_id_p(worker->device); - const uint8_t* key_id = ibutton_key_get_data_p(worker->key_p); - const uint8_t key_size = ibutton_key_get_max_size(); - memcpy(device_id, key_id, key_size); - - onewire_slave_attach(worker->slave, worker->device); - onewire_slave_set_result_callback(worker->slave, onewire_slave_callback, worker); - onewire_slave_start(worker->slave); -} - -void ibutton_worker_emulate_dallas_stop(iButtonWorker* worker) { - onewire_slave_stop(worker->slave); - onewire_slave_detach(worker->slave); -} - -void ibutton_worker_emulate_timer_cb(void* context) { - furi_assert(context); - iButtonWorker* worker = context; - - const LevelDuration level_duration = - protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode); - - furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level_duration)); - furi_hal_ibutton_pin_write(level_duration_get_level(level_duration)); -} - -void ibutton_worker_emulate_timer_start(iButtonWorker* worker) { - furi_assert(worker->key_p); - const uint8_t* key_id = ibutton_key_get_data_p(worker->key_p); - const uint8_t key_size = ibutton_key_get_max_size(); - - switch(ibutton_key_get_type(worker->key_p)) { - case iButtonKeyDS1990: - return; - break; - case iButtonKeyCyfral: - worker->protocol_to_encode = iButtonProtocolCyfral; - break; - case iButtonKeyMetakom: - worker->protocol_to_encode = iButtonProtocolMetakom; - break; - } - - protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size); - protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode); - - furi_hal_ibutton_pin_configure(); - furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker); -} - -void ibutton_worker_emulate_timer_stop(iButtonWorker* worker) { - UNUSED(worker); - furi_hal_ibutton_emulate_stop(); -} void ibutton_worker_mode_emulate_start(iButtonWorker* worker) { - furi_assert(worker->key_p); + furi_assert(worker->key); furi_hal_rfid_pins_reset(); furi_hal_rfid_pin_pull_pulldown(); - switch(ibutton_key_get_type(worker->key_p)) { - case iButtonKeyDS1990: - ibutton_worker_emulate_dallas_start(worker); - break; - case iButtonKeyCyfral: - case iButtonKeyMetakom: - ibutton_worker_emulate_timer_start(worker); - break; - } + ibutton_protocols_emulate_start(worker->protocols, worker->key); } void ibutton_worker_mode_emulate_tick(iButtonWorker* worker) { @@ -292,56 +109,45 @@ void ibutton_worker_mode_emulate_tick(iButtonWorker* worker) { } void ibutton_worker_mode_emulate_stop(iButtonWorker* worker) { - furi_assert(worker->key_p); + furi_assert(worker->key); + + ibutton_protocols_emulate_stop(worker->protocols, worker->key); furi_hal_rfid_pins_reset(); - - switch(ibutton_key_get_type(worker->key_p)) { - case iButtonKeyDS1990: - ibutton_worker_emulate_dallas_stop(worker); - break; - case iButtonKeyCyfral: - case iButtonKeyMetakom: - ibutton_worker_emulate_timer_stop(worker); - break; - } } /*********************** WRITE ***********************/ -void ibutton_worker_mode_write_start(iButtonWorker* worker) { +void ibutton_worker_mode_write_common_start(iButtonWorker* worker) { //-V524 + UNUSED(worker); furi_hal_power_enable_otg(); - onewire_host_start(worker->host); } -void ibutton_worker_mode_write_tick(iButtonWorker* worker) { - furi_check(worker->key_p != NULL); - iButtonWriterResult writer_result = ibutton_writer_write(worker->writer, worker->key_p); - iButtonWorkerWriteResult result; - switch(writer_result) { - case iButtonWriterOK: - result = iButtonWorkerWriteOK; - break; - case iButtonWriterSameKey: - result = iButtonWorkerWriteSameKey; - break; - case iButtonWriterNoDetect: - result = iButtonWorkerWriteNoDetect; - break; - case iButtonWriterCannotWrite: - result = iButtonWorkerWriteCannotWrite; - break; - default: - result = iButtonWorkerWriteNoDetect; - break; - } +void ibutton_worker_mode_write_blank_tick(iButtonWorker* worker) { + furi_assert(worker->key); + const bool success = ibutton_protocols_write_blank(worker->protocols, worker->key); + // TODO: pass a proper result to the callback + const iButtonWorkerWriteResult result = success ? iButtonWorkerWriteOK : + iButtonWorkerWriteNoDetect; if(worker->write_cb != NULL) { worker->write_cb(worker->cb_ctx, result); } } -void ibutton_worker_mode_write_stop(iButtonWorker* worker) { - furi_hal_power_disable_otg(); - onewire_host_stop(worker->host); +void ibutton_worker_mode_write_copy_tick(iButtonWorker* worker) { + furi_assert(worker->key); + + const bool success = ibutton_protocols_write_copy(worker->protocols, worker->key); + // TODO: pass a proper result to the callback + const iButtonWorkerWriteResult result = success ? iButtonWorkerWriteOK : + iButtonWorkerWriteNoDetect; + if(worker->write_cb != NULL) { + worker->write_cb(worker->cb_ctx, result); + } +} + +void ibutton_worker_mode_write_common_stop(iButtonWorker* worker) { //-V524 + UNUSED(worker); + furi_hal_power_disable_otg(); } diff --git a/lib/one_wire/ibutton/ibutton_writer.c b/lib/one_wire/ibutton/ibutton_writer.c deleted file mode 100644 index 84d12249..00000000 --- a/lib/one_wire/ibutton/ibutton_writer.c +++ /dev/null @@ -1,298 +0,0 @@ -#include -#include -#include "ibutton_writer.h" -#include "ibutton_key_command.h" - -/*********************** PRIVATE ***********************/ - -struct iButtonWriter { - OneWireHost* host; -}; - -static void writer_write_one_bit(iButtonWriter* writer, bool value, uint32_t delay) { - onewire_host_write_bit(writer->host, value); - furi_delay_us(delay); -} - -static void writer_write_byte_ds1990(iButtonWriter* writer, uint8_t data) { - for(uint8_t n_bit = 0; n_bit < 8; n_bit++) { - onewire_host_write_bit(writer->host, data & 1); - furi_delay_us(5000); - data = data >> 1; - } -} - -static bool writer_compare_key_ds1990(iButtonWriter* writer, iButtonKey* key) { - bool result = false; - - if(ibutton_key_get_type(key) == iButtonKeyDS1990) { - FURI_CRITICAL_ENTER(); - bool presence = onewire_host_reset(writer->host); - - if(presence) { - onewire_host_write(writer->host, DS1990_CMD_READ_ROM); - - result = true; - for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { - if(ibutton_key_get_data_p(key)[i] != onewire_host_read(writer->host)) { - result = false; - break; - } - } - } - - FURI_CRITICAL_EXIT(); - } - - return result; -} - -static bool writer_write_TM2004(iButtonWriter* writer, iButtonKey* key) { - uint8_t answer; - bool result = true; - - if(ibutton_key_get_type(key) == iButtonKeyDS1990) { - FURI_CRITICAL_ENTER(); - - // write rom, addr is 0x0000 - onewire_host_reset(writer->host); - onewire_host_write(writer->host, TM2004_CMD_WRITE_ROM); - onewire_host_write(writer->host, 0x00); - onewire_host_write(writer->host, 0x00); - - // write key - for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { - // write key byte - onewire_host_write(writer->host, ibutton_key_get_data_p(key)[i]); - answer = onewire_host_read(writer->host); - // TODO: check answer CRC - - // pulse indicating that data is correct - furi_delay_us(600); - writer_write_one_bit(writer, 1, 50000); - - // read written key byte - answer = onewire_host_read(writer->host); //-V519 - - // check that written and read are same - if(ibutton_key_get_data_p(key)[i] != answer) { - result = false; - break; - } - } - - if(!writer_compare_key_ds1990(writer, key)) { - result = false; - } - - onewire_host_reset(writer->host); - - FURI_CRITICAL_EXIT(); - } else { - result = false; - } - - return result; -} - -static bool writer_write_1990_1(iButtonWriter* writer, iButtonKey* key) { - bool result = false; - - if(ibutton_key_get_type(key) == iButtonKeyDS1990) { - FURI_CRITICAL_ENTER(); - - // unlock - onewire_host_reset(writer->host); - onewire_host_write(writer->host, RW1990_1_CMD_WRITE_RECORD_FLAG); - furi_delay_us(10); - writer_write_one_bit(writer, 0, 5000); - - // write key - onewire_host_reset(writer->host); - onewire_host_write(writer->host, RW1990_1_CMD_WRITE_ROM); - for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { - // inverted key for RW1990.1 - writer_write_byte_ds1990(writer, ~ibutton_key_get_data_p(key)[i]); - furi_delay_us(30000); - } - - // lock - onewire_host_write(writer->host, RW1990_1_CMD_WRITE_RECORD_FLAG); - writer_write_one_bit(writer, 1, 10000); - - FURI_CRITICAL_EXIT(); - - if(writer_compare_key_ds1990(writer, key)) { - result = true; - } - } - - return result; -} - -static bool writer_write_1990_2(iButtonWriter* writer, iButtonKey* key) { - bool result = false; - - if(ibutton_key_get_type(key) == iButtonKeyDS1990) { - FURI_CRITICAL_ENTER(); - - // unlock - onewire_host_reset(writer->host); - onewire_host_write(writer->host, RW1990_2_CMD_WRITE_RECORD_FLAG); - furi_delay_us(10); - writer_write_one_bit(writer, 1, 5000); - - // write key - onewire_host_reset(writer->host); - onewire_host_write(writer->host, RW1990_2_CMD_WRITE_ROM); - for(uint8_t i = 0; i < ibutton_key_get_data_size(key); i++) { - writer_write_byte_ds1990(writer, ibutton_key_get_data_p(key)[i]); - furi_delay_us(30000); - } - - // lock - onewire_host_write(writer->host, RW1990_2_CMD_WRITE_RECORD_FLAG); - writer_write_one_bit(writer, 0, 10000); - - FURI_CRITICAL_EXIT(); - - if(writer_compare_key_ds1990(writer, key)) { - result = true; - } - } - - return result; -} - -/* -// TODO: adapt and test -static bool writer_write_TM01( - iButtonWriter* writer, - iButtonKey type, - const uint8_t* key, - uint8_t key_length) { - bool result = true; - - { - // TODO test and encoding - FURI_CRITICAL_ENTER(); - - // unlock - onewire_host_reset(writer->host); - onewire_host_write(writer->host, TM01::CMD_WRITE_RECORD_FLAG); - onewire_write_one_bit(1, 10000); - - // write key - onewire_host_reset(writer->host); - onewire_host_write(writer->host, TM01::CMD_WRITE_ROM); - - // TODO: key types - //if(type == KEY_METAKOM || type == KEY_CYFRAL) { - //} else { - for(uint8_t i = 0; i < key->get_type_data_size(); i++) { - write_byte_ds1990(key->get_data()[i]); - furi_delay_us(10000); - } - //} - - // lock - onewire_host_write(writer->host, TM01::CMD_WRITE_RECORD_FLAG); - onewire_write_one_bit(0, 10000); - - FURI_CRITICAL_EXIT(); - } - - if(!compare_key_ds1990(key)) { - result = false; - } - - { - FURI_CRITICAL_ENTER(); - - if(key->get_key_type() == iButtonKeyType::KeyMetakom || - key->get_key_type() == iButtonKeyType::KeyCyfral) { - onewire_host_reset(writer->host); - if(key->get_key_type() == iButtonKeyType::KeyCyfral) - onewire_host_write(writer->host, TM01::CMD_SWITCH_TO_CYFRAL); - else - onewire_host_write(writer->host, TM01::CMD_SWITCH_TO_METAKOM); - onewire_write_one_bit(1); - } - - FURI_CRITICAL_EXIT(); - } - - return result; -} -*/ - -static iButtonWriterResult writer_write_DS1990(iButtonWriter* writer, iButtonKey* key) { - iButtonWriterResult result = iButtonWriterNoDetect; - bool same_key = writer_compare_key_ds1990(writer, key); - - if(!same_key) { - // currently we can write: - // RW1990_1, TM08v2, TM08vi-2 by write_1990_1() - // RW1990_2 by write_1990_2() - // RW2004, RW2004, TM2004 with EEPROM by write_TM2004(); - - bool write_result = true; - do { - if(writer_write_1990_1(writer, key)) break; - if(writer_write_1990_2(writer, key)) break; - if(writer_write_TM2004(writer, key)) break; - write_result = false; - } while(false); - - if(write_result) { - result = iButtonWriterOK; - } else { - result = iButtonWriterCannotWrite; - } - } else { - result = iButtonWriterSameKey; - } - - return result; -} - -/*********************** PUBLIC ***********************/ - -iButtonWriter* ibutton_writer_alloc(OneWireHost* host) { - iButtonWriter* writer = malloc(sizeof(iButtonWriter)); - writer->host = host; - return writer; -} - -void ibutton_writer_free(iButtonWriter* writer) { - free(writer); -} - -iButtonWriterResult ibutton_writer_write(iButtonWriter* writer, iButtonKey* key) { - iButtonWriterResult result = iButtonWriterNoDetect; - - furi_kernel_lock(); - bool blank_present = onewire_host_reset(writer->host); - furi_kernel_unlock(); - - if(blank_present) { - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - result = writer_write_DS1990(writer, key); - default: - break; - } - } - - return result; -} - -void ibutton_writer_start(iButtonWriter* writer) { - furi_hal_power_enable_otg(); - onewire_host_start(writer->host); -} - -void ibutton_writer_stop(iButtonWriter* writer) { - onewire_host_stop(writer->host); - furi_hal_power_disable_otg(); -} diff --git a/lib/one_wire/ibutton/ibutton_writer.h b/lib/one_wire/ibutton/ibutton_writer.h deleted file mode 100644 index 6dbdbb27..00000000 --- a/lib/one_wire/ibutton/ibutton_writer.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file ibutton_writer.h - * - * iButton blanks writer - */ - -#pragma once -#include -#include "ibutton_key.h" -#include "../one_wire_host.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - iButtonWriterOK, - iButtonWriterSameKey, - iButtonWriterNoDetect, - iButtonWriterCannotWrite, -} iButtonWriterResult; - -typedef struct iButtonWriter iButtonWriter; - -/** - * Allocate writer - * @param host - * @return iButtonWriter* - */ -iButtonWriter* ibutton_writer_alloc(OneWireHost* host); - -/** - * Deallocate writer - * @param writer - */ -void ibutton_writer_free(iButtonWriter* writer); - -/** - * Write key to blank - * @param writer - * @param key - * @return iButtonWriterResult - */ -iButtonWriterResult ibutton_writer_write(iButtonWriter* writer, iButtonKey* key); - -/** - * Start writing. Must be called before write attempt - * @param writer - */ -void ibutton_writer_start(iButtonWriter* writer); - -/** - * Stop writing - * @param writer - */ -void ibutton_writer_stop(iButtonWriter* writer); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/ibutton/protocols/blanks/rw1990.c b/lib/one_wire/ibutton/protocols/blanks/rw1990.c new file mode 100644 index 00000000..d3350fcf --- /dev/null +++ b/lib/one_wire/ibutton/protocols/blanks/rw1990.c @@ -0,0 +1,95 @@ +#include "rw1990.h" + +#include + +#define RW1990_1_CMD_WRITE_RECORD_FLAG 0xD1 +#define RW1990_1_CMD_READ_RECORD_FLAG 0xB5 +#define RW1990_1_CMD_WRITE_ROM 0xD5 + +#define RW1990_2_CMD_WRITE_RECORD_FLAG 0x1D +#define RW1990_2_CMD_READ_RECORD_FLAG 0x1E +#define RW1990_2_CMD_WRITE_ROM 0xD5 + +#define DS1990_CMD_READ_ROM 0x33 + +static void rw1990_write_byte(OneWireHost* host, uint8_t value) { + for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { + onewire_host_write_bit(host, (bool)(bitMask & value)); + furi_delay_us(5000); + } +} + +static bool rw1990_read_and_compare(OneWireHost* host, const uint8_t* data, size_t data_size) { + bool success = false; + + if(onewire_host_reset(host)) { + success = true; + onewire_host_write(host, DS1990_CMD_READ_ROM); + + for(size_t i = 0; i < data_size; ++i) { + if(data[i] != onewire_host_read(host)) { + success = false; + break; + } + } + } + + return success; +} + +bool rw1990_write_v1(OneWireHost* host, const uint8_t* data, size_t data_size) { + // Unlock sequence + onewire_host_reset(host); + onewire_host_write(host, RW1990_1_CMD_WRITE_RECORD_FLAG); + furi_delay_us(10); + + onewire_host_write_bit(host, false); + furi_delay_us(5000); + + // Write data + onewire_host_reset(host); + onewire_host_write(host, RW1990_1_CMD_WRITE_ROM); + + for(size_t i = 0; i < data_size; ++i) { + // inverted key for RW1990.1 + rw1990_write_byte(host, ~(data[i])); + furi_delay_us(30000); + } + + // Lock sequence + onewire_host_write(host, RW1990_1_CMD_WRITE_RECORD_FLAG); + + onewire_host_write_bit(host, true); + furi_delay_us(10000); + + // TODO: Better error handling + return rw1990_read_and_compare(host, data, data_size); +} + +bool rw1990_write_v2(OneWireHost* host, const uint8_t* data, size_t data_size) { + // Unlock sequence + onewire_host_reset(host); + onewire_host_write(host, RW1990_2_CMD_WRITE_RECORD_FLAG); + furi_delay_us(10); + + onewire_host_write_bit(host, true); + furi_delay_us(5000); + + // Write data + onewire_host_reset(host); + onewire_host_write(host, RW1990_2_CMD_WRITE_ROM); + + for(size_t i = 0; i < data_size; ++i) { + rw1990_write_byte(host, data[i]); + furi_delay_us(30000); + } + + // Lock sequence + onewire_host_write(host, RW1990_2_CMD_WRITE_RECORD_FLAG); + + onewire_host_write_bit(host, false); + furi_delay_us(10000); + + // TODO: Better error handling + return rw1990_read_and_compare(host, data, data_size); +} diff --git a/lib/one_wire/ibutton/protocols/blanks/rw1990.h b/lib/one_wire/ibutton/protocols/blanks/rw1990.h new file mode 100644 index 00000000..bdd27f6b --- /dev/null +++ b/lib/one_wire/ibutton/protocols/blanks/rw1990.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include + +bool rw1990_write_v1(OneWireHost* host, const uint8_t* data, size_t data_size); + +bool rw1990_write_v2(OneWireHost* host, const uint8_t* data, size_t data_size); diff --git a/lib/one_wire/ibutton/protocols/blanks/tm2004.c b/lib/one_wire/ibutton/protocols/blanks/tm2004.c new file mode 100644 index 00000000..ef6f0619 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/blanks/tm2004.c @@ -0,0 +1,42 @@ +#include "tm2004.h" + +#include + +#define TM2004_CMD_READ_STATUS 0xAA +#define TM2004_CMD_READ_MEMORY 0xF0 +#define TM2004_CMD_WRITE_ROM 0x3C +#define TM2004_CMD_FINALIZATION 0x35 +#define TM2004_ANSWER_READ_MEMORY 0xF5 + +bool tm2004_write(OneWireHost* host, const uint8_t* data, size_t data_size) { + onewire_host_reset(host); + onewire_host_write(host, TM2004_CMD_WRITE_ROM); + // Starting writing from address 0x0000 + onewire_host_write(host, 0x00); + onewire_host_write(host, 0x00); + + size_t i; + for(i = 0; i < data_size; ++i) { + uint8_t answer; + + onewire_host_write(host, data[i]); + answer = onewire_host_read(host); + // TODO: check answer CRC + + // pulse indicating that data is correct + furi_delay_us(600); + onewire_host_write_bit(host, true); + furi_delay_us(50000); + + // read written key byte + answer = onewire_host_read(host); //-V519 + + // check that written and read are same + if(data[i] != answer) { + break; + } + } + + // TODO: Better error handling + return i == data_size; +} diff --git a/lib/one_wire/ibutton/protocols/blanks/tm2004.h b/lib/one_wire/ibutton/protocols/blanks/tm2004.h new file mode 100644 index 00000000..15713af5 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/blanks/tm2004.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include + +bool tm2004_write(OneWireHost* host, const uint8_t* data, size_t data_size); diff --git a/lib/one_wire/ibutton/protocols/dallas/dallas_common.c b/lib/one_wire/ibutton/protocols/dallas/dallas_common.c new file mode 100644 index 00000000..57a873b1 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/dallas_common.c @@ -0,0 +1,250 @@ +#include "dallas_common.h" + +#include +#include + +#define BITS_IN_BYTE 8U + +#define DALLAS_COMMON_ROM_DATA_KEY_V1 "Data" +#define DALLAS_COMMON_ROM_DATA_KEY_V2 "Rom Data" + +#define DALLAS_COMMON_COPY_SCRATCH_MIN_TIMEOUT_US 5U +#define DALLAS_COMMON_COPY_SCRATCH_POLL_COUNT 20U + +#define DALLAS_COMMON_END_ADDRESS_MASK 0x01F +#define DALLAS_COMMON_STATUS_FLAG_PF (1U << 5) +#define DALLAS_COMMON_STATUS_FLAG_OF (1U << 6) +#define DALLAS_COMMON_STATUS_FLAG_AA (1U << 7) + +#define DALLAS_COMMON_BRIEF_HEAD_COUNT 4U +#define DALLAS_COMMON_BRIEF_TAIL_COUNT 3U + +#define BITS_IN_BYTE 8U +#define BITS_IN_KBIT 1024U + +bool dallas_common_skip_rom(OneWireHost* host) { + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); + return true; +} + +bool dallas_common_read_rom(OneWireHost* host, DallasCommonRomData* rom_data) { + onewire_host_write(host, DALLAS_COMMON_CMD_READ_ROM); + onewire_host_read_bytes(host, rom_data->bytes, sizeof(DallasCommonRomData)); + + return dallas_common_is_valid_crc(rom_data); +} + +bool dallas_common_write_scratchpad( + OneWireHost* host, + uint16_t address, + const uint8_t* data, + size_t data_size) { + onewire_host_write(host, DALLAS_COMMON_CMD_WRITE_SCRATCH); + onewire_host_write(host, (uint8_t)address); + onewire_host_write(host, (uint8_t)(address >> BITS_IN_BYTE)); + + onewire_host_write_bytes(host, data, data_size); + + return true; +} + +bool dallas_common_read_scratchpad( + OneWireHost* host, + DallasCommonAddressRegs* regs, + uint8_t* data, + size_t data_size) { + onewire_host_write(host, DALLAS_COMMON_CMD_READ_SCRATCH); + onewire_host_read_bytes(host, regs->bytes, sizeof(DallasCommonAddressRegs)); + onewire_host_read_bytes(host, data, data_size); + + return true; +} + +bool dallas_common_copy_scratchpad( + OneWireHost* host, + const DallasCommonAddressRegs* regs, + uint32_t timeout_us) { + onewire_host_write(host, DALLAS_COMMON_CMD_COPY_SCRATCH); + onewire_host_write_bytes(host, regs->bytes, sizeof(DallasCommonAddressRegs)); + + const uint32_t poll_delay = + MAX(timeout_us / DALLAS_COMMON_COPY_SCRATCH_POLL_COUNT, + DALLAS_COMMON_COPY_SCRATCH_MIN_TIMEOUT_US); + + uint32_t time_elapsed; + for(time_elapsed = 0; time_elapsed < timeout_us; time_elapsed += poll_delay) { + if(!onewire_host_read_bit(host)) break; + furi_delay_us(poll_delay); + } + + return time_elapsed < timeout_us; +} + +bool dallas_common_read_mem(OneWireHost* host, uint16_t address, uint8_t* data, size_t data_size) { + onewire_host_write(host, DALLAS_COMMON_CMD_READ_MEM); + + onewire_host_write(host, (uint8_t)address); + onewire_host_write(host, (uint8_t)(address > BITS_IN_BYTE)); + + onewire_host_read_bytes(host, data, (uint16_t)data_size); + + return true; +} + +bool dallas_common_write_mem( + OneWireHost* host, + uint32_t timeout_us, + size_t page_size, + const uint8_t* data, + size_t data_size) { + // Data size must be a multiple of page size + furi_check(data_size % page_size == 0); + + DallasCommonAddressRegs regs; + uint8_t* scratch = malloc(page_size); + + size_t i; + for(i = 0; i < data_size; i += page_size) { + const uint8_t* data_ptr = data + i; + + // Write scratchpad with the next page value + if(!onewire_host_reset(host)) break; + if(!dallas_common_skip_rom(host)) break; + if(!dallas_common_write_scratchpad(host, i, data_ptr, page_size)) break; + + // Read back the scratchpad contents and address registers + if(!onewire_host_reset(host)) break; + if(!dallas_common_skip_rom(host)) break; + if(!dallas_common_read_scratchpad(host, ®s, scratch, page_size)) break; + + // Verify scratchpad contents + if(memcmp(data_ptr, scratch, page_size) != 0) break; + + // Write scratchpad to internal memory + if(!onewire_host_reset(host)) break; + if(!dallas_common_skip_rom(host)) break; + if(!dallas_common_copy_scratchpad(host, ®s, timeout_us)) break; + + // Read back the address registers again + if(!onewire_host_reset(host)) break; + if(!dallas_common_skip_rom(host)) break; + if(!dallas_common_read_scratchpad(host, ®s, scratch, 0)) break; + + // Check if AA flag is set + if(!(regs.fields.status & DALLAS_COMMON_STATUS_FLAG_AA)) break; + } + + free(scratch); + + return i == data_size; +} + +bool dallas_common_emulate_search_rom(OneWireSlave* bus, const DallasCommonRomData* rom_data) { + for(size_t i = 0; i < sizeof(DallasCommonRomData); i++) { + for(size_t j = 0; j < BITS_IN_BYTE; j++) { + bool bit = (rom_data->bytes[i] >> j) & 0x01; + + if(!onewire_slave_send_bit(bus, bit)) return false; + if(!onewire_slave_send_bit(bus, !bit)) return false; + + onewire_slave_receive_bit(bus); + // TODO: check for errors and return if any + } + } + + return true; +} + +bool dallas_common_emulate_read_rom(OneWireSlave* bus, const DallasCommonRomData* rom_data) { + return onewire_slave_send(bus, rom_data->bytes, sizeof(DallasCommonRomData)); +} + +bool dallas_common_emulate_read_mem(OneWireSlave* bus, const uint8_t* data, size_t data_size) { + bool success = false; + + union { + uint8_t bytes[sizeof(uint16_t)]; + uint16_t word; + } address; + + do { + if(!onewire_slave_receive(bus, address.bytes, sizeof(address))) break; + if(address.word >= data_size) break; + if(!onewire_slave_send(bus, data + address.word, data_size - address.word)) break; + + success = true; + } while(false); + + return success; +} + +bool dallas_common_save_rom_data(FlipperFormat* ff, const DallasCommonRomData* rom_data) { + return flipper_format_write_hex( + ff, DALLAS_COMMON_ROM_DATA_KEY_V2, rom_data->bytes, sizeof(DallasCommonRomData)); +} + +bool dallas_common_load_rom_data( + FlipperFormat* ff, + uint32_t format_version, + DallasCommonRomData* rom_data) { + switch(format_version) { + case 1: + return flipper_format_read_hex( + ff, DALLAS_COMMON_ROM_DATA_KEY_V1, rom_data->bytes, sizeof(DallasCommonRomData)); + case 2: + return flipper_format_read_hex( + ff, DALLAS_COMMON_ROM_DATA_KEY_V2, rom_data->bytes, sizeof(DallasCommonRomData)); + default: + return false; + } +} + +bool dallas_common_is_valid_crc(const DallasCommonRomData* rom_data) { + const uint8_t crc_calculated = + maxim_crc8(rom_data->bytes, sizeof(DallasCommonRomData) - 1, MAXIM_CRC8_INIT); + const uint8_t crc_received = rom_data->fields.checksum; + + return crc_calculated == crc_received; +} + +void dallas_common_render_brief_data( + FuriString* result, + const DallasCommonRomData* rom_data, + const uint8_t* sram_data, + size_t sram_data_size) { + for(size_t i = 0; i < sizeof(rom_data->bytes); ++i) { + furi_string_cat_printf(result, "%02X ", rom_data->bytes[i]); + } + + furi_string_cat_printf( + result, + "\nInternal SRAM: %zu Kbit\n", + (size_t)(sram_data_size * BITS_IN_BYTE / BITS_IN_KBIT)); + + for(size_t i = 0; i < DALLAS_COMMON_BRIEF_HEAD_COUNT; ++i) { + furi_string_cat_printf(result, "%02X ", sram_data[i]); + } + + furi_string_cat_printf(result, "[ . . . ]"); + + for(size_t i = sram_data_size - DALLAS_COMMON_BRIEF_TAIL_COUNT; i < sram_data_size; ++i) { + furi_string_cat_printf(result, " %02X", sram_data[i]); + } +} + +void dallas_common_render_crc_error(FuriString* result, const DallasCommonRomData* rom_data) { + furi_string_set(result, "CRC Error\n"); + + const size_t data_size = sizeof(DallasCommonRomData); + + for(size_t i = 0; i < data_size; ++i) { + furi_string_cat_printf(result, (i < data_size - 1) ? "%02X " : "%02X", rom_data->bytes[i]); + } +} + +void dallas_common_apply_edits(DallasCommonRomData* rom_data, uint8_t family_code) { + rom_data->fields.family_code = family_code; + const uint8_t crc = + maxim_crc8(rom_data->bytes, sizeof(DallasCommonRomData) - 1, MAXIM_CRC8_INIT); + rom_data->fields.checksum = crc; +} diff --git a/lib/one_wire/ibutton/protocols/dallas/dallas_common.h b/lib/one_wire/ibutton/protocols/dallas/dallas_common.h new file mode 100644 index 00000000..7ad13eb2 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/dallas_common.h @@ -0,0 +1,107 @@ +#pragma once + +#include + +#include +#include + +#define DALLAS_COMMON_MANUFACTURER_NAME "Dallas" + +#define DALLAS_COMMON_CMD_READ_ROM 0x33U +#define DALLAS_COMMON_CMD_MATCH_ROM 0x55U +#define DALLAS_COMMON_CMD_SKIP_ROM 0xCCU +#define DALLAS_COMMON_CMD_COND_SEARCH 0xECU +#define DALLAS_COMMON_CMD_SEARCH_ROM 0xF0U + +#define DALLAS_COMMON_CMD_READ_SCRATCH 0xAAU +#define DALLAS_COMMON_CMD_WRITE_SCRATCH 0x0FU +#define DALLAS_COMMON_CMD_COPY_SCRATCH 0x55U + +#define DALLAS_COMMON_CMD_READ_MEM 0xF0U + +#define DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM 0x3CU +#define DALLAS_COMMON_CMD_OVERDRIVE_MATCH_ROM 0x69U + +typedef enum { + DallasCommonCommandStateIdle, + DallasCommonCommandStateRomCmd, + DallasCommonCommandStateMemCmd, +} DallasCommonCommandState; + +typedef union { + struct { + uint8_t family_code; + uint8_t serial_number[6]; + uint8_t checksum; + } fields; + uint8_t bytes[8]; +} DallasCommonRomData; + +typedef union { + struct { + uint8_t address_lo; + uint8_t address_hi; + uint8_t status; + } fields; + uint8_t bytes[3]; +} DallasCommonAddressRegs; + +/* Standard(ish) iButton commands */ +bool dallas_common_skip_rom(OneWireHost* host); + +bool dallas_common_read_rom(OneWireHost* host, DallasCommonRomData* rom_data); + +bool dallas_common_write_scratchpad( + OneWireHost* host, + uint16_t address, + const uint8_t* data, + size_t data_size); + +bool dallas_common_read_scratchpad( + OneWireHost* host, + DallasCommonAddressRegs* regs, + uint8_t* data, + size_t data_size); + +bool dallas_common_copy_scratchpad( + OneWireHost* host, + const DallasCommonAddressRegs* regs, + uint32_t timeout_us); + +bool dallas_common_read_mem(OneWireHost* host, uint16_t address, uint8_t* data, size_t data_size); + +/* Combined operations */ +bool dallas_common_write_mem( + OneWireHost* host, + uint32_t timeout_us, + size_t page_size, + const uint8_t* data, + size_t data_size); + +/* Emulation */ +bool dallas_common_emulate_search_rom(OneWireSlave* bus, const DallasCommonRomData* rom_data); + +bool dallas_common_emulate_read_rom(OneWireSlave* bus, const DallasCommonRomData* rom_data); + +bool dallas_common_emulate_read_mem(OneWireSlave* bus, const uint8_t* data, size_t data_size); + +/* Save & Load */ +bool dallas_common_save_rom_data(FlipperFormat* ff, const DallasCommonRomData* rom_data); + +bool dallas_common_load_rom_data( + FlipperFormat* ff, + uint32_t format_version, + DallasCommonRomData* rom_data); + +/* Miscellaneous */ +bool dallas_common_is_valid_crc(const DallasCommonRomData* rom_data); + +void dallas_common_render_brief_data( + FuriString* result, + const DallasCommonRomData* rom_data, + const uint8_t* sram_data, + size_t sram_data_size); + +void dallas_common_render_crc_error(FuriString* result, const DallasCommonRomData* rom_data); + +void dallas_common_apply_edits(DallasCommonRomData* rom_data, uint8_t family_code); diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_dallas_base.h b/lib/one_wire/ibutton/protocols/dallas/protocol_dallas_base.h new file mode 100644 index 00000000..b4edb2b2 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_dallas_base.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../protocol_common_i.h" + +#include + +#include +#include + +typedef bool (*iButtonProtocolDallasReadWriteFunc)(OneWireHost*, iButtonProtocolData*); +typedef void (*iButtonProtocolDallasEmulateFunc)(OneWireSlave*, iButtonProtocolData*); +typedef bool (*iButtonProtocolDallasSaveFunc)(FlipperFormat*, const iButtonProtocolData*); +typedef bool (*iButtonProtocolDallasLoadFunc)(FlipperFormat*, uint32_t, iButtonProtocolData*); +typedef void (*iButtonProtocolDallasRenderDataFunc)(FuriString*, const iButtonProtocolData*); +typedef bool (*iButtonProtocolDallasIsValidFunc)(const iButtonProtocolData*); +typedef void ( + *iButtonProtocolDallasGetEditableDataFunc)(iButtonEditableData*, iButtonProtocolData*); +typedef void (*iButtonProtocolDallasApplyEditsFunc)(iButtonProtocolData*); + +typedef struct { + const uint8_t family_code; + const uint32_t features; + const size_t data_size; + const char* manufacturer; + const char* name; + + iButtonProtocolDallasReadWriteFunc read; + iButtonProtocolDallasReadWriteFunc write_blank; + iButtonProtocolDallasReadWriteFunc write_copy; + iButtonProtocolDallasEmulateFunc emulate; + iButtonProtocolDallasSaveFunc save; + iButtonProtocolDallasLoadFunc load; + iButtonProtocolDallasRenderDataFunc render_data; + iButtonProtocolDallasRenderDataFunc render_brief_data; + iButtonProtocolDallasRenderDataFunc render_error; + iButtonProtocolDallasIsValidFunc is_valid; + iButtonProtocolDallasGetEditableDataFunc get_editable_data; + iButtonProtocolDallasApplyEditsFunc apply_edits; +} iButtonProtocolDallasBase; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.c b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.c new file mode 100644 index 00000000..0d9c937e --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.c @@ -0,0 +1,144 @@ +#include "protocol_ds1990.h" + +#include +#include + +#include "dallas_common.h" + +#include "../blanks/rw1990.h" +#include "../blanks/tm2004.h" + +#define DS1990_FAMILY_CODE 0x01U +#define DS1990_FAMILY_NAME "DS1990" + +#define DS1990_CMD_READ_ROM 0x0FU + +typedef struct { + OneWireSlave* bus; +} DS1990ProtocolState; + +typedef struct { + DallasCommonRomData rom_data; + DS1990ProtocolState state; +} DS1990ProtocolData; + +static bool dallas_ds1990_read(OneWireHost*, iButtonProtocolData*); +static bool dallas_ds1990_write_blank(OneWireHost*, iButtonProtocolData*); +static void dallas_ds1990_emulate(OneWireSlave*, iButtonProtocolData*); +static bool dallas_ds1990_load(FlipperFormat*, uint32_t, iButtonProtocolData*); +static bool dallas_ds1990_save(FlipperFormat*, const iButtonProtocolData*); +static void dallas_ds1990_render_brief_data(FuriString*, const iButtonProtocolData*); +static void dallas_ds1990_render_error(FuriString*, const iButtonProtocolData*); +static bool dallas_ds1990_is_data_valid(const iButtonProtocolData*); +static void dallas_ds1990_get_editable_data(iButtonEditableData*, iButtonProtocolData*); +static void dallas_ds1990_apply_edits(iButtonProtocolData*); + +const iButtonProtocolDallasBase ibutton_protocol_ds1990 = { + .family_code = DS1990_FAMILY_CODE, + .features = iButtonProtocolFeatureWriteBlank, + .data_size = sizeof(DS1990ProtocolData), + .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, + .name = DS1990_FAMILY_NAME, + + .read = dallas_ds1990_read, + .write_blank = dallas_ds1990_write_blank, + .write_copy = NULL, /* No data to write a copy */ + .emulate = dallas_ds1990_emulate, + .save = dallas_ds1990_save, + .load = dallas_ds1990_load, + .render_data = NULL, /* No data to render */ + .render_brief_data = dallas_ds1990_render_brief_data, + .render_error = dallas_ds1990_render_error, + .is_valid = dallas_ds1990_is_data_valid, + .get_editable_data = dallas_ds1990_get_editable_data, + .apply_edits = dallas_ds1990_apply_edits, +}; + +bool dallas_ds1990_read(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1990ProtocolData* data = protocol_data; + return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data); +} + +bool dallas_ds1990_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1990ProtocolData* data = protocol_data; + + return rw1990_write_v1(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) || + rw1990_write_v2(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) || + tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); +} + +static bool dallas_ds1990_command_callback(uint8_t command, void* context) { + furi_assert(context); + DS1990ProtocolData* data = context; + OneWireSlave* bus = data->state.bus; + + switch(command) { + case DALLAS_COMMON_CMD_SEARCH_ROM: + dallas_common_emulate_search_rom(bus, &data->rom_data); + break; + case DALLAS_COMMON_CMD_READ_ROM: + case DS1990_CMD_READ_ROM: + dallas_common_emulate_read_rom(bus, &data->rom_data); + break; + default: + break; + } + + // No support for multiple consecutive commands + return false; +} + +void dallas_ds1990_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { + DS1990ProtocolData* data = protocol_data; + data->state.bus = bus; + + onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_command_callback(bus, dallas_ds1990_command_callback, protocol_data); +} + +bool dallas_ds1990_save(FlipperFormat* ff, const iButtonProtocolData* protocol_data) { + const DS1990ProtocolData* data = protocol_data; + return dallas_common_save_rom_data(ff, &data->rom_data); +} + +bool dallas_ds1990_load( + FlipperFormat* ff, + uint32_t format_version, + iButtonProtocolData* protocol_data) { + DS1990ProtocolData* data = protocol_data; + return dallas_common_load_rom_data(ff, format_version, &data->rom_data); +} + +void dallas_ds1990_render_brief_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1990ProtocolData* data = protocol_data; + + for(size_t i = 0; i < sizeof(DallasCommonRomData); ++i) { + furi_string_cat_printf(result, "%02X ", data->rom_data.bytes[i]); + } +} + +void dallas_ds1990_render_error(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1990ProtocolData* data = protocol_data; + + if(!dallas_common_is_valid_crc(&data->rom_data)) { + dallas_common_render_crc_error(result, &data->rom_data); + } +} + +bool dallas_ds1990_is_data_valid(const iButtonProtocolData* protocol_data) { + const DS1990ProtocolData* data = protocol_data; + return dallas_common_is_valid_crc(&data->rom_data); +} + +void dallas_ds1990_get_editable_data( + iButtonEditableData* editable_data, + iButtonProtocolData* protocol_data) { + DS1990ProtocolData* data = protocol_data; + editable_data->ptr = data->rom_data.bytes; + editable_data->size = sizeof(DallasCommonRomData); +} + +void dallas_ds1990_apply_edits(iButtonProtocolData* protocol_data) { + DS1990ProtocolData* data = protocol_data; + dallas_common_apply_edits(&data->rom_data, DS1990_FAMILY_CODE); +} diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.h b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.h new file mode 100644 index 00000000..de3da0e4 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1990.h @@ -0,0 +1,5 @@ +#pragma once + +#include "protocol_dallas_base.h" + +extern const iButtonProtocolDallasBase ibutton_protocol_ds1990; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.c b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.c new file mode 100644 index 00000000..131bc634 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.c @@ -0,0 +1,218 @@ +#include "protocol_ds1992.h" + +#include +#include + +#include "dallas_common.h" + +#include "../blanks/tm2004.h" + +#define DS1992_FAMILY_CODE 0x08U +#define DS1992_FAMILY_NAME "DS1992" + +#define DS1992_SRAM_DATA_SIZE 128U +#define DS1992_SRAM_PAGE_SIZE 4U +#define DS1992_COPY_SCRATCH_TIMEOUT_US 100U + +#define DS1992_DATA_BYTE_COUNT 4U + +#define DS1992_SRAM_DATA_KEY "Sram Data" + +typedef struct { + OneWireSlave* bus; + DallasCommonCommandState command_state; +} DS1992ProtocolState; + +typedef struct { + DallasCommonRomData rom_data; + uint8_t sram_data[DS1992_SRAM_DATA_SIZE]; + DS1992ProtocolState state; +} DS1992ProtocolData; + +static bool dallas_ds1992_read(OneWireHost*, void*); +static bool dallas_ds1992_write_blank(OneWireHost*, iButtonProtocolData*); +static bool dallas_ds1992_write_copy(OneWireHost*, iButtonProtocolData*); +static void dallas_ds1992_emulate(OneWireSlave*, iButtonProtocolData*); +static bool dallas_ds1992_load(FlipperFormat*, uint32_t, iButtonProtocolData*); +static bool dallas_ds1992_save(FlipperFormat*, const iButtonProtocolData*); +static void dallas_ds1992_render_data(FuriString*, const iButtonProtocolData*); +static void dallas_ds1992_render_brief_data(FuriString*, const iButtonProtocolData*); +static void dallas_ds1992_render_error(FuriString*, const iButtonProtocolData*); +static bool dallas_ds1992_is_data_valid(const iButtonProtocolData*); +static void dallas_ds1992_get_editable_data(iButtonEditableData*, iButtonProtocolData*); +static void dallas_ds1992_apply_edits(iButtonProtocolData*); + +const iButtonProtocolDallasBase ibutton_protocol_ds1992 = { + .family_code = DS1992_FAMILY_CODE, + .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteBlank | + iButtonProtocolFeatureWriteCopy, + .data_size = sizeof(DS1992ProtocolData), + .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, + .name = DS1992_FAMILY_NAME, + + .read = dallas_ds1992_read, + .write_blank = dallas_ds1992_write_blank, + .write_copy = dallas_ds1992_write_copy, + .emulate = dallas_ds1992_emulate, + .save = dallas_ds1992_save, + .load = dallas_ds1992_load, + .render_data = dallas_ds1992_render_data, + .render_brief_data = dallas_ds1992_render_brief_data, + .render_error = dallas_ds1992_render_error, + .is_valid = dallas_ds1992_is_data_valid, + .get_editable_data = dallas_ds1992_get_editable_data, + .apply_edits = dallas_ds1992_apply_edits, +}; + +bool dallas_ds1992_read(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data) && + dallas_common_read_mem(host, 0, data->sram_data, DS1992_SRAM_DATA_SIZE); +} + +bool dallas_ds1992_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + // TODO: Make this work, currently broken + return tm2004_write(host, (uint8_t*)data, sizeof(DallasCommonRomData) + DS1992_SRAM_DATA_SIZE); +} + +bool dallas_ds1992_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + return dallas_common_write_mem( + host, + DS1992_COPY_SCRATCH_TIMEOUT_US, + DS1992_SRAM_PAGE_SIZE, + data->sram_data, + DS1992_SRAM_DATA_SIZE); +} + +static void dallas_ds1992_reset_callback(void* context) { + furi_assert(context); + DS1992ProtocolData* data = context; + data->state.command_state = DallasCommonCommandStateIdle; +} + +static bool dallas_ds1992_command_callback(uint8_t command, void* context) { + furi_assert(context); + DS1992ProtocolData* data = context; + OneWireSlave* bus = data->state.bus; + + switch(command) { + case DALLAS_COMMON_CMD_SEARCH_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + return dallas_common_emulate_search_rom(bus, &data->rom_data); + + } else if(data->state.command_state == DallasCommonCommandStateRomCmd) { + data->state.command_state = DallasCommonCommandStateMemCmd; + dallas_common_emulate_read_mem(bus, data->sram_data, DS1992_SRAM_DATA_SIZE); + return false; + + } else { + return false; + } + + case DALLAS_COMMON_CMD_READ_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + return dallas_common_emulate_read_rom(bus, &data->rom_data); + } else { + return false; + } + + case DALLAS_COMMON_CMD_SKIP_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + return true; + } else { + return false; + } + + default: + return false; + } +} + +void dallas_ds1992_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + data->state.bus = bus; + + onewire_slave_set_reset_callback(bus, dallas_ds1992_reset_callback, protocol_data); + onewire_slave_set_command_callback(bus, dallas_ds1992_command_callback, protocol_data); +} + +bool dallas_ds1992_load( + FlipperFormat* ff, + uint32_t format_version, + iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + bool success = false; + + do { + if(format_version < 2) break; + if(!dallas_common_load_rom_data(ff, format_version, &data->rom_data)) break; + if(!flipper_format_read_hex( + ff, DS1992_SRAM_DATA_KEY, data->sram_data, DS1992_SRAM_DATA_SIZE)) + break; + success = true; + } while(false); + + return success; +} + +bool dallas_ds1992_save(FlipperFormat* ff, const iButtonProtocolData* protocol_data) { + const DS1992ProtocolData* data = protocol_data; + bool success = false; + + do { + if(!dallas_common_save_rom_data(ff, &data->rom_data)) break; + if(!flipper_format_write_hex( + ff, DS1992_SRAM_DATA_KEY, data->sram_data, DS1992_SRAM_DATA_SIZE)) + break; + success = true; + } while(false); + + return success; +} + +void dallas_ds1992_render_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1992ProtocolData* data = protocol_data; + pretty_format_bytes_hex_canonical( + result, + DS1992_DATA_BYTE_COUNT, + PRETTY_FORMAT_FONT_MONOSPACE, + data->sram_data, + DS1992_SRAM_DATA_SIZE); +} + +void dallas_ds1992_render_brief_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1992ProtocolData* data = protocol_data; + dallas_common_render_brief_data( + result, &data->rom_data, data->sram_data, DS1992_SRAM_DATA_SIZE); +} + +void dallas_ds1992_render_error(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1992ProtocolData* data = protocol_data; + + if(!dallas_common_is_valid_crc(&data->rom_data)) { + dallas_common_render_crc_error(result, &data->rom_data); + } +} + +bool dallas_ds1992_is_data_valid(const iButtonProtocolData* protocol_data) { + const DS1992ProtocolData* data = protocol_data; + return dallas_common_is_valid_crc(&data->rom_data); +} + +void dallas_ds1992_get_editable_data( + iButtonEditableData* editable_data, + iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + editable_data->ptr = data->rom_data.bytes; + editable_data->size = sizeof(DallasCommonRomData); +} + +void dallas_ds1992_apply_edits(iButtonProtocolData* protocol_data) { + DS1992ProtocolData* data = protocol_data; + dallas_common_apply_edits(&data->rom_data, DS1992_FAMILY_CODE); +} diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.h b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.h new file mode 100644 index 00000000..5a3c45f3 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1992.h @@ -0,0 +1,5 @@ +#pragma once + +#include "protocol_dallas_base.h" + +extern const iButtonProtocolDallasBase ibutton_protocol_ds1992; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.c b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.c new file mode 100644 index 00000000..e69145c5 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.c @@ -0,0 +1,212 @@ +#include "protocol_ds1996.h" + +#include +#include + +#include "dallas_common.h" + +#define DS1996_FAMILY_CODE 0x0CU +#define DS1996_FAMILY_NAME "DS1996" + +#define DS1996_SRAM_DATA_SIZE 8192U +#define DS1996_SRAM_PAGE_SIZE 32U +#define DS1996_COPY_SCRATCH_TIMEOUT_US 100U + +#define DS1996_DATA_BYTE_COUNT 4U + +#define DS1996_SRAM_DATA_KEY "Sram Data" + +typedef struct { + OneWireSlave* bus; + DallasCommonCommandState command_state; +} DS1996ProtocolState; + +typedef struct { + DallasCommonRomData rom_data; + uint8_t sram_data[DS1996_SRAM_DATA_SIZE]; + DS1996ProtocolState state; +} DS1996ProtocolData; + +static bool dallas_ds1996_read(OneWireHost*, void*); +static bool dallas_ds1996_write_copy(OneWireHost*, iButtonProtocolData*); +static void dallas_ds1996_emulate(OneWireSlave*, iButtonProtocolData*); +static bool dallas_ds1996_load(FlipperFormat*, uint32_t, iButtonProtocolData*); +static bool dallas_ds1996_save(FlipperFormat*, const iButtonProtocolData*); +static void dallas_ds1996_render_data(FuriString*, const iButtonProtocolData*); +static void dallas_ds1996_render_brief_data(FuriString*, const iButtonProtocolData*); +static void dallas_ds1996_render_error(FuriString*, const iButtonProtocolData*); +static bool dallas_ds1996_is_data_valid(const iButtonProtocolData*); +static void dallas_ds1996_get_editable_data(iButtonEditableData*, iButtonProtocolData*); +static void dallas_ds1996_apply_edits(iButtonProtocolData*); + +const iButtonProtocolDallasBase ibutton_protocol_ds1996 = { + .family_code = DS1996_FAMILY_CODE, + .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteCopy, + .data_size = sizeof(DS1996ProtocolData), + .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, + .name = DS1996_FAMILY_NAME, + + .read = dallas_ds1996_read, + .write_blank = NULL, /* Data too big for known blanks */ + .write_copy = dallas_ds1996_write_copy, + .emulate = dallas_ds1996_emulate, + .save = dallas_ds1996_save, + .load = dallas_ds1996_load, + .render_data = dallas_ds1996_render_data, + .render_brief_data = dallas_ds1996_render_brief_data, + .render_error = dallas_ds1996_render_error, + .is_valid = dallas_ds1996_is_data_valid, + .get_editable_data = dallas_ds1996_get_editable_data, + .apply_edits = dallas_ds1996_apply_edits, +}; + +bool dallas_ds1996_read(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data) && + dallas_common_read_mem(host, 0, data->sram_data, DS1996_SRAM_DATA_SIZE); +} + +bool dallas_ds1996_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + return dallas_common_write_mem( + host, + DS1996_COPY_SCRATCH_TIMEOUT_US, + DS1996_SRAM_PAGE_SIZE, + data->sram_data, + DS1996_SRAM_DATA_SIZE); +} + +static void dallas_ds1996_reset_callback(void* context) { + furi_assert(context); + DS1996ProtocolData* data = context; + data->state.command_state = DallasCommonCommandStateIdle; +} + +static bool dallas_ds1996_command_callback(uint8_t command, void* context) { + furi_assert(context); + DS1996ProtocolData* data = context; + OneWireSlave* bus = data->state.bus; + + switch(command) { + case DALLAS_COMMON_CMD_SEARCH_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + return dallas_common_emulate_search_rom(bus, &data->rom_data); + + } else if(data->state.command_state == DallasCommonCommandStateRomCmd) { + data->state.command_state = DallasCommonCommandStateMemCmd; + dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE); + return false; + + } else { + return false; + } + + case DALLAS_COMMON_CMD_READ_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + return dallas_common_emulate_read_rom(bus, &data->rom_data); + } else { + return false; + } + + case DALLAS_COMMON_CMD_SKIP_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + return true; + } else { + return false; + } + + case DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM: + case DALLAS_COMMON_CMD_OVERDRIVE_MATCH_ROM: + /* TODO: Overdrive mode support */ + default: + return false; + } +} + +void dallas_ds1996_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + data->state.bus = bus; + + onewire_slave_set_reset_callback(bus, dallas_ds1996_reset_callback, protocol_data); + onewire_slave_set_command_callback(bus, dallas_ds1996_command_callback, protocol_data); +} + +bool dallas_ds1996_load( + FlipperFormat* ff, + uint32_t format_version, + iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + bool success = false; + + do { + if(format_version < 2) break; + if(!dallas_common_load_rom_data(ff, format_version, &data->rom_data)) break; + if(!flipper_format_read_hex( + ff, DS1996_SRAM_DATA_KEY, data->sram_data, DS1996_SRAM_DATA_SIZE)) + break; + success = true; + } while(false); + + return success; +} + +bool dallas_ds1996_save(FlipperFormat* ff, const iButtonProtocolData* protocol_data) { + const DS1996ProtocolData* data = protocol_data; + bool success = false; + + do { + if(!dallas_common_save_rom_data(ff, &data->rom_data)) break; + if(!flipper_format_write_hex( + ff, DS1996_SRAM_DATA_KEY, data->sram_data, DS1996_SRAM_DATA_SIZE)) + break; + success = true; + } while(false); + + return success; +} + +void dallas_ds1996_render_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1996ProtocolData* data = protocol_data; + + pretty_format_bytes_hex_canonical( + result, + DS1996_DATA_BYTE_COUNT, + PRETTY_FORMAT_FONT_MONOSPACE, + data->sram_data, + DS1996_SRAM_DATA_SIZE); +} + +void dallas_ds1996_render_brief_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1996ProtocolData* data = protocol_data; + dallas_common_render_brief_data( + result, &data->rom_data, data->sram_data, DS1996_SRAM_DATA_SIZE); +} + +void dallas_ds1996_render_error(FuriString* result, const iButtonProtocolData* protocol_data) { + const DS1996ProtocolData* data = protocol_data; + + if(!dallas_common_is_valid_crc(&data->rom_data)) { + dallas_common_render_crc_error(result, &data->rom_data); + } +} + +bool dallas_ds1996_is_data_valid(const iButtonProtocolData* protocol_data) { + const DS1996ProtocolData* data = protocol_data; + return dallas_common_is_valid_crc(&data->rom_data); +} + +void dallas_ds1996_get_editable_data( + iButtonEditableData* editable_data, + iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + editable_data->ptr = data->rom_data.bytes; + editable_data->size = sizeof(DallasCommonRomData); +} + +void dallas_ds1996_apply_edits(iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + dallas_common_apply_edits(&data->rom_data, DS1996_FAMILY_CODE); +} diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.h b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.h new file mode 100644 index 00000000..34546985 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds1996.h @@ -0,0 +1,5 @@ +#pragma once + +#include "protocol_dallas_base.h" + +extern const iButtonProtocolDallasBase ibutton_protocol_ds1996; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.c b/lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.c new file mode 100644 index 00000000..50fd0451 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.c @@ -0,0 +1,133 @@ +#include "protocol_ds_generic.h" + +#include +#include + +#include "dallas_common.h" + +#include "../blanks/tm2004.h" + +#define DALLAS_GENERIC_FAMILY_CODE 0x00U +#define DALLAS_GENERIC_FAMILY_NAME "DSGeneric" + +typedef struct { + OneWireSlave* bus; +} DallasGenericProtocolState; + +typedef struct { + DallasCommonRomData rom_data; + DallasGenericProtocolState state; +} DallasGenericProtocolData; + +static bool ds_generic_read(OneWireHost*, iButtonProtocolData*); +static bool ds_generic_write_blank(OneWireHost*, iButtonProtocolData*); +static void ds_generic_emulate(OneWireSlave*, iButtonProtocolData*); +static bool ds_generic_load(FlipperFormat*, uint32_t, iButtonProtocolData*); +static bool ds_generic_save(FlipperFormat*, const iButtonProtocolData*); +static void ds_generic_render_brief_data(FuriString*, const iButtonProtocolData*); +static void ds_generic_render_error(FuriString*, const iButtonProtocolData*); +static bool ds_generic_is_data_valid(const iButtonProtocolData*); +static void ds_generic_get_editable_data(iButtonEditableData*, iButtonProtocolData*); +static void ds_generic_apply_edits(iButtonProtocolData*); + +const iButtonProtocolDallasBase ibutton_protocol_ds_generic = { + .family_code = DALLAS_GENERIC_FAMILY_CODE, + .features = iButtonProtocolFeatureWriteBlank, + .data_size = sizeof(DallasGenericProtocolData), + .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, + .name = DALLAS_GENERIC_FAMILY_NAME, + + .read = ds_generic_read, + .write_blank = ds_generic_write_blank, + .write_copy = NULL, /* No data to write a copy */ + .emulate = ds_generic_emulate, + .save = ds_generic_save, + .load = ds_generic_load, + .render_data = NULL, /* No data to render */ + .render_brief_data = ds_generic_render_brief_data, + .render_error = ds_generic_render_error, + .is_valid = ds_generic_is_data_valid, + .get_editable_data = ds_generic_get_editable_data, + .apply_edits = ds_generic_apply_edits, +}; + +bool ds_generic_read(OneWireHost* host, iButtonProtocolData* protocol_data) { + DallasGenericProtocolData* data = protocol_data; + return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data); +} + +bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { + DallasGenericProtocolData* data = protocol_data; + return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); +} + +static bool ds_generic_command_callback(uint8_t command, void* context) { + furi_assert(context); + DallasGenericProtocolData* data = context; + OneWireSlave* bus = data->state.bus; + + switch(command) { + case DALLAS_COMMON_CMD_SEARCH_ROM: + dallas_common_emulate_search_rom(bus, &data->rom_data); + break; + case DALLAS_COMMON_CMD_READ_ROM: + dallas_common_emulate_read_rom(bus, &data->rom_data); + break; + default: + break; + } + + // No support for multiple consecutive commands + return false; +} + +void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { + DallasGenericProtocolData* data = protocol_data; + data->state.bus = bus; + + onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data); +} + +bool ds_generic_save(FlipperFormat* ff, const iButtonProtocolData* protocol_data) { + const DallasGenericProtocolData* data = protocol_data; + return dallas_common_save_rom_data(ff, &data->rom_data); +} + +bool ds_generic_load( + FlipperFormat* ff, + uint32_t format_version, + iButtonProtocolData* protocol_data) { + DallasGenericProtocolData* data = protocol_data; + return dallas_common_load_rom_data(ff, format_version, &data->rom_data); +} + +void ds_generic_render_brief_data(FuriString* result, const iButtonProtocolData* protocol_data) { + const DallasGenericProtocolData* data = protocol_data; + + for(size_t i = 0; i < sizeof(DallasCommonRomData); ++i) { + furi_string_cat_printf(result, "%02X ", data->rom_data.bytes[i]); + } +} + +void ds_generic_render_error(FuriString* result, const iButtonProtocolData* protocol_data) { + UNUSED(result); + UNUSED(protocol_data); +} + +bool ds_generic_is_data_valid(const iButtonProtocolData* protocol_data) { + UNUSED(protocol_data); + return true; +} + +void ds_generic_get_editable_data( + iButtonEditableData* editable_data, + iButtonProtocolData* protocol_data) { + DallasGenericProtocolData* data = protocol_data; + editable_data->ptr = data->rom_data.bytes; + editable_data->size = sizeof(DallasCommonRomData); +} + +void ds_generic_apply_edits(iButtonProtocolData* protocol_data) { + UNUSED(protocol_data); +} diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.h b/lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.h new file mode 100644 index 00000000..008f8a67 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_ds_generic.h @@ -0,0 +1,5 @@ +#pragma once + +#include "protocol_dallas_base.h" + +extern const iButtonProtocolDallasBase ibutton_protocol_ds_generic; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.c b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.c new file mode 100644 index 00000000..d0ffa511 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.c @@ -0,0 +1,310 @@ +#include "protocol_group_dallas.h" + +#include + +#include "protocol_group_dallas_defs.h" + +#define IBUTTON_ONEWIRE_ROM_SIZE 8U + +typedef struct { + OneWireHost* host; + OneWireSlave* bus; +} iButtonProtocolGroupDallas; + +static iButtonProtocolGroupDallas* ibutton_protocol_group_dallas_alloc() { + iButtonProtocolGroupDallas* group = malloc(sizeof(iButtonProtocolGroupDallas)); + + group->host = onewire_host_alloc(&ibutton_gpio); + group->bus = onewire_slave_alloc(&ibutton_gpio); + + return group; +} + +static void ibutton_protocol_group_dallas_free(iButtonProtocolGroupDallas* group) { + onewire_slave_free(group->bus); + onewire_host_free(group->host); + free(group); +} + +static size_t ibutton_protocol_group_dallas_get_max_data_size(iButtonProtocolGroupDallas* group) { + UNUSED(group); + size_t max_data_size = 0; + + for(iButtonProtocolLocalId i = 0; i < iButtonProtocolDSMax; ++i) { + const size_t current_rom_size = ibutton_protocols_dallas[i]->data_size; + if(current_rom_size > max_data_size) { + max_data_size = current_rom_size; + } + } + + return max_data_size; +} + +static bool ibutton_protocol_group_dallas_get_id_by_name( + iButtonProtocolGroupDallas* group, + iButtonProtocolLocalId* id, + const char* name) { + UNUSED(group); + // Handle older key files which refer to DS1990 as just "Dallas" + if(strcmp(name, "Dallas") == 0) { + *id = iButtonProtocolDS1990; + return true; + } + + for(iButtonProtocolLocalId i = 0; i < iButtonProtocolDSMax; ++i) { + if(strcmp(ibutton_protocols_dallas[i]->name, name) == 0) { + *id = i; + return true; + } + } + return false; +} + +static uint32_t ibutton_protocol_group_dallas_get_features( + iButtonProtocolGroupDallas* group, + iButtonProtocolLocalId id) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + return ibutton_protocols_dallas[id]->features; +} + +static const char* ibutton_protocol_group_dallas_get_manufacturer( + iButtonProtocolGroupDallas* group, + iButtonProtocolLocalId id) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + return ibutton_protocols_dallas[id]->manufacturer; +} + +static const char* ibutton_protocol_group_dallas_get_name( + iButtonProtocolGroupDallas* group, + iButtonProtocolLocalId id) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + return ibutton_protocols_dallas[id]->name; +} + +static iButtonProtocolLocalId + ibutton_protocol_group_dallas_get_id_by_family_code(uint8_t family_code) { + iButtonProtocolLocalId id; + + for(id = 0; id < iButtonProtocolDSGeneric; ++id) { + if(ibutton_protocols_dallas[id]->family_code == family_code) break; + } + + return id; +} + +static bool ibutton_protocol_group_dallas_read( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId* id) { + bool success = false; + uint8_t rom_data[IBUTTON_ONEWIRE_ROM_SIZE]; + OneWireHost* host = group->host; + + onewire_host_start(host); + furi_delay_ms(100); + + FURI_CRITICAL_ENTER(); + + if(onewire_host_search(host, rom_data, OneWireHostSearchModeNormal)) { + /* Considering any found 1-Wire device a success. + * It can be checked later with ibutton_key_is_valid(). */ + success = true; + + /* If a 1-Wire device was found, id is guaranteed to be + * one of the known keys or DSGeneric. */ + *id = ibutton_protocol_group_dallas_get_id_by_family_code(rom_data[0]); + ibutton_protocols_dallas[*id]->read(host, data); + } + + onewire_host_reset_search(host); + onewire_host_stop(host); + + FURI_CRITICAL_EXIT(); + + return success; +} + +static bool ibutton_protocol_group_dallas_write_blank( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + furi_assert(id < iButtonProtocolDSMax); + const iButtonProtocolDallasBase* protocol = ibutton_protocols_dallas[id]; + furi_assert(protocol->features & iButtonProtocolFeatureWriteBlank); + + OneWireHost* host = group->host; + + onewire_host_start(host); + furi_delay_ms(100); + + FURI_CRITICAL_ENTER(); + + const bool success = protocol->write_blank(host, data); + onewire_host_stop(host); + + FURI_CRITICAL_EXIT(); + return success; +} + +static bool ibutton_protocol_group_dallas_write_copy( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + furi_assert(id < iButtonProtocolDSMax); + + const iButtonProtocolDallasBase* protocol = ibutton_protocols_dallas[id]; + furi_assert(protocol->features & iButtonProtocolFeatureWriteCopy); + + OneWireHost* host = group->host; + + onewire_host_start(host); + furi_delay_ms(100); + + FURI_CRITICAL_ENTER(); + + const bool success = protocol->write_copy(host, data); + onewire_host_stop(host); + + FURI_CRITICAL_EXIT(); + return success; +} + +static void ibutton_protocol_group_dallas_emulate_start( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + furi_assert(id < iButtonProtocolDSMax); + OneWireSlave* bus = group->bus; + ibutton_protocols_dallas[id]->emulate(bus, data); + onewire_slave_start(bus); +} + +static void ibutton_protocol_group_dallas_emulate_stop( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + furi_assert(id < iButtonProtocolDSMax); + UNUSED(data); + onewire_slave_stop(group->bus); +} + +static bool ibutton_protocol_group_dallas_save( + iButtonProtocolGroupDallas* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FlipperFormat* ff) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + return ibutton_protocols_dallas[id]->save(ff, data); +} + +static bool ibutton_protocol_group_dallas_load( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id, + uint32_t version, + FlipperFormat* ff) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + return ibutton_protocols_dallas[id]->load(ff, version, data); +} + +static void ibutton_protocol_group_dallas_render_data( + iButtonProtocolGroupDallas* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FuriString* result) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + const iButtonProtocolDallasBase* protocol = ibutton_protocols_dallas[id]; + furi_assert(protocol->render_data); + protocol->render_data(result, data); +} + +static void ibutton_protocol_group_dallas_render_brief_data( + iButtonProtocolGroupDallas* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FuriString* result) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + ibutton_protocols_dallas[id]->render_brief_data(result, data); +} + +static void ibutton_protocol_group_dallas_render_error( + iButtonProtocolGroupDallas* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FuriString* result) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + ibutton_protocols_dallas[id]->render_error(result, data); +} + +static bool ibutton_protocol_group_dallas_is_valid( + iButtonProtocolGroupDallas* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + return ibutton_protocols_dallas[id]->is_valid(data); +} + +static void ibutton_protocol_group_dallas_get_editable_data( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id, + iButtonEditableData* editable) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + ibutton_protocols_dallas[id]->get_editable_data(editable, data); +} + +static void ibutton_protocol_group_dallas_apply_edits( + iButtonProtocolGroupDallas* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + UNUSED(group); + furi_assert(id < iButtonProtocolDSMax); + ibutton_protocols_dallas[id]->apply_edits(data); +} + +const iButtonProtocolGroupBase ibutton_protocol_group_dallas = { + .protocol_count = iButtonProtocolDSMax, + + .alloc = (iButtonProtocolGroupAllocFunc)ibutton_protocol_group_dallas_alloc, + .free = (iButtonProtocolGroupFreeFunc)ibutton_protocol_group_dallas_free, + + .get_max_data_size = + (iButtonProtocolGropuGetSizeFunc)ibutton_protocol_group_dallas_get_max_data_size, + .get_id_by_name = (iButtonProtocolGroupGetIdFunc)ibutton_protocol_group_dallas_get_id_by_name, + .get_features = + (iButtonProtocolGroupGetFeaturesFunc)ibutton_protocol_group_dallas_get_features, + + .get_manufacturer = + (iButtonProtocolGroupGetStringFunc)ibutton_protocol_group_dallas_get_manufacturer, + .get_name = (iButtonProtocolGroupGetStringFunc)ibutton_protocol_group_dallas_get_name, + + .read = (iButtonProtocolGroupReadFunc)ibutton_protocol_group_dallas_read, + .write_blank = (iButtonProtocolGroupWriteFunc)ibutton_protocol_group_dallas_write_blank, + .write_copy = (iButtonProtocolGroupWriteFunc)ibutton_protocol_group_dallas_write_copy, + + .emulate_start = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_dallas_emulate_start, + .emulate_stop = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_dallas_emulate_stop, + + .save = (iButtonProtocolGroupSaveFunc)ibutton_protocol_group_dallas_save, + .load = (iButtonProtocolGroupLoadFunc)ibutton_protocol_group_dallas_load, + + .render_data = (iButtonProtocolGroupRenderFunc)ibutton_protocol_group_dallas_render_data, + .render_brief_data = + (iButtonProtocolGroupRenderFunc)ibutton_protocol_group_dallas_render_brief_data, + .render_error = (iButtonProtocolGroupRenderFunc)ibutton_protocol_group_dallas_render_error, + + .is_valid = (iButtonProtocolGroupIsValidFunc)ibutton_protocol_group_dallas_is_valid, + .get_editable_data = + (iButtonProtocolGroupGetDataFunc)ibutton_protocol_group_dallas_get_editable_data, + .apply_edits = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_dallas_apply_edits, +}; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.h b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.h new file mode 100644 index 00000000..d1293c71 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../protocol_group_base.h" + +extern const iButtonProtocolGroupBase ibutton_protocol_group_dallas; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c new file mode 100644 index 00000000..e54c3125 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.c @@ -0,0 +1,16 @@ +#include "protocol_group_dallas_defs.h" + +#include "protocol_ds1990.h" +#include "protocol_ds1992.h" +#include "protocol_ds1996.h" +#include "protocol_ds_generic.h" + +const iButtonProtocolDallasBase* ibutton_protocols_dallas[] = { + [iButtonProtocolDS1990] = &ibutton_protocol_ds1990, + [iButtonProtocolDS1992] = &ibutton_protocol_ds1992, + [iButtonProtocolDS1996] = &ibutton_protocol_ds1996, + /* Add new 1-Wire protocols here */ + + /* Default catch-all 1-Wire protocol */ + [iButtonProtocolDSGeneric] = &ibutton_protocol_ds_generic, +}; diff --git a/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h new file mode 100644 index 00000000..ba74c0c2 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/dallas/protocol_group_dallas_defs.h @@ -0,0 +1,16 @@ +#pragma once + +#include "protocol_dallas_base.h" + +typedef enum { + iButtonProtocolDS1990, + iButtonProtocolDS1992, + iButtonProtocolDS1996, + /* Add new 1-Wire protocols here */ + + /* Default catch-all 1-Wire protocol */ + iButtonProtocolDSGeneric, + iButtonProtocolDSMax, +} iButtonProtocolDallas; + +extern const iButtonProtocolDallasBase* ibutton_protocols_dallas[]; diff --git a/lib/one_wire/ibutton/protocols/ibutton_protocols.c b/lib/one_wire/ibutton/protocols/ibutton_protocols.c deleted file mode 100644 index b07d68b3..00000000 --- a/lib/one_wire/ibutton/protocols/ibutton_protocols.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "ibutton_protocols.h" -#include "protocol_cyfral.h" -#include "protocol_metakom.h" - -const ProtocolBase* ibutton_protocols[] = { - [iButtonProtocolCyfral] = &protocol_cyfral, - [iButtonProtocolMetakom] = &protocol_metakom, -}; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/ibutton_protocols.h b/lib/one_wire/ibutton/protocols/ibutton_protocols.h deleted file mode 100644 index cdaa3ab6..00000000 --- a/lib/one_wire/ibutton/protocols/ibutton_protocols.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "toolbox/protocols/protocol.h" - -typedef enum { - iButtonProtocolCyfral, - iButtonProtocolMetakom, - - iButtonProtocolMax, -} iButtonProtocol; - -extern const ProtocolBase* ibutton_protocols[]; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/protocol_cyfral.c b/lib/one_wire/ibutton/protocols/misc/protocol_cyfral.c similarity index 96% rename from lib/one_wire/ibutton/protocols/protocol_cyfral.c rename to lib/one_wire/ibutton/protocols/misc/protocol_cyfral.c index a5f459bc..0cdb8766 100644 --- a/lib/one_wire/ibutton/protocols/protocol_cyfral.c +++ b/lib/one_wire/ibutton/protocols/misc/protocol_cyfral.c @@ -1,5 +1,6 @@ #include #include + #include "protocol_cyfral.h" #define CYFRAL_DATA_SIZE sizeof(uint16_t) @@ -324,7 +325,13 @@ static LevelDuration protocol_cyfral_encoder_yield(ProtocolCyfral* proto) { return result; } -const ProtocolBase protocol_cyfral = { +static void protocol_cyfral_render_brief_data(ProtocolCyfral* proto, FuriString* result) { + for(size_t i = 0; i < CYFRAL_DATA_SIZE; ++i) { + furi_string_cat_printf(result, "%02X ", ((uint8_t*)&proto->data)[i]); + } +} + +const ProtocolBase ibutton_protocol_misc_cyfral = { .name = "Cyfral", .manufacturer = "Cyfral", .data_size = CYFRAL_DATA_SIZE, @@ -341,4 +348,5 @@ const ProtocolBase protocol_cyfral = { .start = (ProtocolEncoderStart)protocol_cyfral_encoder_start, .yield = (ProtocolEncoderYield)protocol_cyfral_encoder_yield, }, + .render_brief_data = (ProtocolRenderData)protocol_cyfral_render_brief_data, }; diff --git a/lib/one_wire/ibutton/protocols/misc/protocol_cyfral.h b/lib/one_wire/ibutton/protocols/misc/protocol_cyfral.h new file mode 100644 index 00000000..08b8eef8 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/misc/protocol_cyfral.h @@ -0,0 +1,4 @@ +#pragma once +#include "toolbox/protocols/protocol.h" + +extern const ProtocolBase ibutton_protocol_misc_cyfral; diff --git a/lib/one_wire/ibutton/protocols/misc/protocol_group_misc.c b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc.c new file mode 100644 index 00000000..dad1ef3c --- /dev/null +++ b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc.c @@ -0,0 +1,295 @@ +#include "protocol_group_misc.h" + +#include +#include + +#include + +#include "protocol_group_misc_defs.h" + +#define IBUTTON_MISC_READ_TIMEOUT 100 + +#define IBUTTON_MISC_DATA_KEY_KEY_COMMON "Data" + +typedef struct { + ProtocolDict* dict; + ProtocolId emulate_id; +} iButtonProtocolGroupMisc; + +static iButtonProtocolGroupMisc* ibutton_protocol_group_misc_alloc() { + iButtonProtocolGroupMisc* group = malloc(sizeof(iButtonProtocolGroupMisc)); + + group->dict = protocol_dict_alloc(ibutton_protocols_misc, iButtonProtocolMiscMax); + group->emulate_id = PROTOCOL_NO; + + return group; +} + +static void ibutton_protocol_group_misc_free(iButtonProtocolGroupMisc* group) { + protocol_dict_free(group->dict); + free(group); +} + +static size_t ibutton_protocol_group_misc_get_max_data_size(iButtonProtocolGroupMisc* group) { + return protocol_dict_get_max_data_size(group->dict); +} + +static bool ibutton_protocol_group_misc_get_id_by_name( + iButtonProtocolGroupMisc* group, + iButtonProtocolLocalId* id, + const char* name) { + const ProtocolId found_id = protocol_dict_get_protocol_by_name(group->dict, name); + + if(found_id != PROTOCOL_NO) { + *id = found_id; + return true; + } + return false; +} + +static uint32_t ibutton_protocol_group_misc_get_features( + iButtonProtocolGroupMisc* group, + iButtonProtocolLocalId id) { + UNUSED(group); + UNUSED(id); + return 0; +} + +static const char* ibutton_protocol_group_misc_get_manufacturer( + iButtonProtocolGroupMisc* group, + iButtonProtocolLocalId id) { + return protocol_dict_get_manufacturer(group->dict, id); +} + +static const char* ibutton_protocol_group_misc_get_name( + iButtonProtocolGroupMisc* group, + iButtonProtocolLocalId id) { + return protocol_dict_get_name(group->dict, id); +} + +typedef struct { + uint32_t last_dwt_value; + FuriStreamBuffer* stream; +} iButtonReadContext; + +static void ibutton_protocols_comparator_callback(bool level, void* context) { + iButtonReadContext* read_context = context; + + uint32_t current_dwt_value = DWT->CYCCNT; + + LevelDuration data = + level_duration_make(level, current_dwt_value - read_context->last_dwt_value); + furi_stream_buffer_send(read_context->stream, &data, sizeof(LevelDuration), 0); + + read_context->last_dwt_value = current_dwt_value; +} + +static bool ibutton_protocol_group_misc_read( + iButtonProtocolGroupMisc* group, + iButtonProtocolData* data, + iButtonProtocolLocalId* id) { + bool result = false; + + protocol_dict_decoders_start(group->dict); + + furi_hal_rfid_pins_reset(); + // pulldown pull pin, we sense the signal through the analog part of the RFID schematic + furi_hal_rfid_pin_pull_pulldown(); + + iButtonReadContext read_context = { + .last_dwt_value = DWT->CYCCNT, + .stream = furi_stream_buffer_alloc(sizeof(LevelDuration) * 512, 1), + }; + + furi_hal_rfid_comp_set_callback(ibutton_protocols_comparator_callback, &read_context); + furi_hal_rfid_comp_start(); + + const uint32_t tick_start = furi_get_tick(); + + for(;;) { + LevelDuration level; + size_t ret = furi_stream_buffer_receive( + read_context.stream, &level, sizeof(LevelDuration), IBUTTON_MISC_READ_TIMEOUT); + + if((furi_get_tick() - tick_start) > IBUTTON_MISC_READ_TIMEOUT) { + break; + } + + if(ret > 0) { + ProtocolId decoded_index = protocol_dict_decoders_feed( + group->dict, level_duration_get_level(level), level_duration_get_duration(level)); + + if(decoded_index == PROTOCOL_NO) continue; + + *id = decoded_index; + + protocol_dict_get_data( + group->dict, + decoded_index, + data, + protocol_dict_get_data_size(group->dict, decoded_index)); + + result = true; + } + } + + furi_hal_rfid_comp_stop(); + furi_hal_rfid_comp_set_callback(NULL, NULL); + furi_hal_rfid_pins_reset(); + + furi_stream_buffer_free(read_context.stream); + + return result; +} + +static void ibutton_protocol_group_misc_emulate_callback(void* context) { + iButtonProtocolGroupMisc* group = context; + + const LevelDuration level_duration = + protocol_dict_encoder_yield(group->dict, group->emulate_id); + + furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level_duration)); + furi_hal_ibutton_pin_write(level_duration_get_level(level_duration)); +} + +static void ibutton_protocol_group_misc_emulate_start( + iButtonProtocolGroupMisc* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + group->emulate_id = id; + protocol_dict_set_data(group->dict, id, data, protocol_dict_get_data_size(group->dict, id)); + protocol_dict_encoder_start(group->dict, group->emulate_id); + + furi_hal_ibutton_pin_configure(); + furi_hal_ibutton_emulate_start(0, ibutton_protocol_group_misc_emulate_callback, group); +} + +static void ibutton_protocol_group_misc_emulate_stop( + iButtonProtocolGroupMisc* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + UNUSED(group); + UNUSED(data); + UNUSED(id); + furi_hal_ibutton_emulate_stop(); + furi_hal_ibutton_pin_reset(); +} + +static bool ibutton_protocol_group_misc_save( + iButtonProtocolGroupMisc* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FlipperFormat* ff) { + const size_t data_size = protocol_dict_get_data_size(group->dict, id); + return flipper_format_write_hex(ff, IBUTTON_MISC_DATA_KEY_KEY_COMMON, data, data_size); +} + +static bool ibutton_protocol_group_misc_load( + iButtonProtocolGroupMisc* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id, + uint32_t version, + FlipperFormat* ff) { + const size_t data_size = protocol_dict_get_data_size(group->dict, id); + switch(version) { + case 1: + case 2: + return flipper_format_read_hex(ff, IBUTTON_MISC_DATA_KEY_KEY_COMMON, data, data_size); + default: + return false; + } +} + +static void ibutton_protocol_group_misc_render_data( + iButtonProtocolGroupMisc* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FuriString* result) { + const size_t data_size = protocol_dict_get_data_size(group->dict, id); + protocol_dict_set_data(group->dict, id, data, data_size); + protocol_dict_render_data(group->dict, result, id); +} + +static void ibutton_protocol_group_misc_render_brief_data( + iButtonProtocolGroupMisc* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FuriString* result) { + const size_t data_size = protocol_dict_get_data_size(group->dict, id); + protocol_dict_set_data(group->dict, id, data, data_size); + protocol_dict_render_brief_data(group->dict, result, id); +} + +static void ibutton_protocol_group_misc_render_error( + iButtonProtocolGroupMisc* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id, + FuriString* result) { + UNUSED(group); + UNUSED(data); + UNUSED(id); + UNUSED(result); +} + +static bool ibutton_protocol_group_misc_is_valid( + iButtonProtocolGroupMisc* group, + const iButtonProtocolData* data, + iButtonProtocolLocalId id) { + UNUSED(group); + UNUSED(data); + UNUSED(id); + return true; +} + +static void ibutton_protocol_group_misc_get_editable_data( + iButtonProtocolGroupMisc* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id, + iButtonEditableData* editable) { + editable->ptr = data; + editable->size = protocol_dict_get_data_size(group->dict, id); +} + +static void ibutton_protocol_group_misc_apply_edits( + iButtonProtocolGroupMisc* group, + iButtonProtocolData* data, + iButtonProtocolLocalId id) { + const size_t data_size = protocol_dict_get_data_size(group->dict, id); + protocol_dict_set_data(group->dict, id, data, data_size); +} + +const iButtonProtocolGroupBase ibutton_protocol_group_misc = { + .protocol_count = iButtonProtocolMiscMax, + + .alloc = (iButtonProtocolGroupAllocFunc)ibutton_protocol_group_misc_alloc, + .free = (iButtonProtocolGroupFreeFunc)ibutton_protocol_group_misc_free, + + .get_max_data_size = + (iButtonProtocolGropuGetSizeFunc)ibutton_protocol_group_misc_get_max_data_size, + .get_id_by_name = (iButtonProtocolGroupGetIdFunc)ibutton_protocol_group_misc_get_id_by_name, + .get_features = (iButtonProtocolGroupGetFeaturesFunc)ibutton_protocol_group_misc_get_features, + + .get_manufacturer = + (iButtonProtocolGroupGetStringFunc)ibutton_protocol_group_misc_get_manufacturer, + .get_name = (iButtonProtocolGroupGetStringFunc)ibutton_protocol_group_misc_get_name, + + .read = (iButtonProtocolGroupReadFunc)ibutton_protocol_group_misc_read, + .write_blank = NULL, + .write_copy = NULL, + + .emulate_start = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_misc_emulate_start, + .emulate_stop = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_misc_emulate_stop, + + .save = (iButtonProtocolGroupSaveFunc)ibutton_protocol_group_misc_save, + .load = (iButtonProtocolGroupLoadFunc)ibutton_protocol_group_misc_load, + + .render_data = (iButtonProtocolGroupRenderFunc)ibutton_protocol_group_misc_render_data, + .render_brief_data = + (iButtonProtocolGroupRenderFunc)ibutton_protocol_group_misc_render_brief_data, + .render_error = (iButtonProtocolGroupRenderFunc)ibutton_protocol_group_misc_render_error, + + .is_valid = (iButtonProtocolGroupIsValidFunc)ibutton_protocol_group_misc_is_valid, + .get_editable_data = + (iButtonProtocolGroupGetDataFunc)ibutton_protocol_group_misc_get_editable_data, + .apply_edits = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_misc_apply_edits, +}; diff --git a/lib/one_wire/ibutton/protocols/misc/protocol_group_misc.h b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc.h new file mode 100644 index 00000000..7fde6e73 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../protocol_group_base.h" + +extern const iButtonProtocolGroupBase ibutton_protocol_group_misc; diff --git a/lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.c b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.c new file mode 100644 index 00000000..09ae0bdc --- /dev/null +++ b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.c @@ -0,0 +1,10 @@ +#include "protocol_group_misc_defs.h" + +#include "protocol_cyfral.h" +#include "protocol_metakom.h" + +const ProtocolBase* ibutton_protocols_misc[] = { + [iButtonProtocolMiscCyfral] = &ibutton_protocol_misc_cyfral, + [iButtonProtocolMiscMetakom] = &ibutton_protocol_misc_metakom, + /* Add new misc protocols here */ +}; diff --git a/lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.h b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.h new file mode 100644 index 00000000..0a7f9284 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/misc/protocol_group_misc_defs.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +typedef enum { + iButtonProtocolMiscCyfral, + iButtonProtocolMiscMetakom, + iButtonProtocolMiscMax, +} iButtonProtocolMisc; + +extern const ProtocolBase* ibutton_protocols_misc[]; diff --git a/lib/one_wire/ibutton/protocols/protocol_metakom.c b/lib/one_wire/ibutton/protocols/misc/protocol_metakom.c similarity index 96% rename from lib/one_wire/ibutton/protocols/protocol_metakom.c rename to lib/one_wire/ibutton/protocols/misc/protocol_metakom.c index ff65c667..a2bd2cf7 100644 --- a/lib/one_wire/ibutton/protocols/protocol_metakom.c +++ b/lib/one_wire/ibutton/protocols/misc/protocol_metakom.c @@ -1,5 +1,6 @@ #include #include + #include "protocol_metakom.h" #define METAKOM_DATA_SIZE sizeof(uint32_t) @@ -300,7 +301,13 @@ static LevelDuration protocol_metakom_encoder_yield(ProtocolMetakom* proto) { return result; } -const ProtocolBase protocol_metakom = { +static void protocol_metakom_render_brief_data(ProtocolMetakom* proto, FuriString* result) { + for(size_t i = 0; i < METAKOM_DATA_SIZE; ++i) { + furi_string_cat_printf(result, "%02X ", ((uint8_t*)&proto->data)[i]); + } +} + +const ProtocolBase ibutton_protocol_misc_metakom = { .name = "Metakom", .manufacturer = "Metakom", .data_size = METAKOM_DATA_SIZE, @@ -317,4 +324,5 @@ const ProtocolBase protocol_metakom = { .start = (ProtocolEncoderStart)protocol_metakom_encoder_start, .yield = (ProtocolEncoderYield)protocol_metakom_encoder_yield, }, + .render_brief_data = (ProtocolRenderData)protocol_metakom_render_brief_data, }; diff --git a/lib/one_wire/ibutton/protocols/misc/protocol_metakom.h b/lib/one_wire/ibutton/protocols/misc/protocol_metakom.h new file mode 100644 index 00000000..317619e3 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/misc/protocol_metakom.h @@ -0,0 +1,4 @@ +#pragma once +#include "toolbox/protocols/protocol.h" + +extern const ProtocolBase ibutton_protocol_misc_metakom; diff --git a/lib/one_wire/ibutton/protocols/protocol_common.h b/lib/one_wire/ibutton/protocols/protocol_common.h new file mode 100644 index 00000000..5383158e --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_common.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +typedef int32_t iButtonProtocolId; + +enum { + iButtonProtocolIdInvalid = -1, +}; + +typedef enum { + iButtonProtocolFeatureExtData = (1U << 0), + iButtonProtocolFeatureWriteBlank = (1U << 1), + iButtonProtocolFeatureWriteCopy = (1U << 2), +} iButtonProtocolFeature; + +typedef struct { + uint8_t* ptr; + size_t size; +} iButtonEditableData; diff --git a/lib/one_wire/ibutton/protocols/protocol_common_i.h b/lib/one_wire/ibutton/protocols/protocol_common_i.h new file mode 100644 index 00000000..b80c9288 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_common_i.h @@ -0,0 +1,6 @@ +#pragma once + +#include "protocol_common.h" + +typedef void iButtonProtocolData; +typedef int32_t iButtonProtocolLocalId; diff --git a/lib/one_wire/ibutton/protocols/protocol_cyfral.h b/lib/one_wire/ibutton/protocols/protocol_cyfral.h deleted file mode 100644 index 97a98e48..00000000 --- a/lib/one_wire/ibutton/protocols/protocol_cyfral.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "toolbox/protocols/protocol.h" - -extern const ProtocolBase protocol_cyfral; \ No newline at end of file diff --git a/lib/one_wire/ibutton/protocols/protocol_group_base.h b/lib/one_wire/ibutton/protocols/protocol_group_base.h new file mode 100644 index 00000000..c8fec70f --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_group_base.h @@ -0,0 +1,104 @@ +#pragma once + +#include +#include + +#include "protocol_common_i.h" + +typedef void iButtonProtocolGroupData; +typedef int32_t iButtonProtocolGroupId; + +typedef iButtonProtocolGroupData* (*iButtonProtocolGroupAllocFunc)(void); + +typedef void (*iButtonProtocolGroupFreeFunc)(iButtonProtocolGroupData*); + +typedef void (*iButtonProtocolGroupRenderFunc)( + iButtonProtocolGroupData*, + const iButtonProtocolData*, + iButtonProtocolLocalId, + FuriString*); + +typedef bool (*iButtonProtocolGroupIsValidFunc)( + iButtonProtocolGroupData*, + const iButtonProtocolData*, + iButtonProtocolLocalId); + +typedef void (*iButtonProtocolGroupGetDataFunc)( + iButtonProtocolGroupData*, + iButtonProtocolData*, + iButtonProtocolLocalId, + iButtonEditableData*); + +typedef void (*iButtonProtocolGroupApplyFunc)( + iButtonProtocolGroupData*, + iButtonProtocolData*, + iButtonProtocolLocalId); + +typedef size_t (*iButtonProtocolGropuGetSizeFunc)(iButtonProtocolGroupData*); + +typedef uint32_t ( + *iButtonProtocolGroupGetFeaturesFunc)(iButtonProtocolGroupData*, iButtonProtocolLocalId); + +typedef const char* ( + *iButtonProtocolGroupGetStringFunc)(iButtonProtocolGroupData*, iButtonProtocolLocalId); + +typedef bool (*iButtonProtocolGroupGetIdFunc)( + iButtonProtocolGroupData*, + iButtonProtocolLocalId*, + const char*); + +typedef bool (*iButtonProtocolGroupReadFunc)( + iButtonProtocolGroupData*, + iButtonProtocolData*, + iButtonProtocolLocalId*); + +typedef bool (*iButtonProtocolGroupWriteFunc)( + iButtonProtocolGroupData*, + iButtonProtocolData*, + iButtonProtocolLocalId); + +typedef bool (*iButtonProtocolGroupSaveFunc)( + iButtonProtocolGroupData*, + const iButtonProtocolData*, + iButtonProtocolLocalId, + FlipperFormat*); + +typedef bool (*iButtonProtocolGroupLoadFunc)( + iButtonProtocolGroupData*, + iButtonProtocolData*, + iButtonProtocolLocalId, + uint32_t, + FlipperFormat*); + +typedef struct { + const uint32_t protocol_count; + + iButtonProtocolGroupAllocFunc alloc; + iButtonProtocolGroupFreeFunc free; + + iButtonProtocolGropuGetSizeFunc get_max_data_size; + iButtonProtocolGroupGetIdFunc get_id_by_name; + iButtonProtocolGroupGetFeaturesFunc get_features; + + iButtonProtocolGroupGetStringFunc get_manufacturer; + iButtonProtocolGroupGetStringFunc get_name; + + iButtonProtocolGroupReadFunc read; + iButtonProtocolGroupWriteFunc write_blank; + iButtonProtocolGroupWriteFunc write_copy; + + iButtonProtocolGroupApplyFunc emulate_start; + iButtonProtocolGroupApplyFunc emulate_stop; + + iButtonProtocolGroupSaveFunc save; + iButtonProtocolGroupLoadFunc load; + + iButtonProtocolGroupRenderFunc render_data; + iButtonProtocolGroupRenderFunc render_brief_data; + iButtonProtocolGroupRenderFunc render_error; + + iButtonProtocolGroupIsValidFunc is_valid; + iButtonProtocolGroupGetDataFunc get_editable_data; + + iButtonProtocolGroupApplyFunc apply_edits; +} iButtonProtocolGroupBase; diff --git a/lib/one_wire/ibutton/protocols/protocol_group_defs.c b/lib/one_wire/ibutton/protocols/protocol_group_defs.c new file mode 100644 index 00000000..40a360f0 --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_group_defs.c @@ -0,0 +1,9 @@ +#include "protocol_group_defs.h" + +#include "dallas/protocol_group_dallas.h" +#include "misc/protocol_group_misc.h" + +const iButtonProtocolGroupBase* ibutton_protocol_groups[] = { + [iButtonProtocolGroupDallas] = &ibutton_protocol_group_dallas, + [iButtonProtocolGroupMisc] = &ibutton_protocol_group_misc, +}; diff --git a/lib/one_wire/ibutton/protocols/protocol_group_defs.h b/lib/one_wire/ibutton/protocols/protocol_group_defs.h new file mode 100644 index 00000000..2d41e3cb --- /dev/null +++ b/lib/one_wire/ibutton/protocols/protocol_group_defs.h @@ -0,0 +1,11 @@ +#pragma once + +#include "protocol_group_base.h" + +typedef enum { + iButtonProtocolGroupDallas, + iButtonProtocolGroupMisc, + iButtonProtocolGroupMax +} iButtonProtocolGroup; + +extern const iButtonProtocolGroupBase* ibutton_protocol_groups[]; diff --git a/lib/one_wire/ibutton/protocols/protocol_metakom.h b/lib/one_wire/ibutton/protocols/protocol_metakom.h deleted file mode 100644 index 5e44a2a8..00000000 --- a/lib/one_wire/ibutton/protocols/protocol_metakom.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "toolbox/protocols/protocol.h" - -extern const ProtocolBase protocol_metakom; \ No newline at end of file diff --git a/lib/one_wire/one_wire_device.c b/lib/one_wire/one_wire_device.c deleted file mode 100644 index d9b4955d..00000000 --- a/lib/one_wire/one_wire_device.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include "maxim_crc.h" -#include "one_wire_device.h" -#include "one_wire_slave.h" -#include "one_wire_slave_i.h" - -struct OneWireDevice { - uint8_t id_storage[8]; - OneWireSlave* bus; -}; - -OneWireDevice* onewire_device_alloc( - uint8_t id_1, - uint8_t id_2, - uint8_t id_3, - uint8_t id_4, - uint8_t id_5, - uint8_t id_6, - uint8_t id_7, - uint8_t id_8) { - OneWireDevice* device = malloc(sizeof(OneWireDevice)); - device->id_storage[0] = id_1; - device->id_storage[1] = id_2; - device->id_storage[2] = id_3; - device->id_storage[3] = id_4; - device->id_storage[4] = id_5; - device->id_storage[5] = id_6; - device->id_storage[6] = id_7; - device->id_storage[7] = id_8; - device->bus = NULL; - - return device; -} - -void onewire_device_free(OneWireDevice* device) { - if(device->bus != NULL) { - onewire_slave_detach(device->bus); - } - - free(device); -} - -void onewire_device_send_id(OneWireDevice* device) { - if(device->bus != NULL) { - onewire_slave_send(device->bus, device->id_storage, 8); - } -} - -void onewire_device_attach(OneWireDevice* device, OneWireSlave* bus) { - device->bus = bus; -} - -void onewire_device_detach(OneWireDevice* device) { - device->bus = NULL; -} - -uint8_t* onewire_device_get_id_p(OneWireDevice* device) { - return device->id_storage; -} diff --git a/lib/one_wire/one_wire_device.h b/lib/one_wire/one_wire_device.h deleted file mode 100644 index fc687c7b..00000000 --- a/lib/one_wire/one_wire_device.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file one_wire_device.h - * - * 1-Wire slave library, device interface. Currently it can only emulate ID. - */ - -#pragma once -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OneWireSlave OneWireSlave; -typedef struct OneWireDevice OneWireDevice; - -/** - * Allocate onewire device with ID - * @param id_1 - * @param id_2 - * @param id_3 - * @param id_4 - * @param id_5 - * @param id_6 - * @param id_7 - * @param id_8 - * @return OneWireDevice* - */ -OneWireDevice* onewire_device_alloc( - uint8_t id_1, - uint8_t id_2, - uint8_t id_3, - uint8_t id_4, - uint8_t id_5, - uint8_t id_6, - uint8_t id_7, - uint8_t id_8); - -/** - * Deallocate onewire device - * @param device - */ -void onewire_device_free(OneWireDevice* device); - -/** - * Send ID report, called from onewire slave - * @param device - */ -void onewire_device_send_id(OneWireDevice* device); - -/** - * Attach device to onewire slave bus - * @param device - * @param bus - */ -void onewire_device_attach(OneWireDevice* device, OneWireSlave* bus); - -/** - * Attach device from onewire slave bus - * @param device - */ -void onewire_device_detach(OneWireDevice* device); - -/** - * Get pointer to device id array - * @param device - * @return uint8_t* - */ -uint8_t* onewire_device_get_id_p(OneWireDevice* device); - -#ifdef __cplusplus -} -#endif diff --git a/lib/one_wire/one_wire_host.c b/lib/one_wire/one_wire_host.c index f3d3d3c4..0a4a79f5 100644 --- a/lib/one_wire/one_wire_host.c +++ b/lib/one_wire/one_wire_host.c @@ -116,6 +116,12 @@ void onewire_host_write(OneWireHost* host, uint8_t value) { } } +void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t count) { + for(uint16_t i = 0; i < count; ++i) { + onewire_host_write(host, buffer[i]); + } +} + void onewire_host_skip(OneWireHost* host) { onewire_host_write(host, 0xCC); } @@ -175,10 +181,10 @@ uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSea // issue the search command switch(mode) { - case CONDITIONAL_SEARCH: + case OneWireHostSearchModeConditional: onewire_host_write(host, 0xEC); break; - case NORMAL_SEARCH: + case OneWireHostSearchModeNormal: onewire_host_write(host, 0xF0); break; } diff --git a/lib/one_wire/one_wire_host.h b/lib/one_wire/one_wire_host.h index 9c01abc1..dc469904 100644 --- a/lib/one_wire/one_wire_host.h +++ b/lib/one_wire/one_wire_host.h @@ -14,8 +14,8 @@ extern "C" { #endif typedef enum { - CONDITIONAL_SEARCH = 0, /**< Search for alarmed device */ - NORMAL_SEARCH = 1, /**< Search all devices */ + OneWireHostSearchModeConditional = 0, /**< Search for alarmed device */ + OneWireHostSearchModeNormal = 1, /**< Search all devices */ } OneWireHostSearchMode; typedef struct OneWireHost OneWireHost; @@ -76,6 +76,14 @@ void onewire_host_write_bit(OneWireHost* host, bool value); */ void onewire_host_write(OneWireHost* host, uint8_t value); +/** + * Write many bytes + * @param host + * @param buffer + * @param count + */ +void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t count); + /** * Skip ROM command * @param host diff --git a/lib/one_wire/one_wire_slave.c b/lib/one_wire/one_wire_slave.c index 4b54c4f9..d1676cf3 100644 --- a/lib/one_wire/one_wire_slave.c +++ b/lib/one_wire/one_wire_slave.c @@ -1,37 +1,42 @@ #include "one_wire_slave.h" -#include "one_wire_slave_i.h" -#include "one_wire_device.h" + #include #include -#define OWS_RESET_MIN 270 -#define OWS_RESET_MAX 960 -#define OWS_PRESENCE_TIMEOUT 20 -#define OWS_PRESENCE_MIN 100 -#define OWS_PRESENCE_MAX 480 -#define OWS_MSG_HIGH_TIMEOUT 15000 -#define OWS_SLOT_MAX 135 -#define OWS_READ_MIN 20 -#define OWS_READ_MAX 60 -#define OWS_WRITE_ZERO 30 +#define ONEWIRE_TRSTL_MIN 270 /* Minimum Reset Low time */ +#define ONEWIRE_TRSTL_MAX 1200 /* Maximum Reset Low time */ + +#define ONEWIRE_TPDH_TYP 20 /* Typical Presence Detect High time */ +#define ONEWIRE_TPDL_MIN 100 /* Minimum Presence Detect Low time */ +#define ONEWIRE_TPDL_MAX 480 /* Maximum Presence Detect Low time */ + +#define ONEWIRE_TSLOT_MIN 60 /* Minimum Read/Write Slot time */ +#define ONEWIRE_TSLOT_MAX 135 /* Maximum Read/Write Slot time */ + +#define ONEWIRE_TW1L_MAX 20 /* Maximum Master Write 1 time */ +#define ONEWIRE_TRL_TMSR_MAX 30 /* Maximum Master Read Low + Read Sample time */ + +#define ONEWIRE_TH_TIMEOUT 15000 /* Maximum time before general timeout */ typedef enum { - NO_ERROR = 0, - VERY_LONG_RESET, - VERY_SHORT_RESET, - PRESENCE_LOW_ON_LINE, - AWAIT_TIMESLOT_TIMEOUT_HIGH, - INCORRECT_ONEWIRE_CMD, - FIRST_BIT_OF_BYTE_TIMEOUT, - RESET_IN_PROGRESS + OneWireSlaveErrorNone = 0, + OneWireSlaveErrorResetInProgress, + OneWireSlaveErrorPresenceConflict, + OneWireSlaveErrorInvalidCommand, + OneWireSlaveErrorTimeout, } OneWireSlaveError; struct OneWireSlave { const GpioPin* gpio_pin; OneWireSlaveError error; - OneWireDevice* device; - OneWireSlaveResultCallback result_cb; - void* result_cb_ctx; + + OneWireSlaveResetCallback reset_callback; + OneWireSlaveCommandCallback command_callback; + OneWireSlaveResultCallback result_callback; + + void* reset_callback_context; + void* result_callback_context; + void* command_callback_context; }; /*********************** PRIVATE ***********************/ @@ -55,180 +60,94 @@ static uint32_t } static bool onewire_slave_show_presence(OneWireSlave* bus) { + // wait until the bus is high (might return immediately) + onewire_slave_wait_while_gpio_is(bus, ONEWIRE_TRSTL_MAX, false); // wait while master delay presence check - onewire_slave_wait_while_gpio_is(bus, OWS_PRESENCE_TIMEOUT, true); + furi_delay_us(ONEWIRE_TPDH_TYP); // show presence furi_hal_gpio_write(bus->gpio_pin, false); - furi_delay_us(OWS_PRESENCE_MIN); + furi_delay_us(ONEWIRE_TPDL_MIN); furi_hal_gpio_write(bus->gpio_pin, true); // somebody also can show presence - const uint32_t wait_low_time = OWS_PRESENCE_MAX - OWS_PRESENCE_MIN; + const uint32_t wait_low_time = ONEWIRE_TPDL_MAX - ONEWIRE_TPDL_MIN; // so we will wait if(onewire_slave_wait_while_gpio_is(bus, wait_low_time, false) == 0) { - bus->error = PRESENCE_LOW_ON_LINE; + bus->error = OneWireSlaveErrorPresenceConflict; return false; } return true; } -static bool onewire_slave_receive_bit(OneWireSlave* bus) { - // wait while bus is low - uint32_t time = OWS_SLOT_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - if(time == 0) { - bus->error = RESET_IN_PROGRESS; - return false; - } - - // wait while bus is high - time = OWS_MSG_HIGH_TIMEOUT; - time = onewire_slave_wait_while_gpio_is(bus, time, true); - if(time == 0) { - bus->error = AWAIT_TIMESLOT_TIMEOUT_HIGH; - return false; - } - - // wait a time of zero - time = OWS_READ_MIN; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - - return (time > 0); -} - -static bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { - const bool write_zero = !value; - - // wait while bus is low - uint32_t time = OWS_SLOT_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - if(time == 0) { - bus->error = RESET_IN_PROGRESS; - return false; - } - - // wait while bus is high - time = OWS_MSG_HIGH_TIMEOUT; - time = onewire_slave_wait_while_gpio_is(bus, time, true); - if(time == 0) { - bus->error = AWAIT_TIMESLOT_TIMEOUT_HIGH; - return false; - } - - // choose write time - if(write_zero) { - furi_hal_gpio_write(bus->gpio_pin, false); - time = OWS_WRITE_ZERO; - } else { - time = OWS_READ_MAX; - } - - // hold line for ZERO or ONE time - furi_delay_us(time); - furi_hal_gpio_write(bus->gpio_pin, true); - - return true; -} - -static void onewire_slave_cmd_search_rom(OneWireSlave* bus) { - const uint8_t key_bytes = 8; - uint8_t* key = onewire_device_get_id_p(bus->device); - - for(uint8_t i = 0; i < key_bytes; i++) { - uint8_t key_byte = key[i]; - - for(uint8_t j = 0; j < 8; j++) { - bool bit = (key_byte >> j) & 0x01; - - if(!onewire_slave_send_bit(bus, bit)) return; - if(!onewire_slave_send_bit(bus, !bit)) return; - - onewire_slave_receive_bit(bus); - if(bus->error != NO_ERROR) return; - } - } -} - -static bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) { - uint8_t cmd; - onewire_slave_receive(bus, &cmd, 1); - - if(bus->error == RESET_IN_PROGRESS) - return true; - else if(bus->error != NO_ERROR) - return false; - - switch(cmd) { - case 0xF0: - // SEARCH ROM - onewire_slave_cmd_search_rom(bus); - return true; - - case 0x0F: - case 0x33: - // READ ROM - onewire_device_send_id(bus->device); - return true; - - default: // Unknown command - bus->error = INCORRECT_ONEWIRE_CMD; - return false; - } -} - -static bool onewire_slave_bus_start(OneWireSlave* bus) { - bool result = true; - - if(bus->device == NULL) { - result = false; - } else { - FURI_CRITICAL_ENTER(); - furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - bus->error = NO_ERROR; - +static inline bool onewire_slave_receive_and_process_command(OneWireSlave* bus) { + /* Reset condition detected, send a presence pulse and reset protocol state */ + if(bus->error == OneWireSlaveErrorResetInProgress) { if(onewire_slave_show_presence(bus)) { - // TODO think about multiple command cycles - onewire_slave_receive_and_process_cmd(bus); - result = (bus->error == NO_ERROR || bus->error == INCORRECT_ONEWIRE_CMD); + bus->error = OneWireSlaveErrorNone; - } else { - result = false; + if(bus->reset_callback != NULL) { + bus->reset_callback(bus->reset_callback_context); + } + + return true; } - furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); - FURI_CRITICAL_EXIT(); + } else if(bus->error == OneWireSlaveErrorNone) { + uint8_t command; + if(!onewire_slave_receive(bus, &command, 1)) { + /* Upon failure, request an additional iteration to + choose the appropriate action by checking bus->error */ + return true; + } else if(bus->command_callback) { + return bus->command_callback(command, bus->command_callback_context); + } else { + bus->error = OneWireSlaveErrorInvalidCommand; + } } + return false; +} + +static inline bool onewire_slave_bus_start(OneWireSlave* bus) { + FURI_CRITICAL_ENTER(); + furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); + + /* Start in Reset state in order to send a presence pulse immediately */ + bus->error = OneWireSlaveErrorResetInProgress; + + while(onewire_slave_receive_and_process_command(bus)) + ; + + const bool result = (bus->error == OneWireSlaveErrorNone); + + furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); + FURI_CRITICAL_EXIT(); + return result; } -static void exti_cb(void* context) { +static void onewire_slave_exti_callback(void* context) { OneWireSlave* bus = context; - volatile bool input_state = furi_hal_gpio_read(bus->gpio_pin); + const volatile bool input_state = furi_hal_gpio_read(bus->gpio_pin); static uint32_t pulse_start = 0; if(input_state) { - uint32_t pulse_length = + const uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); - if(pulse_length >= OWS_RESET_MIN) { - if(pulse_length <= OWS_RESET_MAX) { - // reset cycle ok - bool result = onewire_slave_bus_start(bus); - if(result && bus->result_cb != NULL) { - bus->result_cb(bus->result_cb_ctx); - } - } else { - bus->error = VERY_LONG_RESET; + + if((pulse_length >= ONEWIRE_TRSTL_MIN) && pulse_length <= (ONEWIRE_TRSTL_MAX)) { + const bool result = onewire_slave_bus_start(bus); + + if(result && bus->result_callback != NULL) { + bus->result_callback(bus->result_callback_context); } - } else { - bus->error = VERY_SHORT_RESET; } + } else { - //FALL event pulse_start = DWT->CYCCNT; } }; @@ -237,11 +156,10 @@ static void exti_cb(void* context) { OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin) { OneWireSlave* bus = malloc(sizeof(OneWireSlave)); + bus->gpio_pin = gpio_pin; - bus->error = NO_ERROR; - bus->device = NULL; - bus->result_cb = NULL; - bus->result_cb_ctx = NULL; + bus->error = OneWireSlaveErrorNone; + return bus; } @@ -251,7 +169,7 @@ void onewire_slave_free(OneWireSlave* bus) { } void onewire_slave_start(OneWireSlave* bus) { - furi_hal_gpio_add_int_callback(bus->gpio_pin, exti_cb, bus); + furi_hal_gpio_add_int_callback(bus->gpio_pin, onewire_slave_exti_callback, bus); furi_hal_gpio_write(bus->gpio_pin, true); furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); } @@ -262,41 +180,98 @@ void onewire_slave_stop(OneWireSlave* bus) { furi_hal_gpio_remove_int_callback(bus->gpio_pin); } -void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device) { - bus->device = device; - onewire_device_attach(device, bus); +void onewire_slave_set_reset_callback( + OneWireSlave* bus, + OneWireSlaveResetCallback callback, + void* context) { + bus->reset_callback = callback; + bus->reset_callback_context = context; } -void onewire_slave_detach(OneWireSlave* bus) { - if(bus->device != NULL) { - onewire_device_detach(bus->device); - } - bus->device = NULL; +void onewire_slave_set_command_callback( + OneWireSlave* bus, + OneWireSlaveCommandCallback callback, + void* context) { + bus->command_callback = callback; + bus->command_callback_context = context; } void onewire_slave_set_result_callback( OneWireSlave* bus, OneWireSlaveResultCallback result_cb, void* context) { - bus->result_cb = result_cb; - bus->result_cb_ctx = context; + bus->result_callback = result_cb; + bus->result_callback_context = context; } -bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length) { - uint8_t bytes_sent = 0; +bool onewire_slave_receive_bit(OneWireSlave* bus) { + // wait while bus is low + uint32_t time = ONEWIRE_TSLOT_MAX; + time = onewire_slave_wait_while_gpio_is(bus, time, false); + if(time == 0) { + bus->error = OneWireSlaveErrorResetInProgress; + return false; + } + // wait while bus is high + time = ONEWIRE_TH_TIMEOUT; + time = onewire_slave_wait_while_gpio_is(bus, time, true); + if(time == 0) { + bus->error = OneWireSlaveErrorTimeout; + return false; + } + + // wait a time of zero + time = ONEWIRE_TW1L_MAX; + time = onewire_slave_wait_while_gpio_is(bus, time, false); + + return (time > 0); +} + +bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { + // wait while bus is low + uint32_t time = ONEWIRE_TSLOT_MAX; + time = onewire_slave_wait_while_gpio_is(bus, time, false); + if(time == 0) { + bus->error = OneWireSlaveErrorResetInProgress; + return false; + } + + // wait while bus is high + time = ONEWIRE_TH_TIMEOUT; + time = onewire_slave_wait_while_gpio_is(bus, time, true); + if(time == 0) { + bus->error = OneWireSlaveErrorTimeout; + return false; + } + + // choose write time + if(!value) { + furi_hal_gpio_write(bus->gpio_pin, false); + time = ONEWIRE_TRL_TMSR_MAX; + } else { + time = ONEWIRE_TSLOT_MIN; + } + + // hold line for ZERO or ONE time + furi_delay_us(time); furi_hal_gpio_write(bus->gpio_pin, true); + return true; +} + +bool onewire_slave_send(OneWireSlave* bus, const uint8_t* data, size_t data_size) { + furi_hal_gpio_write(bus->gpio_pin, true); + + size_t bytes_sent = 0; + // bytes loop - for(; bytes_sent < data_length; ++bytes_sent) { - const uint8_t data_byte = address[bytes_sent]; + for(; bytes_sent < data_size; ++bytes_sent) { + const uint8_t data_byte = data[bytes_sent]; // bit loop for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) { if(!onewire_slave_send_bit(bus, bit_mask & data_byte)) { - // if we cannot send first bit - if((bit_mask == 0x01) && (bus->error == AWAIT_TIMESLOT_TIMEOUT_HIGH)) - bus->error = FIRST_BIT_OF_BYTE_TIMEOUT; return false; } } @@ -304,19 +279,25 @@ bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t return true; } -bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length) { - uint8_t bytes_received = 0; - +bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size) { furi_hal_gpio_write(bus->gpio_pin, true); - for(; bytes_received < data_length; ++bytes_received) { + size_t bytes_received = 0; + + for(; bytes_received < data_size; ++bytes_received) { uint8_t value = 0; for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) { - if(onewire_slave_receive_bit(bus)) value |= bit_mask; + if(onewire_slave_receive_bit(bus)) { + value |= bit_mask; + } + + if(bus->error != OneWireSlaveErrorNone) { + return false; + } } data[bytes_received] = value; } - return (bytes_received != data_length); + return true; } diff --git a/lib/one_wire/one_wire_slave.h b/lib/one_wire/one_wire_slave.h index 2e5db3a1..914cd933 100644 --- a/lib/one_wire/one_wire_slave.h +++ b/lib/one_wire/one_wire_slave.h @@ -1,12 +1,14 @@ /** * @file one_wire_slave.h * - * 1-Wire slave library. Currently it can only emulate ID. + * 1-Wire slave library. */ #pragma once +#include #include #include + #include #ifdef __cplusplus @@ -15,7 +17,10 @@ extern "C" { typedef struct OneWireDevice OneWireDevice; typedef struct OneWireSlave OneWireSlave; + +typedef void (*OneWireSlaveResetCallback)(void* context); typedef void (*OneWireSlaveResultCallback)(void* context); +typedef bool (*OneWireSlaveCommandCallback)(uint8_t command, void* context); /** * Allocate onewire slave @@ -43,17 +48,54 @@ void onewire_slave_start(OneWireSlave* bus); void onewire_slave_stop(OneWireSlave* bus); /** - * Attach device for emulation - * @param bus - * @param device + * TODO: description comment */ -void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device); +bool onewire_slave_receive_bit(OneWireSlave* bus); /** - * Detach device from bus - * @param bus + * TODO: description comment */ -void onewire_slave_detach(OneWireSlave* bus); +bool onewire_slave_send_bit(OneWireSlave* bus, bool value); + +/** + * Send data + * @param bus + * @param data + * @param data_size + * @return bool + */ +bool onewire_slave_send(OneWireSlave* bus, const uint8_t* data, size_t data_size); + +/** + * Receive data + * @param bus + * @param data + * @param data_size + * @return bool + */ +bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size); + +/** + * Set a callback to be called on each reset + * @param bus + * @param callback + * @param context + */ +void onewire_slave_set_reset_callback( + OneWireSlave* bus, + OneWireSlaveResetCallback callback, + void* context); + +/** + * Set a callback to be called on each command + * @param bus + * @param callback + * @param context + */ +void onewire_slave_set_command_callback( + OneWireSlave* bus, + OneWireSlaveCommandCallback callback, + void* context); /** * Set a callback to report emulation success diff --git a/lib/one_wire/one_wire_slave_i.h b/lib/one_wire/one_wire_slave_i.h deleted file mode 100644 index 55e0762e..00000000 --- a/lib/one_wire/one_wire_slave_i.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file one_wire_slave_i.h - * - * 1-Wire slave library, internal functions - */ - -#pragma once -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OneWireDevice OneWireDevice; -typedef struct OneWireSlave OneWireSlave; - -/** - * Send data, called from emulated device - * @param bus - * @param address - * @param data_length - * @return bool - */ -bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length); - -/** - * Receive data, called from emulated device - * @param bus - * @param data - * @param data_length - * @return bool - */ -bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length); - -#ifdef __cplusplus -} -#endif diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 8ce45d25..d7b0e7bb 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -27,6 +27,7 @@ env.Append( File("stream/string_stream.h"), File("stream/buffered_file_stream.h"), File("protocols/protocol_dict.h"), + File("pretty_format.h"), ], ) diff --git a/lib/toolbox/pretty_format.c b/lib/toolbox/pretty_format.c new file mode 100644 index 00000000..d5ba1038 --- /dev/null +++ b/lib/toolbox/pretty_format.c @@ -0,0 +1,60 @@ +#include "pretty_format.h" + +#include +#include + +#define PRETTY_FORMAT_MAX_CANONICAL_DATA_SIZE 256U + +void pretty_format_bytes_hex_canonical( + FuriString* result, + size_t num_places, + const char* line_prefix, + const uint8_t* data, + size_t data_size) { + furi_assert(data); + + bool is_truncated = false; + + if(data_size > PRETTY_FORMAT_MAX_CANONICAL_DATA_SIZE) { + data_size = PRETTY_FORMAT_MAX_CANONICAL_DATA_SIZE; + is_truncated = true; + } + + /* Only num_places byte(s) can be on a single line, therefore: */ + const size_t line_count = + data_size / num_places + (data_size % num_places != 0 ? 1 : 0) + (is_truncated ? 2 : 0); + /* Line length = Prefix length + 3 * num_places (2 hex digits + space) + 1 * num_places + + + 1 pipe character + 1 newline character */ + const size_t line_length = (line_prefix ? strlen(line_prefix) : 0) + 4 * num_places + 2; + + /* Reserve memory in adance in order to avoid unnecessary reallocs */ + furi_string_reset(result); + furi_string_reserve(result, line_count * line_length); + + for(size_t i = 0; i < data_size; i += num_places) { + if(line_prefix) { + furi_string_cat(result, line_prefix); + } + + const size_t begin_idx = i; + const size_t end_idx = MIN(i + num_places, data_size); + + for(size_t j = begin_idx; j < end_idx; j++) { + furi_string_cat_printf(result, "%02X ", data[j]); + } + + furi_string_push_back(result, '|'); + + for(size_t j = begin_idx; j < end_idx; j++) { + const char c = data[j]; + const char sep = ((j < end_idx - 1) ? ' ' : '\n'); + const char* fmt = ((j < data_size - 1) ? "%c%c" : "%c"); + furi_string_cat_printf(result, fmt, (c > 0x1f && c < 0x7f) ? c : '.', sep); + } + } + + if(is_truncated) { + furi_string_cat_printf( + result, "\n(Data is too big. Showing only the first %zu bytes.)", data_size); + } +} diff --git a/lib/toolbox/pretty_format.h b/lib/toolbox/pretty_format.h new file mode 100644 index 00000000..860528e4 --- /dev/null +++ b/lib/toolbox/pretty_format.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PRETTY_FORMAT_FONT_BOLD "\e#" +#define PRETTY_FORMAT_FONT_MONOSPACE "\e*" + +/** + * Format a data buffer as a canonical HEX dump + * @param [out] result pointer to the output string (must be initialised) + * @param [in] num_places the number of bytes on one line (both as HEX and ASCII) + * @param [in] line_prefix if not NULL, prepend this string to each line + * @param [in] data pointer to the input data buffer + * @param [in] data_size input data size + */ +void pretty_format_bytes_hex_canonical( + FuriString* result, + size_t num_places, + const char* line_prefix, + const uint8_t* data, + size_t data_size); + +#ifdef __cplusplus +} +#endif diff --git a/lib/toolbox/stream/buffered_file_stream.c b/lib/toolbox/stream/buffered_file_stream.c index 3b20a391..3b485e80 100644 --- a/lib/toolbox/stream/buffered_file_stream.c +++ b/lib/toolbox/stream/buffered_file_stream.c @@ -95,6 +95,7 @@ FS_Error buffered_file_stream_get_error(Stream* _stream) { static void buffered_file_stream_free(BufferedFileStream* stream) { furi_assert(stream); + buffered_file_stream_sync((Stream*)stream); stream_free(stream->file_stream); stream_cache_free(stream->cache); free(stream); From 24f084d282430c13910983964066d197d97c493a Mon Sep 17 00:00:00 2001 From: andr0423 <40040215+andr0423@users.noreply.github.com> Date: Fri, 3 Mar 2023 12:50:15 +0300 Subject: [PATCH 04/23] Fixed music player path for dummy mode (#2454) Music player path changed #2453 --- applications/services/desktop/scenes/desktop_scene_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index befcf399..b02958b6 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -12,7 +12,7 @@ #define TAG "DesktopSrv" -#define MUSIC_PLAYER_APP EXT_PATH("/apps/Misc/music_player.fap") +#define MUSIC_PLAYER_APP EXT_PATH("/apps/Media/music_player.fap") #define SNAKE_GAME_APP EXT_PATH("/apps/Games/snake_game.fap") #define CLOCK_APP EXT_PATH("/apps/Tools/clock.fap") From fed4c28925a398aa3ff1dcf531fb027e236d1960 Mon Sep 17 00:00:00 2001 From: Milk-Cool <43724263+Milk-Cool@users.noreply.github.com> Date: Fri, 3 Mar 2023 13:01:05 +0300 Subject: [PATCH 05/23] Fixed typo in fbt.md (#2452) Co-authored-by: hedger --- documentation/fbt.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/fbt.md b/documentation/fbt.md index 65c3ee68..a4717463 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -9,8 +9,8 @@ To use `fbt`, you only need `git` installed in your system. `fbt` by default downloads and unpacks a pre-built toolchain, and then modifies environment variables for itself to use it. It does not contaminate your global system's path with the toolchain. > However, if you wish to use tools supplied with the toolchain outside `fbt`, you can open an *fbt shell*, with properly configured environment. - > - On Windows, simply run `scripts/toochain/fbtenv.cmd`. - > - On Linux & MacOS, run `source scripts/toochain/fbtenv.sh` in a new shell. + > - On Windows, simply run `scripts/toolchain/fbtenv.cmd`. + > - On Linux & MacOS, run `source scripts/toolchain/fbtenv.sh` in a new shell. If your system is not supported by pre-built toolchain variants or you want to use custom versions of dependencies, you can `set FBT_NOENV=1`. `fbt` will skip toolchain & environment configuration and will expect all tools to be available on your system's `PATH`. *(this option is not available on Windows)* From 42d27d04f60977d5bf267b86eca0aee6c22a5c2d Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Fri, 3 Mar 2023 12:55:51 +0200 Subject: [PATCH 06/23] [FL-3127] Fix navigation on unsupported card types (#2440) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/nfc/scenes/nfc_scene_read_card_success.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_success.c b/applications/main/nfc/scenes/nfc_scene_read_card_success.c index 9b2a2188..ee80ee76 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_success.c @@ -46,6 +46,9 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc->scene_manager); } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); } return consumed; } From 6cc5119c648b0690f915e703d7d7fc71f6f554ec Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 3 Mar 2023 15:37:02 +0300 Subject: [PATCH 07/23] [FL-3117] Infrared: Fix hangups on repeated button press (#2441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/infrared/infrared.c | 21 +++++++++++++-------- applications/main/infrared/infrared_i.h | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index 9d78a09b..4f450496 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -3,6 +3,8 @@ #include #include +#define INFRARED_TX_MIN_INTERVAL_MS 50U + static const NotificationSequence* infrared_notification_sequences[] = { &sequence_success, &sequence_set_only_green_255, @@ -299,10 +301,13 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) { void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { if(infrared->app_state.is_transmitting) { - FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active"); return; - } else { - infrared->app_state.is_transmitting = true; + } + + const uint32_t time_elapsed = furi_get_tick() - infrared->app_state.last_transmit_time; + + if(time_elapsed < INFRARED_TX_MIN_INTERVAL_MS) { + return; } if(infrared_signal_is_raw(signal)) { @@ -319,6 +324,8 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { infrared_worker_tx_set_get_signal_callback( infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); infrared_worker_tx_start(infrared->worker); + + infrared->app_state.is_transmitting = true; } void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { @@ -328,26 +335,24 @@ void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { InfraredSignal* signal = infrared_remote_button_get_signal(button); infrared_tx_start_signal(infrared, signal); - infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); } void infrared_tx_start_received(Infrared* infrared) { infrared_tx_start_signal(infrared, infrared->received_signal); - infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); } void infrared_tx_stop(Infrared* infrared) { if(!infrared->app_state.is_transmitting) { - FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped"); return; - } else { - infrared->app_state.is_transmitting = false; } infrared_worker_tx_stop(infrared->worker); infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); + + infrared->app_state.is_transmitting = false; + infrared->app_state.last_transmit_time = furi_get_tick(); } void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { diff --git a/applications/main/infrared/infrared_i.h b/applications/main/infrared/infrared_i.h index 5b555e4b..9e65c2b1 100644 --- a/applications/main/infrared/infrared_i.h +++ b/applications/main/infrared/infrared_i.h @@ -69,6 +69,7 @@ typedef struct { InfraredEditTarget edit_target : 8; InfraredEditMode edit_mode : 8; int32_t current_button_index; + uint32_t last_transmit_time; } InfraredAppState; struct Infrared { From 72ca6b25e9b4454927cc286d3c968f1f97771b01 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Fri, 3 Mar 2023 19:09:13 +0400 Subject: [PATCH 08/23] [FL-3106] SubGhz: better and more verbose error handling in protocols, stricter CAME validation (#2443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add error protocol * WS: add error protocol * SubGhz: error processing * SubGhz: more stringent CAME protocol restrictions * SubGhz: fix header duration CAME protocol * SubGhz: delete comments * SubGhz: sync SubGhzProtocolStatus with FuriStatus * SubGhz: update documentation and bump api_version Co-authored-by: あく --- .../main/subghz/helpers/subghz_types.h | 1 + .../scenes/subghz_scene_receiver_info.c | 3 +- .../subghz/scenes/subghz_scene_set_type.c | 5 +- .../subghz/scenes/subghz_scene_transmitter.c | 38 +++++----- applications/main/subghz/subghz_i.c | 21 ++++-- .../helpers/weather_station_types.h | 2 +- .../protocols/acurite_592txr.c | 22 ++---- .../protocols/acurite_592txr.h | 9 +-- .../weather_station/protocols/acurite_606tx.c | 22 ++---- .../weather_station/protocols/acurite_606tx.h | 9 +-- .../protocols/acurite_609txc.c | 22 ++---- .../protocols/acurite_609txc.h | 9 +-- .../protocols/ambient_weather.c | 22 ++---- .../protocols/ambient_weather.h | 9 +-- .../protocols/auriol_hg0601a.c | 20 ++---- .../protocols/auriol_hg0601a.h | 9 +-- .../weather_station/protocols/gt_wt_02.c | 20 ++---- .../weather_station/protocols/gt_wt_02.h | 9 +-- .../weather_station/protocols/gt_wt_03.c | 20 ++---- .../weather_station/protocols/gt_wt_03.h | 9 +-- .../weather_station/protocols/infactory.c | 20 ++---- .../weather_station/protocols/infactory.h | 9 +-- .../weather_station/protocols/lacrosse_tx.c | 20 ++---- .../weather_station/protocols/lacrosse_tx.h | 9 +-- .../protocols/lacrosse_tx141thbv2.c | 21 ++---- .../protocols/lacrosse_tx141thbv2.h | 8 +-- .../weather_station/protocols/nexus_th.c | 20 ++---- .../weather_station/protocols/nexus_th.h | 9 +-- .../weather_station/protocols/oregon2.c | 24 ++++--- .../weather_station/protocols/oregon_v1.c | 20 ++---- .../weather_station/protocols/oregon_v1.h | 9 +-- .../weather_station/protocols/thermopro_tx4.c | 22 ++---- .../weather_station/protocols/thermopro_tx4.h | 9 +-- .../weather_station/protocols/tx_8300.c | 19 ++--- .../weather_station/protocols/tx_8300.h | 9 +-- .../weather_station/protocols/ws_generic.c | 57 +++++++++++++-- .../weather_station/protocols/ws_generic.h | 21 ++++-- firmware/targets/f18/api_symbols.csv | 2 +- firmware/targets/f7/api_symbols.csv | 17 ++--- lib/subghz/blocks/generic.c | 43 ++++++++++-- lib/subghz/blocks/generic.h | 21 ++++-- lib/subghz/protocols/alutech_at_4n.c | 30 ++++---- lib/subghz/protocols/alutech_at_4n.h | 11 ++- lib/subghz/protocols/ansonic.c | 43 +++++------- lib/subghz/protocols/ansonic.h | 8 ++- lib/subghz/protocols/base.c | 8 +-- lib/subghz/protocols/base.h | 8 +-- lib/subghz/protocols/bett.c | 45 +++++------- lib/subghz/protocols/bett.h | 14 ++-- lib/subghz/protocols/bin_raw.c | 48 ++++++++++--- lib/subghz/protocols/bin_raw.h | 14 ++-- lib/subghz/protocols/came.c | 69 +++++++++++++------ lib/subghz/protocols/came.h | 14 ++-- lib/subghz/protocols/came_atomo.c | 22 ++---- lib/subghz/protocols/came_atomo.h | 9 +-- lib/subghz/protocols/came_twee.c | 41 ++++------- lib/subghz/protocols/came_twee.h | 14 ++-- lib/subghz/protocols/chamberlain_code.c | 30 ++++---- lib/subghz/protocols/chamberlain_code.h | 14 ++-- lib/subghz/protocols/clemsa.c | 45 +++++------- lib/subghz/protocols/clemsa.h | 14 ++-- lib/subghz/protocols/doitrand.c | 48 ++++++------- lib/subghz/protocols/doitrand.h | 14 ++-- lib/subghz/protocols/dooya.c | 46 +++++-------- lib/subghz/protocols/dooya.h | 14 ++-- lib/subghz/protocols/faac_slh.c | 22 ++---- lib/subghz/protocols/faac_slh.h | 9 +-- lib/subghz/protocols/gate_tx.c | 46 +++++-------- lib/subghz/protocols/gate_tx.h | 14 ++-- lib/subghz/protocols/holtek.c | 46 +++++-------- lib/subghz/protocols/holtek.h | 14 ++-- lib/subghz/protocols/holtek_ht12x.c | 59 ++++++++-------- lib/subghz/protocols/holtek_ht12x.h | 14 ++-- lib/subghz/protocols/honeywell_wdb.c | 46 +++++-------- lib/subghz/protocols/honeywell_wdb.h | 18 +++-- lib/subghz/protocols/hormann.c | 46 +++++-------- lib/subghz/protocols/hormann.h | 14 ++-- lib/subghz/protocols/ido.c | 19 ++--- lib/subghz/protocols/ido.h | 9 +-- lib/subghz/protocols/intertechno_v3.c | 29 ++++---- lib/subghz/protocols/intertechno_v3.h | 12 ++-- lib/subghz/protocols/keeloq.c | 62 ++++++++--------- lib/subghz/protocols/keeloq.h | 14 ++-- lib/subghz/protocols/kia.c | 19 ++--- lib/subghz/protocols/kia.h | 9 +-- lib/subghz/protocols/kinggates_stylo_4k.c | 32 ++++----- lib/subghz/protocols/kinggates_stylo_4k.h | 8 +-- lib/subghz/protocols/linear.c | 46 +++++-------- lib/subghz/protocols/linear.h | 14 ++-- lib/subghz/protocols/linear_delta3.c | 46 +++++-------- lib/subghz/protocols/linear_delta3.h | 18 +++-- lib/subghz/protocols/magellan.c | 48 ++++++------- lib/subghz/protocols/magellan.h | 14 ++-- lib/subghz/protocols/marantec.c | 43 +++++------- lib/subghz/protocols/marantec.h | 14 ++-- lib/subghz/protocols/megacode.c | 48 ++++++------- lib/subghz/protocols/megacode.h | 14 ++-- lib/subghz/protocols/nero_radio.c | 48 ++++++------- lib/subghz/protocols/nero_radio.h | 14 ++-- lib/subghz/protocols/nero_sketch.c | 48 ++++++------- lib/subghz/protocols/nero_sketch.h | 14 ++-- lib/subghz/protocols/nice_flo.c | 31 +++++---- lib/subghz/protocols/nice_flo.h | 14 ++-- lib/subghz/protocols/nice_flor_s.c | 24 ++++--- lib/subghz/protocols/nice_flor_s.h | 9 +-- lib/subghz/protocols/phoenix_v2.c | 48 ++++++------- lib/subghz/protocols/phoenix_v2.h | 14 ++-- lib/subghz/protocols/power_smart.c | 43 +++++------- lib/subghz/protocols/power_smart.h | 14 ++-- lib/subghz/protocols/princeton.c | 62 +++++++++-------- lib/subghz/protocols/princeton.h | 14 ++-- lib/subghz/protocols/raw.c | 18 +++-- lib/subghz/protocols/raw.h | 10 +-- lib/subghz/protocols/scher_khan.c | 5 +- lib/subghz/protocols/scher_khan.h | 9 +-- lib/subghz/protocols/secplus_v1.c | 47 ++++++------- lib/subghz/protocols/secplus_v1.h | 14 ++-- lib/subghz/protocols/secplus_v2.c | 57 +++++++-------- lib/subghz/protocols/secplus_v2.h | 14 ++-- lib/subghz/protocols/smc5326.c | 62 +++++++++-------- lib/subghz/protocols/smc5326.h | 14 ++-- lib/subghz/protocols/somfy_keytis.c | 36 +++++----- lib/subghz/protocols/somfy_keytis.h | 9 +-- lib/subghz/protocols/somfy_telis.c | 22 ++---- lib/subghz/protocols/somfy_telis.h | 9 +-- lib/subghz/protocols/star_line.c | 35 ++++------ lib/subghz/protocols/star_line.h | 9 +-- lib/subghz/transmitter.c | 5 +- lib/subghz/transmitter.h | 5 +- lib/subghz/types.h | 26 ++++++- 130 files changed, 1455 insertions(+), 1507 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index abf70539..2bd2f682 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -53,6 +53,7 @@ typedef enum { SubGhzLoadKeyStateUnknown, SubGhzLoadKeyStateOK, SubGhzLoadKeyStateParseErr, + SubGhzLoadKeyStateProtocolDescriptionErr, } SubGhzLoadKeyState; /** SubGhzLock */ diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 4733b0e1..152334ad 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -22,7 +22,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( subghz->txrx->receiver, subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + if(subghz->txrx->decoder_result) { + //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->txrx->decoder_result, subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); @@ -128,7 +130,6 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz, subghz_history_get_raw_data( subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { subghz_tx_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index eaa3ccef..2134377e 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -34,8 +34,9 @@ bool subghz_scene_set_type_submenu_gen_data_protocol( do { Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); stream_clean(fff_data_stream); - if(!subghz_protocol_decoder_base_serialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset)) { + if(subghz_protocol_decoder_base_serialize( + subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != + SubGhzProtocolStatusOk) { FURI_LOG_E(TAG, "Unable to serialize"); break; } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index fbe954f0..c8663cc8 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -9,9 +9,8 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { } bool subghz_scene_transmitter_update_data_show(void* context) { - //ToDo Fix SubGhz* subghz = context; - + bool ret = false; if(subghz->txrx->decoder_result) { FuriString* key_str; FuriString* frequency_str; @@ -22,30 +21,29 @@ bool subghz_scene_transmitter_update_data_show(void* context) { modulation_str = furi_string_alloc(); uint8_t show_button = 0; - subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); + if(subghz_protocol_decoder_base_deserialize( + subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { + subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) { - show_button = 1; + if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == + SubGhzProtocolFlag_Send) { + 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(modulation_str); furi_string_free(key_str); - - return true; } - return false; + return ret; } void subghz_scene_transmitter_on_enter(void* context) { diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 7de020a5..94713ddb 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -153,7 +153,6 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { FURI_LOG_E(TAG, "Missing Protocol"); break; } - //ToDo FIX if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { FURI_LOG_E(TAG, "Unable Repeat"); break; @@ -163,7 +162,8 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { subghz->txrx->environment, furi_string_get_cstr(temp_str)); 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) { subghz_begin( subghz, @@ -186,7 +186,12 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { //Start TX furi_hal_subghz_start_async_tx( 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) { @@ -333,8 +338,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->receiver, furi_string_get_cstr(temp_str)); if(subghz->txrx->decoder_result) { - if(!subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data)) { + SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( + subghz->txrx->decoder_result, subghz->txrx->fff_data); + if(status != SubGhzProtocolStatusOk) { + load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; } } else { @@ -355,6 +362,12 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); } return false; + case SubGhzLoadKeyStateProtocolDescriptionErr: + if(show_dialog) { + dialog_message_show_storage_error( + subghz->dialogs, "Error in protocol\nparameters\ndescription"); + } + return false; case SubGhzLoadKeyStateOK: return true; diff --git a/applications/plugins/weather_station/helpers/weather_station_types.h b/applications/plugins/weather_station/helpers/weather_station_types.h index 1f5612e2..11146597 100644 --- a/applications/plugins/weather_station/helpers/weather_station_types.h +++ b/applications/plugins/weather_station/helpers/weather_station_types.h @@ -3,7 +3,7 @@ #include #include -#define WS_VERSION_APP "0.7" +#define WS_VERSION_APP "0.8" #define WS_DEVELOPED "SkorP" #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" diff --git a/applications/plugins/weather_station/protocols/acurite_592txr.c b/applications/plugins/weather_station/protocols/acurite_592txr.c index 5384a3c9..874f6dd3 100644 --- a/applications/plugins/weather_station/protocols/acurite_592txr.c +++ b/applications/plugins/weather_station/protocols/acurite_592txr.c @@ -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); } -bool ws_protocol_decoder_acurite_592txr_serialize( +SubGhzProtocolStatus ws_protocol_decoder_acurite_592txr_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -267,22 +267,14 @@ bool ws_protocol_decoder_acurite_592txr_serialize( 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); WSProtocolDecoderAcurite_592TXR* instance = context; - bool ret = false; - do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_acurite_592txr_const.min_count_bit_for_found); } void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/acurite_592txr.h b/applications/plugins/weather_station/protocols/acurite_592txr.h index ac0371d8..1071d1cf 100644 --- a/applications/plugins/weather_station/protocols/acurite_592txr.h +++ b/applications/plugins/weather_station/protocols/acurite_592txr.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_acurite_592txr_serialize( * Deserialize data WSProtocolDecoderAcurite_592TXR. * @param context Pointer to a WSProtocolDecoderAcurite_592TXR 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. diff --git a/applications/plugins/weather_station/protocols/acurite_606tx.c b/applications/plugins/weather_station/protocols/acurite_606tx.c index 4cb5d18b..e0d405c6 100644 --- a/applications/plugins/weather_station/protocols/acurite_606tx.c +++ b/applications/plugins/weather_station/protocols/acurite_606tx.c @@ -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); } -bool ws_protocol_decoder_acurite_606tx_serialize( +SubGhzProtocolStatus ws_protocol_decoder_acurite_606tx_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -208,22 +208,14 @@ bool ws_protocol_decoder_acurite_606tx_serialize( 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); WSProtocolDecoderAcurite_606TX* instance = context; - bool ret = false; - do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_acurite_606tx_const.min_count_bit_for_found); } void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/acurite_606tx.h b/applications/plugins/weather_station/protocols/acurite_606tx.h index 5bab3bcb..15b6d1eb 100644 --- a/applications/plugins/weather_station/protocols/acurite_606tx.h +++ b/applications/plugins/weather_station/protocols/acurite_606tx.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_acurite_606tx_serialize( * Deserialize data WSProtocolDecoderAcurite_606TX. * @param context Pointer to a WSProtocolDecoderAcurite_606TX 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. diff --git a/applications/plugins/weather_station/protocols/acurite_609txc.c b/applications/plugins/weather_station/protocols/acurite_609txc.c index aeb0785e..853b7844 100644 --- a/applications/plugins/weather_station/protocols/acurite_609txc.c +++ b/applications/plugins/weather_station/protocols/acurite_609txc.c @@ -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); } -bool ws_protocol_decoder_acurite_609txc_serialize( +SubGhzProtocolStatus ws_protocol_decoder_acurite_609txc_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -208,22 +208,14 @@ bool ws_protocol_decoder_acurite_609txc_serialize( 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); WSProtocolDecoderAcurite_609TXC* instance = context; - bool ret = false; - do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_acurite_609txc_const.min_count_bit_for_found); } void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/acurite_609txc.h b/applications/plugins/weather_station/protocols/acurite_609txc.h index f87c20e9..3e3b9cee 100644 --- a/applications/plugins/weather_station/protocols/acurite_609txc.h +++ b/applications/plugins/weather_station/protocols/acurite_609txc.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_acurite_609txc_serialize( * Deserialize data WSProtocolDecoderAcurite_609TXC. * @param context Pointer to a WSProtocolDecoderAcurite_609TXC 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. diff --git a/applications/plugins/weather_station/protocols/ambient_weather.c b/applications/plugins/weather_station/protocols/ambient_weather.c index e3c85f40..588a7f82 100644 --- a/applications/plugins/weather_station/protocols/ambient_weather.c +++ b/applications/plugins/weather_station/protocols/ambient_weather.c @@ -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); } -bool ws_protocol_decoder_ambient_weather_serialize( +SubGhzProtocolStatus ws_protocol_decoder_ambient_weather_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -237,22 +237,14 @@ bool ws_protocol_decoder_ambient_weather_serialize( 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); WSProtocolDecoderAmbient_Weather* instance = context; - bool ret = false; - do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_ambient_weather_const.min_count_bit_for_found); } void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/ambient_weather.h b/applications/plugins/weather_station/protocols/ambient_weather.h index 04cc5819..1694403c 100644 --- a/applications/plugins/weather_station/protocols/ambient_weather.h +++ b/applications/plugins/weather_station/protocols/ambient_weather.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_ambient_weather_serialize( * Deserialize data WSProtocolDecoderAmbient_Weather. * @param context Pointer to a WSProtocolDecoderAmbient_Weather 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. diff --git a/applications/plugins/weather_station/protocols/auriol_hg0601a.c b/applications/plugins/weather_station/protocols/auriol_hg0601a.c index d5f89fc8..813fe152 100644 --- a/applications/plugins/weather_station/protocols/auriol_hg0601a.c +++ b/applications/plugins/weather_station/protocols/auriol_hg0601a.c @@ -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); } -bool ws_protocol_decoder_auriol_th_serialize( +SubGhzProtocolStatus ws_protocol_decoder_auriol_th_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -219,22 +219,12 @@ bool ws_protocol_decoder_auriol_th_serialize( 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); WSProtocolDecoderAuriol_TH* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_auriol_th_const.min_count_bit_for_found); } void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/auriol_hg0601a.h b/applications/plugins/weather_station/protocols/auriol_hg0601a.h index c23007c1..155bb07f 100644 --- a/applications/plugins/weather_station/protocols/auriol_hg0601a.h +++ b/applications/plugins/weather_station/protocols/auriol_hg0601a.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_auriol_th_serialize( * Deserialize data WSProtocolDecoderAuriol_TH. * @param context Pointer to a WSProtocolDecoderAuriol_TH 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. diff --git a/applications/plugins/weather_station/protocols/gt_wt_02.c b/applications/plugins/weather_station/protocols/gt_wt_02.c index cbe11919..d333164b 100644 --- a/applications/plugins/weather_station/protocols/gt_wt_02.c +++ b/applications/plugins/weather_station/protocols/gt_wt_02.c @@ -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); } -bool ws_protocol_decoder_gt_wt_02_serialize( +SubGhzProtocolStatus ws_protocol_decoder_gt_wt_02_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -226,22 +226,12 @@ bool ws_protocol_decoder_gt_wt_02_serialize( 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); WSProtocolDecoderGT_WT02* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_gt_wt_02_const.min_count_bit_for_found); } void ws_protocol_decoder_gt_wt_02_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/gt_wt_02.h b/applications/plugins/weather_station/protocols/gt_wt_02.h index f17d5baa..e13576d2 100644 --- a/applications/plugins/weather_station/protocols/gt_wt_02.h +++ b/applications/plugins/weather_station/protocols/gt_wt_02.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_gt_wt_02_serialize( * Deserialize data WSProtocolDecoderGT_WT02. * @param context Pointer to a WSProtocolDecoderGT_WT02 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. diff --git a/applications/plugins/weather_station/protocols/gt_wt_03.c b/applications/plugins/weather_station/protocols/gt_wt_03.c index 7831cf06..30430b83 100644 --- a/applications/plugins/weather_station/protocols/gt_wt_03.c +++ b/applications/plugins/weather_station/protocols/gt_wt_03.c @@ -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); } -bool ws_protocol_decoder_gt_wt_03_serialize( +SubGhzProtocolStatus ws_protocol_decoder_gt_wt_03_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -301,22 +301,12 @@ bool ws_protocol_decoder_gt_wt_03_serialize( 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); WSProtocolDecoderGT_WT03* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_gt_wt_03_const.min_count_bit_for_found); } void ws_protocol_decoder_gt_wt_03_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/gt_wt_03.h b/applications/plugins/weather_station/protocols/gt_wt_03.h index fd9536e3..d566bb39 100644 --- a/applications/plugins/weather_station/protocols/gt_wt_03.h +++ b/applications/plugins/weather_station/protocols/gt_wt_03.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_gt_wt_03_serialize( * Deserialize data WSProtocolDecoderGT_WT03. * @param context Pointer to a WSProtocolDecoderGT_WT03 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. diff --git a/applications/plugins/weather_station/protocols/infactory.c b/applications/plugins/weather_station/protocols/infactory.c index 53a656d7..4b0e6602 100644 --- a/applications/plugins/weather_station/protocols/infactory.c +++ b/applications/plugins/weather_station/protocols/infactory.c @@ -248,7 +248,7 @@ uint8_t ws_protocol_decoder_infactory_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool ws_protocol_decoder_infactory_serialize( +SubGhzProtocolStatus ws_protocol_decoder_infactory_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -257,22 +257,12 @@ bool ws_protocol_decoder_infactory_serialize( 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); WSProtocolDecoderInfactory* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_infactory_const.min_count_bit_for_found); } void ws_protocol_decoder_infactory_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/infactory.h b/applications/plugins/weather_station/protocols/infactory.h index 2792ab98..9431a067 100644 --- a/applications/plugins/weather_station/protocols/infactory.h +++ b/applications/plugins/weather_station/protocols/infactory.h @@ -56,9 +56,9 @@ uint8_t ws_protocol_decoder_infactory_get_hash_data(void* context); * @param context Pointer to a WSProtocolDecoderInfactory instance * @param flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_infactory_serialize( * Deserialize data WSProtocolDecoderInfactory. * @param context Pointer to a WSProtocolDecoderInfactory 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. diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx.c b/applications/plugins/weather_station/protocols/lacrosse_tx.c index 8d8a24e2..f4b850d7 100644 --- a/applications/plugins/weather_station/protocols/lacrosse_tx.c +++ b/applications/plugins/weather_station/protocols/lacrosse_tx.c @@ -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); } -bool ws_protocol_decoder_lacrosse_tx_serialize( +SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -290,22 +290,12 @@ bool ws_protocol_decoder_lacrosse_tx_serialize( 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); WSProtocolDecoderLaCrosse_TX* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_lacrosse_tx_const.min_count_bit_for_found); } void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx.h b/applications/plugins/weather_station/protocols/lacrosse_tx.h index e8845568..151282b3 100644 --- a/applications/plugins/weather_station/protocols/lacrosse_tx.h +++ b/applications/plugins/weather_station/protocols/lacrosse_tx.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_lacrosse_tx_serialize( * Deserialize data WSProtocolDecoderLaCrosse_TX. * @param context Pointer to a WSProtocolDecoderLaCrosse_TX 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. diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.c b/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.c index e4b61225..5d007b12 100644 --- a/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.c +++ b/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.c @@ -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); } -bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( +SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx141thbv2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -256,24 +256,15 @@ bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( 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, FlipperFormat* flipper_format) { furi_assert(context); WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; - bool ret = false; - do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_lacrosse_tx141thbv2_const.min_count_bit_for_found); } void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.h b/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.h index 941b0105..036db054 100644 --- a/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.h +++ b/applications/plugins/weather_station/protocols/lacrosse_tx141thbv2.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,9 @@ bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( * Deserialize data WSProtocolDecoderLaCrosse_TX141THBv2. * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 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, FlipperFormat* flipper_format); diff --git a/applications/plugins/weather_station/protocols/nexus_th.c b/applications/plugins/weather_station/protocols/nexus_th.c index 38f2fe89..14ba8b27 100644 --- a/applications/plugins/weather_station/protocols/nexus_th.c +++ b/applications/plugins/weather_station/protocols/nexus_th.c @@ -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); } -bool ws_protocol_decoder_nexus_th_serialize( +SubGhzProtocolStatus ws_protocol_decoder_nexus_th_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -225,22 +225,12 @@ bool ws_protocol_decoder_nexus_th_serialize( 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); WSProtocolDecoderNexus_TH* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_nexus_th_const.min_count_bit_for_found); } void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/nexus_th.h b/applications/plugins/weather_station/protocols/nexus_th.h index 5450f004..6c2715b8 100644 --- a/applications/plugins/weather_station/protocols/nexus_th.h +++ b/applications/plugins/weather_station/protocols/nexus_th.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_nexus_th_serialize( * Deserialize data WSProtocolDecoderNexus_TH. * @param context Pointer to a WSProtocolDecoderNexus_TH 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. diff --git a/applications/plugins/weather_station/protocols/oregon2.c b/applications/plugins/weather_station/protocols/oregon2.c index 8ca80bbe..313748cc 100644 --- a/applications/plugins/weather_station/protocols/oregon2.c +++ b/applications/plugins/weather_station/protocols/oregon2.c @@ -302,17 +302,19 @@ uint8_t ws_protocol_decoder_oregon2_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool ws_protocol_decoder_oregon2_serialize( +SubGhzProtocolStatus ws_protocol_decoder_oregon2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(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; if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) { FURI_LOG_E(TAG, "Error adding VarBits"); - return false; + return SubGhzProtocolStatusErrorParserOthers; } if(!flipper_format_write_hex( flipper_format, @@ -320,22 +322,25 @@ bool ws_protocol_decoder_oregon2_serialize( (const uint8_t*)&instance->var_data, sizeof(instance->var_data))) { 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); WSProtocolDecoderOregon2* instance = context; - bool ret = false; uint32_t temp_data; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = ws_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) { FURI_LOG_E(TAG, "Missing VarLen"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } 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, sizeof(instance->var_data))) { //-V1051 FURI_LOG_E(TAG, "Missing VarData"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } 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); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } - ret = true; } while(false); return ret; } diff --git a/applications/plugins/weather_station/protocols/oregon_v1.c b/applications/plugins/weather_station/protocols/oregon_v1.c index 1ed9da20..03215bbf 100644 --- a/applications/plugins/weather_station/protocols/oregon_v1.c +++ b/applications/plugins/weather_station/protocols/oregon_v1.c @@ -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); } -bool ws_protocol_decoder_oregon_v1_serialize( +SubGhzProtocolStatus ws_protocol_decoder_oregon_v1_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -292,22 +292,12 @@ bool ws_protocol_decoder_oregon_v1_serialize( 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); WSProtocolDecoderOregon_V1* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_oregon_v1_const.min_count_bit_for_found); } void ws_protocol_decoder_oregon_v1_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/oregon_v1.h b/applications/plugins/weather_station/protocols/oregon_v1.h index c9aa5af4..48937601 100644 --- a/applications/plugins/weather_station/protocols/oregon_v1.h +++ b/applications/plugins/weather_station/protocols/oregon_v1.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_oregon_v1_serialize( * Deserialize data WSProtocolDecoderOregon_V1. * @param context Pointer to a WSProtocolDecoderOregon_V1 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. diff --git a/applications/plugins/weather_station/protocols/thermopro_tx4.c b/applications/plugins/weather_station/protocols/thermopro_tx4.c index 0882bc33..24e883e6 100644 --- a/applications/plugins/weather_station/protocols/thermopro_tx4.c +++ b/applications/plugins/weather_station/protocols/thermopro_tx4.c @@ -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); } -bool ws_protocol_decoder_thermopro_tx4_serialize( +SubGhzProtocolStatus ws_protocol_decoder_thermopro_tx4_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -220,22 +220,14 @@ bool ws_protocol_decoder_thermopro_tx4_serialize( 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); WSProtocolDecoderThermoPRO_TX4* instance = context; - bool ret = false; - do { - if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_thermopro_tx4_const.min_count_bit_for_found); } void ws_protocol_decoder_thermopro_tx4_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/thermopro_tx4.h b/applications/plugins/weather_station/protocols/thermopro_tx4.h index 1feae58d..526648d1 100644 --- a/applications/plugins/weather_station/protocols/thermopro_tx4.h +++ b/applications/plugins/weather_station/protocols/thermopro_tx4.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_thermopro_tx4_serialize( * Deserialize data WSProtocolDecoderThermoPRO_TX4. * @param context Pointer to a WSProtocolDecoderThermoPRO_TX4 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. diff --git a/applications/plugins/weather_station/protocols/tx_8300.c b/applications/plugins/weather_station/protocols/tx_8300.c index ee0412ba..3a06ce49 100644 --- a/applications/plugins/weather_station/protocols/tx_8300.c +++ b/applications/plugins/weather_station/protocols/tx_8300.c @@ -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); } -bool ws_protocol_decoder_tx_8300_serialize( +SubGhzProtocolStatus ws_protocol_decoder_tx_8300_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -255,21 +255,12 @@ bool ws_protocol_decoder_tx_8300_serialize( 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); WSProtocolDecoderTX_8300* instance = context; - bool ret = false; - do { - 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; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, ws_protocol_tx_8300_const.min_count_bit_for_found); } void ws_protocol_decoder_tx_8300_get_string(void* context, FuriString* output) { diff --git a/applications/plugins/weather_station/protocols/tx_8300.h b/applications/plugins/weather_station/protocols/tx_8300.h index ec198e80..088ccd7c 100644 --- a/applications/plugins/weather_station/protocols/tx_8300.h +++ b/applications/plugins/weather_station/protocols/tx_8300.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -67,9 +67,10 @@ bool ws_protocol_decoder_tx_8300_serialize( * Deserialize data WSProtocolDecoderTX_8300. * @param context Pointer to a WSProtocolDecoderTX_8300 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. diff --git a/applications/plugins/weather_station/protocols/ws_generic.c b/applications/plugins/weather_station/protocols/ws_generic.c index 8a88ed52..026856a9 100644 --- a/applications/plugins/weather_station/protocols/ws_generic.c +++ b/applications/plugins/weather_station/protocols/ws_generic.c @@ -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); } -bool ws_block_generic_serialize( +SubGhzProtocolStatus ws_block_generic_serialize( WSBlockGeneric* instance, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(instance); - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; FuriString* temp_str; temp_str = furi_string_alloc(); do { @@ -34,11 +34,13 @@ bool ws_block_generic_serialize( if(!flipper_format_write_header_cstr( flipper_format, WS_KEY_FILE_TYPE, WS_KEY_FILE_VERSION)) { FURI_LOG_E(TAG, "Unable to add header"); + res = SubGhzProtocolStatusErrorParserHeader; break; } if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { FURI_LOG_E(TAG, "Unable to add Frequency"); + res = SubGhzProtocolStatusErrorParserFrequency; break; } @@ -46,34 +48,40 @@ bool ws_block_generic_serialize( if(!flipper_format_write_string_cstr( flipper_format, "Preset", furi_string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Unable to add Preset"); + res = SubGhzProtocolStatusErrorParserPreset; break; } if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { if(!flipper_format_write_string_cstr( flipper_format, "Custom_preset_module", "CC1101")) { FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); + res = SubGhzProtocolStatusErrorParserCustomPreset; break; } if(!flipper_format_write_hex( flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); + res = SubGhzProtocolStatusErrorParserCustomPreset; break; } } if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) { FURI_LOG_E(TAG, "Unable to add Protocol"); + res = SubGhzProtocolStatusErrorParserProtocolName; break; } uint32_t temp_data = instance->id; if(!flipper_format_write_uint32(flipper_format, "Id", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add Id"); + res = SubGhzProtocolStatusErrorParserOthers; break; } temp_data = instance->data_count_bit; if(!flipper_format_write_uint32(flipper_format, "Bit", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } @@ -84,18 +92,21 @@ bool ws_block_generic_serialize( if(!flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Data"); + res = SubGhzProtocolStatusErrorParserOthers; break; } temp_data = instance->battery_low; if(!flipper_format_write_uint32(flipper_format, "Batt", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add Battery_low"); + res = SubGhzProtocolStatusErrorParserOthers; break; } temp_data = instance->humidity; if(!flipper_format_write_uint32(flipper_format, "Hum", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add Humidity"); + res = SubGhzProtocolStatusErrorParserOthers; break; } @@ -107,52 +118,60 @@ bool ws_block_generic_serialize( temp_data = curr_ts; if(!flipper_format_write_uint32(flipper_format, "Ts", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add timestamp"); + res = SubGhzProtocolStatusErrorParserOthers; break; } temp_data = instance->channel; if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add Channel"); + res = SubGhzProtocolStatusErrorParserOthers; break; } temp_data = instance->btn; if(!flipper_format_write_uint32(flipper_format, "Btn", &temp_data, 1)) { FURI_LOG_E(TAG, "Unable to add Btn"); + res = SubGhzProtocolStatusErrorParserOthers; break; } float temp = instance->temp; if(!flipper_format_write_float(flipper_format, "Temp", &temp, 1)) { FURI_LOG_E(TAG, "Unable to add Temperature"); + res = SubGhzProtocolStatusErrorParserOthers; break; } - res = true; + res = SubGhzProtocolStatusOk; } while(false); furi_string_free(temp_str); 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); - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; uint32_t temp_data = 0; do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "Id", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Id"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->id = (uint32_t)temp_data; if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } 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}; if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Missing Data"); + res = SubGhzProtocolStatusErrorParserOthers; 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)) { FURI_LOG_E(TAG, "Missing Battery_low"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->battery_low = (uint8_t)temp_data; if(!flipper_format_read_uint32(flipper_format, "Hum", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Humidity"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->humidity = (uint8_t)temp_data; if(!flipper_format_read_uint32(flipper_format, "Ts", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing timestamp"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->timestamp = (uint32_t)temp_data; if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Channel"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->channel = (uint8_t)temp_data; if(!flipper_format_read_uint32(flipper_format, "Btn", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Btn"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->btn = (uint8_t)temp_data; @@ -200,12 +225,32 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp float temp; if(!flipper_format_read_float(flipper_format, "Temp", (float*)&temp, 1)) { FURI_LOG_E(TAG, "Missing Temperature"); + res = SubGhzProtocolStatusErrorParserOthers; break; } instance->temp = temp; - res = true; + res = SubGhzProtocolStatusOk; } while(0); 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; } \ No newline at end of file diff --git a/applications/plugins/weather_station/protocols/ws_generic.h b/applications/plugins/weather_station/protocols/ws_generic.h index 47cfa74b..ff047fae 100644 --- a/applications/plugins/weather_station/protocols/ws_generic.h +++ b/applications/plugins/weather_station/protocols/ws_generic.h @@ -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 flipper_format Pointer to a FlipperFormat instance * @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, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -59,9 +59,22 @@ bool ws_block_generic_serialize( * Deserialize data WSBlockGeneric. * @param instance Pointer to a WSBlockGeneric 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 } diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f306deb8..608f5b19 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,16.0,, +Version,+,17.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index f896dd1b..1c35abd3 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,16.0,, +Version,+,17.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2588,9 +2588,10 @@ Function,-,strupr,char*,char* Function,-,strverscmp,int,"const char*, const char*" Function,-,strxfrm,size_t,"char*, const char*, size_t" Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" -Function,+,subghz_block_generic_deserialize,_Bool,"SubGhzBlockGeneric*, FlipperFormat*" +Function,+,subghz_block_generic_deserialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*" +Function,+,subghz_block_generic_deserialize_check_count_bit,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, uint16_t" Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*" -Function,+,subghz_block_generic_serialize,_Bool,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*" +Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*" Function,+,subghz_environment_alloc,SubGhzEnvironment*, Function,+,subghz_environment_free,void,SubGhzEnvironment* Function,+,subghz_environment_get_alutech_at_4n_rainbow_table_file_name,const char*,SubGhzEnvironment* @@ -2632,19 +2633,19 @@ Function,+,subghz_protocol_blocks_parity_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t" Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t" Function,+,subghz_protocol_blocks_xor_bytes,uint8_t,"const uint8_t[], size_t" -Function,-,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" +Function,+,subghz_protocol_decoder_base_deserialize,SubGhzProtocolStatus,"SubGhzProtocolDecoderBase*, FlipperFormat*" Function,+,subghz_protocol_decoder_base_get_hash_data,uint8_t,SubGhzProtocolDecoderBase* Function,+,subghz_protocol_decoder_base_get_string,_Bool,"SubGhzProtocolDecoderBase*, FuriString*" -Function,+,subghz_protocol_decoder_base_serialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*, SubGhzRadioPreset*" +Function,+,subghz_protocol_decoder_base_serialize,SubGhzProtocolStatus,"SubGhzProtocolDecoderBase*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_base_set_decoder_callback,void,"SubGhzProtocolDecoderBase*, SubGhzProtocolDecoderBaseRxCallback, void*" Function,+,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* -Function,+,subghz_protocol_decoder_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_decoder_raw_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" Function,+,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" Function,+,subghz_protocol_decoder_raw_free,void,void* Function,+,subghz_protocol_decoder_raw_get_string,void,"void*, FuriString*" Function,+,subghz_protocol_decoder_raw_reset,void,void* Function,+,subghz_protocol_encoder_raw_alloc,void*,SubGhzEnvironment* -Function,+,subghz_protocol_encoder_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_encoder_raw_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" Function,+,subghz_protocol_encoder_raw_free,void,void* Function,+,subghz_protocol_encoder_raw_stop,void,void* Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void* @@ -2682,7 +2683,7 @@ Function,+,subghz_setting_get_preset_name,const char*,"SubGhzSetting*, size_t" Function,+,subghz_setting_load,void,"SubGhzSetting*, const char*" Function,+,subghz_setting_load_custom_preset,_Bool,"SubGhzSetting*, const char*, FlipperFormat*" Function,+,subghz_transmitter_alloc_init,SubGhzTransmitter*,"SubGhzEnvironment*, const char*" -Function,+,subghz_transmitter_deserialize,_Bool,"SubGhzTransmitter*, FlipperFormat*" +Function,+,subghz_transmitter_deserialize,SubGhzProtocolStatus,"SubGhzTransmitter*, FlipperFormat*" Function,+,subghz_transmitter_free,void,SubGhzTransmitter* Function,+,subghz_transmitter_get_protocol_instance,SubGhzProtocolEncoderBase*,SubGhzTransmitter* Function,+,subghz_transmitter_stop,_Bool,SubGhzTransmitter* diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index 3d59adc8..f59323da 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -20,12 +20,12 @@ void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* p furi_string_set(preset_str, preset_name_temp); } -bool subghz_block_generic_serialize( +SubGhzProtocolStatus subghz_block_generic_serialize( SubGhzBlockGeneric* instance, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(instance); - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; FuriString* temp_str; temp_str = furi_string_alloc(); do { @@ -33,11 +33,13 @@ bool subghz_block_generic_serialize( if(!flipper_format_write_header_cstr( flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { FURI_LOG_E(TAG, "Unable to add header"); + res = SubGhzProtocolStatusErrorParserHeader; break; } if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { FURI_LOG_E(TAG, "Unable to add Frequency"); + res = SubGhzProtocolStatusErrorParserFrequency; break; } @@ -45,27 +47,32 @@ bool subghz_block_generic_serialize( if(!flipper_format_write_string_cstr( flipper_format, "Preset", furi_string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Unable to add Preset"); + res = SubGhzProtocolStatusErrorParserPreset; break; } if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { if(!flipper_format_write_string_cstr( flipper_format, "Custom_preset_module", "CC1101")) { FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); + res = SubGhzProtocolStatusErrorParserCustomPreset; break; } if(!flipper_format_write_hex( flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); + res = SubGhzProtocolStatusErrorParserCustomPreset; break; } } if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) { FURI_LOG_E(TAG, "Unable to add Protocol"); + res = SubGhzProtocolStatusErrorParserProtocolName; break; } uint32_t temp = instance->data_count_bit; if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) { FURI_LOG_E(TAG, "Unable to add Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } @@ -76,17 +83,19 @@ bool subghz_block_generic_serialize( if(!flipper_format_write_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Key"); + res = SubGhzProtocolStatusErrorParserKey; break; } - res = true; + res = SubGhzProtocolStatusOk; } while(false); furi_string_free(temp_str); return res; } -bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format) { furi_assert(instance); - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; FuriString* temp_str; temp_str = furi_string_alloc(); uint32_t temp_data = 0; @@ -94,10 +103,12 @@ bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperForma do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } instance->data_count_bit = (uint16_t)temp_data; @@ -105,16 +116,36 @@ bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperForma uint8_t key_data[sizeof(uint64_t)] = {0}; if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Missing Key"); + res = SubGhzProtocolStatusErrorParserKey; break; } for(uint8_t i = 0; i < sizeof(uint64_t); i++) { instance->data = instance->data << 8 | key_data[i]; } - res = true; + res = SubGhzProtocolStatusOk; } while(0); furi_string_free(temp_str); return res; } + +SubGhzProtocolStatus subghz_block_generic_deserialize_check_count_bit( + SubGhzBlockGeneric* instance, + FlipperFormat* flipper_format, + uint16_t count_bit) { + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_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; +} \ No newline at end of file diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index 284df51a..bc26a54d 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -36,9 +36,9 @@ void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* p * @param instance Pointer to a SubGhzBlockGeneric instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return Status Error */ -bool subghz_block_generic_serialize( +SubGhzProtocolStatus subghz_block_generic_serialize( SubGhzBlockGeneric* instance, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -47,9 +47,22 @@ bool subghz_block_generic_serialize( * Deserialize data SubGhzBlockGeneric. * @param instance Pointer to a SubGhzBlockGeneric instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return Status Error */ -bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format); + +/** + * Deserialize data SubGhzBlockGeneric. + * @param instance Pointer to a SubGhzBlockGeneric instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param count_bit Count bit protocol + * @return Status Error + */ +SubGhzProtocolStatus subghz_block_generic_deserialize_check_count_bit( + SubGhzBlockGeneric* instance, + FlipperFormat* flipper_format, + uint16_t count_bit); #ifdef __cplusplus } diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 6bcf9f25..e8bb8705 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -385,46 +385,46 @@ uint8_t subghz_protocol_decoder_alutech_at_4n_get_hash_data(void* context) { return (uint8_t)instance->crc; } -bool subghz_protocol_decoder_alutech_at_4n_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_alutech_at_4n_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderAlutech_at_4n* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) { + SubGhzProtocolStatus res = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if((res == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) { FURI_LOG_E(TAG, "Unable to add CRC"); - res = false; + res = SubGhzProtocolStatusErrorParserOthers; } return res; - - return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_alutech_at_4n_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_alutech_at_4n_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderAlutech_at_4n* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_alutech_at_4n_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_alutech_at_4n_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "CRC", (uint32_t*)&instance->crc, 1)) { FURI_LOG_E(TAG, "Missing CRC"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/alutech_at_4n.h b/lib/subghz/protocols/alutech_at_4n.h index 38bac3ea..189f2f0d 100644 --- a/lib/subghz/protocols/alutech_at_4n.h +++ b/lib/subghz/protocols/alutech_at_4n.h @@ -49,9 +49,9 @@ uint8_t subghz_protocol_decoder_alutech_at_4n_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_alutech_at_4n_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_alutech_at_4n_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -60,11 +60,10 @@ bool subghz_protocol_decoder_alutech_at_4n_serialize( * Deserialize data SubGhzProtocolDecoderAlutech_at_4n. * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_alutech_at_4n_deserialize( - void* context, - FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_alutech_at_4n_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c index 81b196e3..9a122629 100644 --- a/lib/subghz/protocols/ansonic.c +++ b/lib/subghz/protocols/ansonic.c @@ -136,28 +136,29 @@ static bool subghz_protocol_encoder_ansonic_get_upload(SubGhzProtocolEncoderAnso return true; } -bool subghz_protocol_encoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderAnsonic* instance = context; - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + res = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_ansonic_const.min_count_bit_for_found); + if(res != SubGhzProtocolStatusOk) { FURI_LOG_E(TAG, "Deserialize error"); break; } - if(instance->generic.data_count_bit != - subghz_protocol_ansonic_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_ansonic_get_upload(instance)) break; + if(!subghz_protocol_encoder_ansonic_get_upload(instance)) { + res = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); return res; @@ -301,7 +302,7 @@ uint8_t subghz_protocol_decoder_ansonic_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_ansonic_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_ansonic_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -310,22 +311,12 @@ bool subghz_protocol_decoder_ansonic_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderAnsonic* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_ansonic_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_ansonic_const.min_count_bit_for_found); } void subghz_protocol_decoder_ansonic_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/ansonic.h b/lib/subghz/protocols/ansonic.h index 0170a604..95585318 100644 --- a/lib/subghz/protocols/ansonic.h +++ b/lib/subghz/protocols/ansonic.h @@ -30,7 +30,8 @@ void subghz_protocol_encoder_ansonic_free(void* context); * @param flipper_format Pointer to a FlipperFormat instance * @return true On success */ -bool subghz_protocol_encoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -86,7 +87,7 @@ uint8_t subghz_protocol_decoder_ansonic_get_hash_data(void* context); * @param preset The modulation on which the signal was received, SubGhzRadioPreset * @return true On success */ -bool subghz_protocol_decoder_ansonic_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_ansonic_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -97,7 +98,8 @@ bool subghz_protocol_decoder_ansonic_serialize( * @param flipper_format Pointer to a FlipperFormat instance * @return true On success */ -bool subghz_protocol_decoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/base.c b/lib/subghz/protocols/base.c index 36f33b9a..37d1a308 100644 --- a/lib/subghz/protocols/base.c +++ b/lib/subghz/protocols/base.c @@ -23,11 +23,11 @@ bool subghz_protocol_decoder_base_get_string( return status; } -bool subghz_protocol_decoder_base_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_base_serialize( SubGhzProtocolDecoderBase* decoder_base, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { - bool status = false; + SubGhzProtocolStatus status = SubGhzProtocolStatusError; if(decoder_base->protocol && decoder_base->protocol->decoder && decoder_base->protocol->decoder->serialize) { @@ -37,10 +37,10 @@ bool subghz_protocol_decoder_base_serialize( return status; } -bool subghz_protocol_decoder_base_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_base_deserialize( SubGhzProtocolDecoderBase* decoder_base, FlipperFormat* flipper_format) { - bool status = false; + SubGhzProtocolStatus status = SubGhzProtocolStatusError; if(decoder_base->protocol && decoder_base->protocol->decoder && decoder_base->protocol->decoder->deserialize) { diff --git a/lib/subghz/protocols/base.h b/lib/subghz/protocols/base.h index 1f3d3e1b..1d819ab5 100644 --- a/lib/subghz/protocols/base.h +++ b/lib/subghz/protocols/base.h @@ -49,9 +49,9 @@ bool subghz_protocol_decoder_base_get_string( * @param decoder_base Pointer to a SubGhzProtocolDecoderBase instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return Status Error */ -bool subghz_protocol_decoder_base_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_base_serialize( SubGhzProtocolDecoderBase* decoder_base, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -60,9 +60,9 @@ bool subghz_protocol_decoder_base_serialize( * Deserialize data SubGhzProtocolDecoderBase. * @param decoder_base Pointer to a SubGhzProtocolDecoderBase instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return Status Error */ -bool subghz_protocol_decoder_base_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_base_deserialize( SubGhzProtocolDecoderBase* decoder_base, FlipperFormat* flipper_format); diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 644d80fd..de13472a 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -155,31 +155,32 @@ static bool subghz_protocol_encoder_bett_get_upload(SubGhzProtocolEncoderBETT* i return true; } -bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderBETT* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_bett_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { FURI_LOG_E(TAG, "Deserialize error"); break; } - if(instance->generic.data_count_bit != - subghz_protocol_bett_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_bett_get_upload(instance)) break; + if(!subghz_protocol_encoder_bett_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_bett_stop(void* context) { @@ -295,7 +296,7 @@ uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_bett_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_bett_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -304,22 +305,12 @@ bool subghz_protocol_decoder_bett_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderBETT* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_bett_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_bett_const.min_count_bit_for_found); } void subghz_protocol_decoder_bett_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/bett.h b/lib/subghz/protocols/bett.h index c0ce0b7f..0a11cbe6 100644 --- a/lib/subghz/protocols/bett.h +++ b/lib/subghz/protocols/bett.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_bett_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderBETT instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderBETT instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_bett_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_bett_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_bett_serialize( * Deserialize data SubGhzProtocolDecoderBETT. * @param context Pointer to a SubGhzProtocolDecoderBETT instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index c3f54411..123a4ba9 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -219,20 +219,23 @@ static bool subghz_protocol_encoder_bin_raw_get_upload(SubGhzProtocolEncoderBinR return true; } -bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderBinRAW* instance = context; - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; uint32_t temp_data = 0; do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } @@ -240,6 +243,7 @@ bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* f if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); + res = SubGhzProtocolStatusErrorParserTe; break; } @@ -251,11 +255,13 @@ bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* f while(flipper_format_read_uint32(flipper_format, "Bit_RAW", (uint32_t*)&temp_data, 1)) { if(ind >= BIN_RAW_MAX_MARKUP_COUNT) { FURI_LOG_E(TAG, "Markup overflow"); + res = SubGhzProtocolStatusErrorParserOthers; break; } byte_count += subghz_protocol_bin_raw_get_full_byte(temp_data); if(byte_count > BIN_RAW_BUF_DATA_SIZE) { FURI_LOG_E(TAG, "Receive buffer overflow"); + res = SubGhzProtocolStatusErrorParserOthers; break; } @@ -270,6 +276,7 @@ bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* f subghz_protocol_bin_raw_get_full_byte(temp_data))) { instance->data_markup[ind].bit_count = 0; FURI_LOG_E(TAG, "Missing Data_RAW"); + res = SubGhzProtocolStatusErrorParserOthers; break; } ind++; @@ -297,16 +304,20 @@ bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* f #endif if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) break; + if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) { + break; + res = SubGhzProtocolStatusErrorEncoderGetUpload; + } instance->encoder.is_running = true; - res = true; + res = SubGhzProtocolStatusOk; } while(0); return res; @@ -957,14 +968,14 @@ uint8_t subghz_protocol_decoder_bin_raw_get_hash_data(void* context) { subghz_protocol_bin_raw_get_full_byte(instance->data_markup[0].bit_count)); } -bool subghz_protocol_decoder_bin_raw_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_bin_raw_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderBinRAW* instance = context; - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; FuriString* temp_str; temp_str = furi_string_alloc(); do { @@ -972,11 +983,13 @@ bool subghz_protocol_decoder_bin_raw_serialize( if(!flipper_format_write_header_cstr( flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { FURI_LOG_E(TAG, "Unable to add header"); + res = SubGhzProtocolStatusErrorParserHeader; break; } if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { FURI_LOG_E(TAG, "Unable to add Frequency"); + res = SubGhzProtocolStatusErrorParserFrequency; break; } @@ -984,34 +997,40 @@ bool subghz_protocol_decoder_bin_raw_serialize( if(!flipper_format_write_string_cstr( flipper_format, "Preset", furi_string_get_cstr(temp_str))) { FURI_LOG_E(TAG, "Unable to add Preset"); + res = SubGhzProtocolStatusErrorParserPreset; break; } if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { if(!flipper_format_write_string_cstr( flipper_format, "Custom_preset_module", "CC1101")) { FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); + res = SubGhzProtocolStatusErrorParserCustomPreset; break; } if(!flipper_format_write_hex( flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); + res = SubGhzProtocolStatusErrorParserCustomPreset; break; } } if(!flipper_format_write_string_cstr( flipper_format, "Protocol", instance->generic.protocol_name)) { FURI_LOG_E(TAG, "Unable to add Protocol"); + res = SubGhzProtocolStatusErrorParserProtocolName; break; } uint32_t temp = instance->generic.data_count_bit; if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) { FURI_LOG_E(TAG, "Unable to add Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } if(!flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { FURI_LOG_E(TAG, "Unable to add TE"); + res = SubGhzProtocolStatusErrorParserTe; break; } @@ -1020,6 +1039,7 @@ bool subghz_protocol_decoder_bin_raw_serialize( temp = instance->data_markup[i].bit_count; if(!flipper_format_write_uint32(flipper_format, "Bit_RAW", &temp, 1)) { FURI_LOG_E(TAG, "Bit_RAW"); + res = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_write_hex( @@ -1028,31 +1048,35 @@ bool subghz_protocol_decoder_bin_raw_serialize( instance->data + instance->data_markup[i].byte_bias, subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count))) { FURI_LOG_E(TAG, "Unable to add Data_RAW"); + res = SubGhzProtocolStatusErrorParserOthers; break; } i++; } - res = true; + res = SubGhzProtocolStatusOk; } while(false); furi_string_free(temp_str); return res; } -bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderBinRAW* instance = context; - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; uint32_t temp_data = 0; do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { FURI_LOG_E(TAG, "Missing Bit"); + res = SubGhzProtocolStatusErrorParserBitCount; break; } @@ -1060,6 +1084,7 @@ bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* f if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); + res = SubGhzProtocolStatusErrorParserTe; break; } @@ -1071,11 +1096,13 @@ bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* f while(flipper_format_read_uint32(flipper_format, "Bit_RAW", (uint32_t*)&temp_data, 1)) { if(ind >= BIN_RAW_MAX_MARKUP_COUNT) { FURI_LOG_E(TAG, "Markup overflow"); + res = SubGhzProtocolStatusErrorParserOthers; break; } byte_count += subghz_protocol_bin_raw_get_full_byte(temp_data); if(byte_count > BIN_RAW_BUF_DATA_SIZE) { FURI_LOG_E(TAG, "Receive buffer overflow"); + res = SubGhzProtocolStatusErrorParserOthers; break; } @@ -1090,12 +1117,13 @@ bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* f subghz_protocol_bin_raw_get_full_byte(temp_data))) { instance->data_markup[ind].bit_count = 0; FURI_LOG_E(TAG, "Missing Data_RAW"); + res = SubGhzProtocolStatusErrorParserOthers; break; } ind++; } - res = true; + res = SubGhzProtocolStatusOk; } while(0); return res; diff --git a/lib/subghz/protocols/bin_raw.h b/lib/subghz/protocols/bin_raw.h index c63f86ce..82775e57 100644 --- a/lib/subghz/protocols/bin_raw.h +++ b/lib/subghz/protocols/bin_raw.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_bin_raw_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -88,9 +89,9 @@ void subghz_protocol_decoder_bin_raw_data_input_rssi( * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_bin_raw_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_bin_raw_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -99,9 +100,10 @@ bool subghz_protocol_decoder_bin_raw_serialize( * Deserialize data SubGhzProtocolDecoderBinRAW. * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index bed26d7d..14b2e010 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -13,6 +13,7 @@ */ #define TAG "SubGhzProtocolCAME" +#define CAME_12_COUNT_BIT 12 #define CAME_24_COUNT_BIT 24 #define PRASTEL_COUNT_BIT 25 #define PRASTEL_NAME "Prastel" @@ -108,6 +109,7 @@ void subghz_protocol_encoder_came_free(void* context) { */ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* instance) { furi_assert(instance); + uint32_t header_te = 0; size_t index = 0; size_t size_upload = (instance->generic.data_count_bit * 2) + 2; if(size_upload > instance->encoder.size_upload) { @@ -117,13 +119,28 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i instance->encoder.size_upload = size_upload; } //Send header - instance->encoder.upload[index++] = level_duration_make( - false, - (((instance->generic.data_count_bit == CAME_24_COUNT_BIT) || - (instance->generic.data_count_bit == - subghz_protocol_came_const.min_count_bit_for_found)) ? - (uint32_t)subghz_protocol_came_const.te_short * 76 : - (uint32_t)subghz_protocol_came_const.te_short * 39)); + + switch(instance->generic.data_count_bit) { + case CAME_24_COUNT_BIT: + // CAME 24 Bit = 24320 us + header_te = 76; + break; + case CAME_12_COUNT_BIT: + case AIRFORCE_COUNT_BIT: + // CAME 12 Bit Original only! and Airforce protocol = 15040 us + header_te = 47; + break; + case PRASTEL_COUNT_BIT: + // PRASTEL = 11520 us + header_te = 36; + break; + default: + // Some wrong detected protocols, 5120 us + header_te = 16; + break; + } + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * header_te); //Send start bit instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); @@ -146,30 +163,33 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i return true; } -bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderCame* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit > PRASTEL_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_came_get_upload(instance)) break; + if(!subghz_protocol_encoder_came_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_came_stop(void* context) { @@ -244,8 +264,11 @@ void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t durat if(!level) { //save interval if(duration >= (subghz_protocol_came_const.te_short * 4)) { instance->decoder.parser_step = CameDecoderStepFoundStartBit; - if(instance->decoder.decode_count_bit >= - subghz_protocol_came_const.min_count_bit_for_found) { + if((instance->decoder.decode_count_bit == + subghz_protocol_came_const.min_count_bit_for_found) || + (instance->decoder.decode_count_bit == AIRFORCE_COUNT_BIT) || + (instance->decoder.decode_count_bit == PRASTEL_COUNT_BIT) || + (instance->decoder.decode_count_bit == CAME_24_COUNT_BIT)) { instance->generic.serial = 0x0; instance->generic.btn = 0x0; @@ -294,7 +317,7 @@ uint8_t subghz_protocol_decoder_came_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_came_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_came_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -303,19 +326,21 @@ bool subghz_protocol_decoder_came_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderCame* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit > PRASTEL_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/came.h b/lib/subghz/protocols/came.h index 253c93aa..fffa017f 100644 --- a/lib/subghz/protocols/came.h +++ b/lib/subghz/protocols/came.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_came_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderCame instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_came_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderCame instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_came_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_came_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_came_serialize( * Deserialize data SubGhzProtocolDecoderCame. * @param context Pointer to a SubGhzProtocolDecoderCame instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 2e271848..9f411a66 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -298,7 +298,7 @@ uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_came_atomo_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_came_atomo_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -307,22 +307,14 @@ bool subghz_protocol_decoder_came_atomo_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderCameAtomo* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_came_atomo_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_came_atomo_const.min_count_bit_for_found); } void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/came_atomo.h b/lib/subghz/protocols/came_atomo.h index 3781a0d8..0faea4f1 100644 --- a/lib/subghz/protocols/came_atomo.h +++ b/lib/subghz/protocols/came_atomo.h @@ -49,9 +49,9 @@ uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderCameAtomo instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_came_atomo_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_came_atomo_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -60,9 +60,10 @@ bool subghz_protocol_decoder_came_atomo_serialize( * Deserialize data SubGhzProtocolDecoderCameAtomo. * @param context Pointer to a SubGhzProtocolDecoderCameAtomo instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index e7eb33c4..6fe61581 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -241,18 +241,17 @@ static void subghz_protocol_came_twee_remote_controller(SubGhzBlockGeneric* inst instance->cnt = data >> 6; } -bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderCameTwee* instance = context; - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_came_twee_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + res = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_came_twee_const.min_count_bit_for_found); + if(res != SubGhzProtocolStatusOk) { break; } //optional parameter parameter @@ -262,8 +261,6 @@ bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* subghz_protocol_came_twee_remote_controller(&instance->generic); subghz_protocol_encoder_came_twee_get_upload(instance); instance->encoder.is_running = true; - - res = true; } while(false); return res; @@ -419,7 +416,7 @@ uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_came_twee_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_came_twee_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -428,22 +425,14 @@ bool subghz_protocol_decoder_came_twee_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderCameTwee* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_came_twee_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_came_twee_const.min_count_bit_for_found); } void subghz_protocol_decoder_came_twee_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/came_twee.h b/lib/subghz/protocols/came_twee.h index 359b964d..f26f1e80 100644 --- a/lib/subghz/protocols/came_twee.h +++ b/lib/subghz/protocols/came_twee.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_came_twee_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderCameTwee instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderCameTwee instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_came_twee_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_came_twee_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_came_twee_serialize( * Deserialize data SubGhzProtocolDecoderCameTwee. * @param context Pointer to a SubGhzProtocolDecoderCameTwee instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 9c8e5ee4..be0877fb 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -207,31 +207,35 @@ static bool return true; } -bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderChamb_Code* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if(instance->generic.data_count_bit > subghz_protocol_chamb_code_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_chamb_code_get_upload(instance)) break; + if(!subghz_protocol_encoder_chamb_code_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_chamb_code_stop(void* context) { @@ -425,7 +429,7 @@ uint8_t subghz_protocol_decoder_chamb_code_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_chamb_code_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_chamb_code_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -434,20 +438,22 @@ bool subghz_protocol_decoder_chamb_code_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderChamb_Code* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if(instance->generic.data_count_bit > subghz_protocol_chamb_code_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/chamberlain_code.h b/lib/subghz/protocols/chamberlain_code.h index f87b64d9..c8ffed5c 100644 --- a/lib/subghz/protocols/chamberlain_code.h +++ b/lib/subghz/protocols/chamberlain_code.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_chamb_code_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderChamb_Code instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_chamb_code_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_chamb_code_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_chamb_code_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_chamb_code_serialize( * Deserialize data SubGhzProtocolDecoderChamb_Code. * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index a2cb7a18..a0547a11 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -155,31 +155,32 @@ static bool subghz_protocol_encoder_clemsa_get_upload(SubGhzProtocolEncoderClems return true; } -bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderClemsa* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_clemsa_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_clemsa_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_clemsa_get_upload(instance)) break; + if(!subghz_protocol_encoder_clemsa_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_clemsa_stop(void* context) { @@ -316,7 +317,7 @@ uint8_t subghz_protocol_decoder_clemsa_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_clemsa_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_clemsa_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -325,22 +326,12 @@ bool subghz_protocol_decoder_clemsa_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderClemsa* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_clemsa_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_clemsa_const.min_count_bit_for_found); } void subghz_protocol_decoder_clemsa_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/clemsa.h b/lib/subghz/protocols/clemsa.h index 8858c1a3..f14cd3da 100644 --- a/lib/subghz/protocols/clemsa.h +++ b/lib/subghz/protocols/clemsa.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_clemsa_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderClemsa instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_clemsa_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderClemsa instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_clemsa_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_clemsa_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_clemsa_serialize( * Deserialize data SubGhzProtocolDecoderClemsa. * @param context Pointer to a SubGhzProtocolDecoderClemsa instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_clemsa_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index 6b31d4f2..69b8bba4 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -136,31 +136,31 @@ static bool subghz_protocol_encoder_doitrand_get_upload(SubGhzProtocolEncoderDoi return true; } -bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderDoitrand* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_doitrand_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_doitrand_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_doitrand_get_upload(instance)) break; + if(!subghz_protocol_encoder_doitrand_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_doitrand_stop(void* context) { @@ -310,7 +310,7 @@ uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_doitrand_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_doitrand_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -319,22 +319,14 @@ bool subghz_protocol_decoder_doitrand_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderDoitrand* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_doitrand_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_doitrand_const.min_count_bit_for_found); } void subghz_protocol_decoder_doitrand_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/doitrand.h b/lib/subghz/protocols/doitrand.h index 30f1fffd..5dbc6678 100644 --- a/lib/subghz/protocols/doitrand.h +++ b/lib/subghz/protocols/doitrand.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_doitrand_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_doitrand_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_doitrand_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_doitrand_serialize( * Deserialize data SubGhzProtocolDecoderDoitrand. * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c index c70b6d54..47e95209 100644 --- a/lib/subghz/protocols/dooya.c +++ b/lib/subghz/protocols/dooya.c @@ -146,31 +146,31 @@ static bool subghz_protocol_encoder_dooya_get_upload(SubGhzProtocolEncoderDooya* return true; } -bool subghz_protocol_encoder_dooya_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_dooya_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderDooya* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_dooya_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_dooya_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_dooya_get_upload(instance)) break; + if(!subghz_protocol_encoder_dooya_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_dooya_stop(void* context) { @@ -354,7 +354,7 @@ uint8_t subghz_protocol_decoder_dooya_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_dooya_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_dooya_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -363,22 +363,12 @@ bool subghz_protocol_decoder_dooya_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_dooya_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_dooya_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderDooya* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_dooya_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_dooya_const.min_count_bit_for_found); } /** diff --git a/lib/subghz/protocols/dooya.h b/lib/subghz/protocols/dooya.h index f0cf843c..ffe9d41e 100644 --- a/lib/subghz/protocols/dooya.h +++ b/lib/subghz/protocols/dooya.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_dooya_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderDooya instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_dooya_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_dooya_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_dooya_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderDooya instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_dooya_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_dooya_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_dooya_serialize( * Deserialize data SubGhzProtocolDecoderDooya. * @param context Pointer to a SubGhzProtocolDecoderDooya instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_dooya_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_dooya_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index ad186738..d9dd6840 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -180,7 +180,7 @@ uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_faac_slh_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_faac_slh_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -189,22 +189,14 @@ bool subghz_protocol_decoder_faac_slh_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderFaacSLH* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_faac_slh_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_faac_slh_const.min_count_bit_for_found); } void subghz_protocol_decoder_faac_slh_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/faac_slh.h b/lib/subghz/protocols/faac_slh.h index 52c265d2..9d9a9e40 100644 --- a/lib/subghz/protocols/faac_slh.h +++ b/lib/subghz/protocols/faac_slh.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderFaacSLH instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_faac_slh_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_faac_slh_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_faac_slh_serialize( * Deserialize data SubGhzProtocolDecoderFaacSLH. * @param context Pointer to a SubGhzProtocolDecoderFaacSLH instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 4c7c2d48..51a424fe 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -129,31 +129,31 @@ static bool subghz_protocol_encoder_gate_tx_get_upload(SubGhzProtocolEncoderGate return true; } -bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderGateTx* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_gate_tx_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_gate_tx_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_gate_tx_get_upload(instance)) break; + if(!subghz_protocol_encoder_gate_tx_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_gate_tx_stop(void* context) { @@ -290,7 +290,7 @@ uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_gate_tx_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_gate_tx_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -299,22 +299,12 @@ bool subghz_protocol_decoder_gate_tx_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderGateTx* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_gate_tx_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_gate_tx_const.min_count_bit_for_found); } void subghz_protocol_decoder_gate_tx_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/gate_tx.h b/lib/subghz/protocols/gate_tx.h index 4bfba359..a6abede0 100644 --- a/lib/subghz/protocols/gate_tx.h +++ b/lib/subghz/protocols/gate_tx.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_gate_tx_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderGateTx instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderGateTx instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_gate_tx_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_gate_tx_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_gate_tx_serialize( * Deserialize data SubGhzProtocolDecoderGateTx. * @param context Pointer to a SubGhzProtocolDecoderGateTx instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index 8aaad3b7..294bd124 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -142,31 +142,31 @@ static bool subghz_protocol_encoder_holtek_get_upload(SubGhzProtocolEncoderHolte return true; } -bool subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderHoltek* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_holtek_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_holtek_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_holtek_get_upload(instance)) break; + if(!subghz_protocol_encoder_holtek_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_holtek_stop(void* context) { @@ -322,7 +322,7 @@ uint8_t subghz_protocol_decoder_holtek_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_holtek_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_holtek_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -331,22 +331,12 @@ bool subghz_protocol_decoder_holtek_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_holtek_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_holtek_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderHoltek* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_holtek_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_holtek_const.min_count_bit_for_found); } void subghz_protocol_decoder_holtek_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/holtek.h b/lib/subghz/protocols/holtek.h index 252a26dc..19081308 100644 --- a/lib/subghz/protocols/holtek.h +++ b/lib/subghz/protocols/holtek.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_holtek_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderHoltek instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_holtek_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderHoltek instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_holtek_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_holtek_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_holtek_serialize( * Deserialize data SubGhzProtocolDecoderHoltek. * @param context Pointer to a SubGhzProtocolDecoderHoltek instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_holtek_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_holtek_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/holtek_ht12x.c b/lib/subghz/protocols/holtek_ht12x.c index 169387de..831f824d 100644 --- a/lib/subghz/protocols/holtek_ht12x.c +++ b/lib/subghz/protocols/holtek_ht12x.c @@ -147,39 +147,41 @@ static bool return true; } -bool subghz_protocol_encoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderHoltek_HT12X* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_holtek_th12x_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_holtek_th12x_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorParserTe; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_holtek_th12x_get_upload(instance)) break; + if(!subghz_protocol_encoder_holtek_th12x_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_holtek_th12x_stop(void* context) { @@ -327,42 +329,45 @@ uint8_t subghz_protocol_decoder_holtek_th12x_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_holtek_th12x_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_holtek_th12x_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderHoltek_HT12X* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { FURI_LOG_E(TAG, "Unable to add TE"); - res = false; + ret = SubGhzProtocolStatusErrorParserTe; } - return res; + return ret; } -bool subghz_protocol_decoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderHoltek_HT12X* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_holtek_th12x_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_holtek_th12x_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); + ret = SubGhzProtocolStatusErrorParserTe; break; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/holtek_ht12x.h b/lib/subghz/protocols/holtek_ht12x.h index 7b5c31dd..500c061a 100644 --- a/lib/subghz/protocols/holtek_ht12x.h +++ b/lib/subghz/protocols/holtek_ht12x.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_holtek_th12x_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderHoltek_HT12X instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_holtek_th12x_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderHoltek_HT12X instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_holtek_th12x_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_holtek_th12x_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_holtek_th12x_serialize( * Deserialize data SubGhzProtocolDecoderHoltek_HT12X. * @param context Pointer to a SubGhzProtocolDecoderHoltek_HT12X instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_holtek_th12x_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 3b940fc6..7fd8d66d 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -142,33 +142,32 @@ static bool subghz_protocol_encoder_honeywell_wdb_get_upload( return true; } -bool subghz_protocol_encoder_honeywell_wdb_deserialize( +SubGhzProtocolStatus subghz_protocol_encoder_honeywell_wdb_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderHoneywell_WDB* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_honeywell_wdb_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_honeywell_wdb_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_honeywell_wdb_get_upload(instance)) break; + if(!subghz_protocol_encoder_honeywell_wdb_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_honeywell_wdb_stop(void* context) { @@ -345,7 +344,7 @@ uint8_t subghz_protocol_decoder_honeywell_wdb_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_honeywell_wdb_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_honeywell_wdb_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -354,24 +353,15 @@ bool subghz_protocol_decoder_honeywell_wdb_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_honeywell_wdb_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_honeywell_wdb_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderHoneywell_WDB* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_honeywell_wdb_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_honeywell_wdb_const.min_count_bit_for_found); } void subghz_protocol_decoder_honeywell_wdb_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/honeywell_wdb.h b/lib/subghz/protocols/honeywell_wdb.h index 82863183..91728691 100644 --- a/lib/subghz/protocols/honeywell_wdb.h +++ b/lib/subghz/protocols/honeywell_wdb.h @@ -28,11 +28,10 @@ void subghz_protocol_encoder_honeywell_wdb_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderHoneywell_WDB instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_honeywell_wdb_deserialize( - void* context, - FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_honeywell_wdb_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -86,9 +85,9 @@ uint8_t subghz_protocol_decoder_honeywell_wdb_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_honeywell_wdb_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_honeywell_wdb_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -97,11 +96,10 @@ bool subghz_protocol_decoder_honeywell_wdb_serialize( * Deserialize data SubGhzProtocolDecoderHoneywell_WDB. * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_honeywell_wdb_deserialize( - void* context, - FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_honeywell_wdb_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 67b8cdfc..4c5c68cc 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -140,31 +140,31 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm return true; } -bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderHormann* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_hormann_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_hormann_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_hormann_get_upload(instance)) break; + if(!subghz_protocol_encoder_hormann_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_hormann_stop(void* context) { @@ -295,7 +295,7 @@ uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_hormann_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_hormann_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -304,22 +304,12 @@ bool subghz_protocol_decoder_hormann_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderHormann* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_hormann_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_hormann_const.min_count_bit_for_found); } void subghz_protocol_decoder_hormann_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/hormann.h b/lib/subghz/protocols/hormann.h index 857a5004..8cb45aec 100644 --- a/lib/subghz/protocols/hormann.h +++ b/lib/subghz/protocols/hormann.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_hormann_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderHormann instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderHormann instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_hormann_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_hormann_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_hormann_serialize( * Deserialize data SubGhzProtocolDecoderHormann. * @param context Pointer to a SubGhzProtocolDecoderHormann instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/ido.c b/lib/subghz/protocols/ido.c index 31ff20e4..90c0fb0e 100644 --- a/lib/subghz/protocols/ido.c +++ b/lib/subghz/protocols/ido.c @@ -179,7 +179,7 @@ uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_ido_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_ido_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -188,21 +188,12 @@ bool subghz_protocol_decoder_ido_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderIDo* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != subghz_protocol_ido_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_ido_const.min_count_bit_for_found); } void subghz_protocol_decoder_ido_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/ido.h b/lib/subghz/protocols/ido.h index 634f6ff8..94932024 100644 --- a/lib/subghz/protocols/ido.h +++ b/lib/subghz/protocols/ido.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderIDo instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_ido_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_ido_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_ido_serialize( * Deserialize data SubGhzProtocolDecoderIDo. * @param context Pointer to a SubGhzProtocolDecoderIDo instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index 2c4e514c..7fe95299 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -158,34 +158,36 @@ static bool subghz_protocol_encoder_intertechno_v3_get_upload( return true; } -bool subghz_protocol_encoder_intertechno_v3_deserialize( +SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderIntertechno_V3* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit != subghz_protocol_intertechno_v3_const.min_count_bit_for_found) && (instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_intertechno_v3_get_upload(instance)) break; + if(!subghz_protocol_encoder_intertechno_v3_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_intertechno_v3_stop(void* context) { @@ -404,7 +406,7 @@ uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_intertechno_v3_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_intertechno_v3_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -413,23 +415,24 @@ bool subghz_protocol_decoder_intertechno_v3_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_intertechno_v3_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_intertechno_v3_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderIntertechno_V3* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit != subghz_protocol_intertechno_v3_const.min_count_bit_for_found) && (instance->generic.data_count_bit != INTERTECHNO_V3_DIMMING_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/intertechno_v3.h b/lib/subghz/protocols/intertechno_v3.h index ffee14b0..4d1c24cb 100644 --- a/lib/subghz/protocols/intertechno_v3.h +++ b/lib/subghz/protocols/intertechno_v3.h @@ -28,9 +28,9 @@ void subghz_protocol_encoder_intertechno_v3_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderIntertechno_V3 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return Starus error */ -bool subghz_protocol_encoder_intertechno_v3_deserialize( +SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize( void* context, FlipperFormat* flipper_format); @@ -86,9 +86,9 @@ uint8_t subghz_protocol_decoder_intertechno_v3_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return Starus error */ -bool subghz_protocol_decoder_intertechno_v3_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_intertechno_v3_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -97,9 +97,9 @@ bool subghz_protocol_decoder_intertechno_v3_serialize( * Deserialize data SubGhzProtocolDecoderIntertechno_V3. * @param context Pointer to a SubGhzProtocolDecoderIntertechno_V3 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return Starus error */ -bool subghz_protocol_decoder_intertechno_v3_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_intertechno_v3_deserialize( void* context, FlipperFormat* flipper_format); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 4a3602fb..57d1cd22 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -254,18 +254,17 @@ static bool return true; } -bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderKeeloq* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_keeloq_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_keeloq_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } subghz_protocol_keeloq_check_remote_controller( @@ -273,6 +272,7 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl if(strcmp(instance->manufacture_name, "DoorHan") != 0) { FURI_LOG_E(TAG, "Wrong manufacturer name"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } @@ -280,10 +280,13 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn)) break; - + if(!subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } uint8_t key_data[sizeof(uint64_t)] = {0}; @@ -292,15 +295,14 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl } if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Key"); + ret = SubGhzProtocolStatusErrorParserKey; break; } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_keeloq_stop(void* context) { @@ -669,7 +671,7 @@ uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_keeloq_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_keeloq_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -678,34 +680,24 @@ bool subghz_protocol_decoder_keeloq_serialize( subghz_protocol_keeloq_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + SubGhzProtocolStatus res = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_string_cstr( - flipper_format, "Manufacture", instance->manufacture_name)) { + if((res == SubGhzProtocolStatusOk) && + !flipper_format_write_string_cstr( + flipper_format, "Manufacture", instance->manufacture_name)) { FURI_LOG_E(TAG, "Unable to add manufacture name"); - res = false; + res = SubGhzProtocolStatusErrorParserOthers; } return res; } -bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderKeeloq* instance = context; - bool res = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_keeloq_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - res = true; - } while(false); - - return res; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_keeloq_const.min_count_bit_for_found); } void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/keeloq.h b/lib/subghz/protocols/keeloq.h index 7b1aaee2..59cd9cf9 100644 --- a/lib/subghz/protocols/keeloq.h +++ b/lib/subghz/protocols/keeloq.h @@ -48,9 +48,10 @@ bool subghz_protocol_keeloq_create_data( * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderKeeloq instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -104,9 +105,9 @@ uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderKeeloq instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return SubGhzProtocolStatus */ -bool subghz_protocol_decoder_keeloq_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_keeloq_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -115,9 +116,10 @@ bool subghz_protocol_decoder_keeloq_serialize( * Deserialize data SubGhzProtocolDecoderKeeloq. * @param context Pointer to a SubGhzProtocolDecoderKeeloq instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return SubGhzProtocolStatus */ -bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/kia.c b/lib/subghz/protocols/kia.c index a5d9e37e..1d134f7b 100644 --- a/lib/subghz/protocols/kia.c +++ b/lib/subghz/protocols/kia.c @@ -230,7 +230,7 @@ uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_kia_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -239,21 +239,12 @@ bool subghz_protocol_decoder_kia_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != subghz_protocol_kia_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_kia_const.min_count_bit_for_found); } void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/kia.h b/lib/subghz/protocols/kia.h index a9afcf14..749ff8af 100644 --- a/lib/subghz/protocols/kia.h +++ b/lib/subghz/protocols/kia.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderKIA instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_kia_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_kia_serialize( * Deserialize data SubGhzProtocolDecoderKIA. * @param context Pointer to a SubGhzProtocolDecoderKIA instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 2c8de0d2..cd027b99 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -260,56 +260,56 @@ uint8_t subghz_protocol_decoder_kinggates_stylo_4k_get_hash_data(void* context) &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_kinggates_stylo_4k_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_kinggates_stylo_4k_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); uint8_t key_data[sizeof(uint64_t)] = {0}; for(size_t i = 0; i < sizeof(uint64_t); i++) { key_data[sizeof(uint64_t) - i - 1] = (instance->data >> (i * 8)) & 0xFF; } - if(res && !flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Data"); - res = false; + ret = SubGhzProtocolStatusErrorParserOthers; } - return res; - - return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + return ret; } -bool subghz_protocol_decoder_kinggates_stylo_4k_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_kinggates_stylo_4k_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_kinggates_stylo_4k_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_kinggates_stylo_4k_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } uint8_t key_data[sizeof(uint64_t)] = {0}; if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Missing Data"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } for(uint8_t i = 0; i < sizeof(uint64_t); i++) { instance->data = instance->data << 8 | key_data[i]; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/kinggates_stylo_4k.h b/lib/subghz/protocols/kinggates_stylo_4k.h index c9f1cf38..64cbb904 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.h +++ b/lib/subghz/protocols/kinggates_stylo_4k.h @@ -49,9 +49,9 @@ uint8_t subghz_protocol_decoder_kinggates_stylo_4k_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_kinggates_stylo_4k_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_kinggates_stylo_4k_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -60,9 +60,9 @@ bool subghz_protocol_decoder_kinggates_stylo_4k_serialize( * Deserialize data SubGhzProtocolDecoderKingGates_stylo_4k. * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_kinggates_stylo_4k_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_kinggates_stylo_4k_deserialize( void* context, FlipperFormat* flipper_format); diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index 2fc8b20c..8d373579 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -147,31 +147,31 @@ static bool subghz_protocol_encoder_linear_get_upload(SubGhzProtocolEncoderLinea return true; } -bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderLinear* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_linear_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_linear_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_linear_get_upload(instance)) break; + if(!subghz_protocol_encoder_linear_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_linear_stop(void* context) { @@ -300,7 +300,7 @@ uint8_t subghz_protocol_decoder_linear_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_linear_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_linear_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -309,22 +309,12 @@ bool subghz_protocol_decoder_linear_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_linear_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_linear_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderLinear* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_linear_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, flipper_format, subghz_protocol_linear_const.min_count_bit_for_found); } void subghz_protocol_decoder_linear_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/linear.h b/lib/subghz/protocols/linear.h index 923337ac..b692b911 100644 --- a/lib/subghz/protocols/linear.h +++ b/lib/subghz/protocols/linear.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_linear_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderLinear instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_linear_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderLinear instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_linear_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_linear_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_linear_serialize( * Deserialize data SubGhzProtocolDecoderLinear. * @param context Pointer to a SubGhzProtocolDecoderLinear instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_linear_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_linear_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c index 869edac8..97ac5cc5 100644 --- a/lib/subghz/protocols/linear_delta3.c +++ b/lib/subghz/protocols/linear_delta3.c @@ -150,33 +150,32 @@ static bool return true; } -bool subghz_protocol_encoder_linear_delta3_deserialize( +SubGhzProtocolStatus subghz_protocol_encoder_linear_delta3_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderLinearDelta3* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_linear_delta3_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_linear_delta3_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_linear_delta3_get_upload(instance)) break; + if(!subghz_protocol_encoder_linear_delta3_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_linear_delta3_stop(void* context) { @@ -312,7 +311,7 @@ uint8_t subghz_protocol_decoder_linear_delta3_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8)); } -bool subghz_protocol_decoder_linear_delta3_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_linear_delta3_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -321,24 +320,15 @@ bool subghz_protocol_decoder_linear_delta3_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_linear_delta3_deserialize( +SubGhzProtocolStatus subghz_protocol_decoder_linear_delta3_deserialize( void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderLinearDelta3* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_linear_delta3_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_linear_delta3_const.min_count_bit_for_found); } void subghz_protocol_decoder_linear_delta3_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/linear_delta3.h b/lib/subghz/protocols/linear_delta3.h index 2f0a32e6..22f6730f 100644 --- a/lib/subghz/protocols/linear_delta3.h +++ b/lib/subghz/protocols/linear_delta3.h @@ -28,11 +28,10 @@ void subghz_protocol_encoder_linear_delta3_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderLinearDelta3 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_linear_delta3_deserialize( - void* context, - FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_linear_delta3_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -86,9 +85,9 @@ uint8_t subghz_protocol_decoder_linear_delta3_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_linear_delta3_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_linear_delta3_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -97,11 +96,10 @@ bool subghz_protocol_decoder_linear_delta3_serialize( * Deserialize data SubGhzProtocolDecoderLinearDelta3. * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_linear_delta3_deserialize( - void* context, - FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_linear_delta3_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/magellan.c b/lib/subghz/protocols/magellan.c index 71497525..1b8eccc3 100644 --- a/lib/subghz/protocols/magellan.c +++ b/lib/subghz/protocols/magellan.c @@ -150,31 +150,31 @@ static bool subghz_protocol_encoder_magellan_get_upload(SubGhzProtocolEncoderMag return true; } -bool subghz_protocol_encoder_magellan_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_magellan_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderMagellan* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_magellan_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_magellan_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_magellan_get_upload(instance)) break; + if(!subghz_protocol_encoder_magellan_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_magellan_stop(void* context) { @@ -397,7 +397,7 @@ uint8_t subghz_protocol_decoder_magellan_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_magellan_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_magellan_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -406,22 +406,14 @@ bool subghz_protocol_decoder_magellan_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_magellan_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_magellan_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderMagellan* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_magellan_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_magellan_const.min_count_bit_for_found); } void subghz_protocol_decoder_magellan_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/magellan.h b/lib/subghz/protocols/magellan.h index a179c9cb..e0fb7ca5 100644 --- a/lib/subghz/protocols/magellan.h +++ b/lib/subghz/protocols/magellan.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_magellan_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderMagellan instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_magellan_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_magellan_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_magellan_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderMagellan instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_magellan_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_magellan_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_magellan_serialize( * Deserialize data SubGhzProtocolDecoderMagellan. * @param context Pointer to a SubGhzProtocolDecoderMagellan instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_magellan_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_magellan_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index d557c29b..fc4aa0dc 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -188,18 +188,17 @@ static void subghz_protocol_marantec_remote_controller(SubGhzBlockGeneric* insta instance->serial = ((instance->data >> 12) & 0xFFFFFF00) | ((instance->data >> 8) & 0xFF); } -bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderMarantec* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_marantec_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_marantec_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter @@ -209,11 +208,9 @@ bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* subghz_protocol_marantec_remote_controller(&instance->generic); subghz_protocol_encoder_marantec_get_upload(instance); instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_marantec_stop(void* context) { @@ -346,7 +343,7 @@ uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_marantec_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_marantec_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -355,22 +352,14 @@ bool subghz_protocol_decoder_marantec_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderMarantec* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_marantec_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_marantec_const.min_count_bit_for_found); } void subghz_protocol_decoder_marantec_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/marantec.h b/lib/subghz/protocols/marantec.h index e330ccf1..485c563b 100644 --- a/lib/subghz/protocols/marantec.h +++ b/lib/subghz/protocols/marantec.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_marantec_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderMarantec instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderMarantec instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_marantec_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_marantec_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_marantec_serialize( * Deserialize data SubGhzProtocolDecoderMarantec. * @param context Pointer to a SubGhzProtocolDecoderMarantec instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index 05b5b689..ba58bc44 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -175,31 +175,31 @@ static bool subghz_protocol_encoder_megacode_get_upload(SubGhzProtocolEncoderMeg return true; } -bool subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderMegaCode* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_megacode_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_megacode_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_megacode_get_upload(instance)) break; + if(!subghz_protocol_encoder_megacode_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_megacode_stop(void* context) { @@ -381,7 +381,7 @@ uint8_t subghz_protocol_decoder_megacode_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_megacode_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_megacode_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -390,22 +390,14 @@ bool subghz_protocol_decoder_megacode_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_megacode_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_megacode_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderMegaCode* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_megacode_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_megacode_const.min_count_bit_for_found); } void subghz_protocol_decoder_megacode_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/megacode.h b/lib/subghz/protocols/megacode.h index e31434fa..616ecdf6 100644 --- a/lib/subghz/protocols/megacode.h +++ b/lib/subghz/protocols/megacode.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_megacode_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderMegaCode instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_megacode_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderMegaCode instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_megacode_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_megacode_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_megacode_serialize( * Deserialize data SubGhzProtocolDecoderMegaCode. * @param context Pointer to a SubGhzProtocolDecoderMegaCode instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_megacode_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_megacode_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index c8126b1e..d7731dca 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -154,31 +154,31 @@ static bool return true; } -bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderNeroRadio* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_nero_radio_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_nero_radio_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_nero_radio_get_upload(instance)) break; + if(!subghz_protocol_encoder_nero_radio_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_nero_radio_stop(void* context) { @@ -343,7 +343,7 @@ uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_nero_radio_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nero_radio_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -352,22 +352,14 @@ bool subghz_protocol_decoder_nero_radio_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderNeroRadio* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_nero_radio_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_nero_radio_const.min_count_bit_for_found); } void subghz_protocol_decoder_nero_radio_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/nero_radio.h b/lib/subghz/protocols/nero_radio.h index 361da617..0598aee6 100644 --- a/lib/subghz/protocols/nero_radio.h +++ b/lib/subghz/protocols/nero_radio.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_nero_radio_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderNeroRadio instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderNeroRadio instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nero_radio_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nero_radio_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_nero_radio_serialize( * Deserialize data SubGhzProtocolDecoderNeroRadio. * @param context Pointer to a SubGhzProtocolDecoderNeroRadio instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index b124b717..09cd0255 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -148,31 +148,31 @@ static bool return true; } -bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderNeroSketch* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_nero_sketch_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_nero_sketch_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_nero_sketch_get_upload(instance)) break; + if(!subghz_protocol_encoder_nero_sketch_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_nero_sketch_stop(void* context) { @@ -328,7 +328,7 @@ uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_nero_sketch_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nero_sketch_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -337,22 +337,14 @@ bool subghz_protocol_decoder_nero_sketch_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderNeroSketch* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_nero_sketch_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_nero_sketch_const.min_count_bit_for_found); } void subghz_protocol_decoder_nero_sketch_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/nero_sketch.h b/lib/subghz/protocols/nero_sketch.h index ac87fb00..b557772d 100644 --- a/lib/subghz/protocols/nero_sketch.h +++ b/lib/subghz/protocols/nero_sketch.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_nero_sketch_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderNeroSketch instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderNeroSketch instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nero_sketch_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nero_sketch_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_nero_sketch_serialize( * Deserialize data SubGhzProtocolDecoderNeroSketch. * @param context Pointer to a SubGhzProtocolDecoderNeroSketch instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index a57d5f4d..af81d9f9 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -129,13 +129,14 @@ static bool subghz_protocol_encoder_nice_flo_get_upload(SubGhzProtocolEncoderNic return true; } -bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderNiceFlo* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit < @@ -143,19 +144,21 @@ bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* (instance->generic.data_count_bit > 2 * subghz_protocol_nice_flo_const.min_count_bit_for_found)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_nice_flo_get_upload(instance)) break; + if(!subghz_protocol_encoder_nice_flo_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_nice_flo_stop(void* context) { @@ -280,7 +283,7 @@ uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_nice_flo_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nice_flo_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -289,12 +292,14 @@ bool subghz_protocol_decoder_nice_flo_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderNiceFlo* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit < @@ -302,9 +307,9 @@ bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* (instance->generic.data_count_bit > 2 * subghz_protocol_nice_flo_const.min_count_bit_for_found)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/nice_flo.h b/lib/subghz/protocols/nice_flo.h index e382e614..9a4b53d1 100644 --- a/lib/subghz/protocols/nice_flo.h +++ b/lib/subghz/protocols/nice_flo.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_nice_flo_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderNiceFlo instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderNiceFlo instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nice_flo_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nice_flo_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_nice_flo_serialize( * Deserialize data SubGhzProtocolDecoderNiceFlo. * @param context Pointer to a SubGhzProtocolDecoderNiceFlo instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index dd5521a6..d8f5a070 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -417,51 +417,55 @@ uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_nice_flor_s_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nice_flor_s_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderNiceFlorS* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { - if(res && + if((ret == SubGhzProtocolStatusOk) && !flipper_format_write_uint32(flipper_format, "Data", (uint32_t*)&instance->data, 1)) { FURI_LOG_E(TAG, "Unable to add Data"); - res = false; + ret = SubGhzProtocolStatusErrorParserOthers; } } - return res; + return ret; } -bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderNiceFlorS* instance = context; - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { break; } if((instance->generic.data_count_bit != subghz_protocol_nice_flor_s_const.min_count_bit_for_found) && (instance->generic.data_count_bit != NICE_ONE_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; break; } if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } uint32_t temp = 0; if(!flipper_format_read_uint32(flipper_format, "Data", (uint32_t*)&temp, 1)) { FURI_LOG_E(TAG, "Missing Data"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } instance->data = (uint64_t)temp; } - - ret = true; } while(false); return ret; } diff --git a/lib/subghz/protocols/nice_flor_s.h b/lib/subghz/protocols/nice_flor_s.h index 593a7915..1ce61149 100644 --- a/lib/subghz/protocols/nice_flor_s.h +++ b/lib/subghz/protocols/nice_flor_s.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderNiceFlorS instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nice_flor_s_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_nice_flor_s_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_nice_flor_s_serialize( * Deserialize data SubGhzProtocolDecoderNiceFlorS. * @param context Pointer to a SubGhzProtocolDecoderNiceFlorS instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index b3d6f1e9..4ed9766e 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -132,31 +132,31 @@ static bool return true; } -bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderPhoenix_V2* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_phoenix_v2_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_phoenix_v2_get_upload(instance)) break; + if(!subghz_protocol_encoder_phoenix_v2_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_phoenix_v2_stop(void* context) { @@ -293,7 +293,7 @@ uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_phoenix_v2_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_phoenix_v2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -302,22 +302,14 @@ bool subghz_protocol_decoder_phoenix_v2_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderPhoenix_V2* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_phoenix_v2_const.min_count_bit_for_found); } void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/phoenix_v2.h b/lib/subghz/protocols/phoenix_v2.h index 48487535..0724de1f 100644 --- a/lib/subghz/protocols/phoenix_v2.h +++ b/lib/subghz/protocols/phoenix_v2.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_phoenix_v2_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_phoenix_v2_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_phoenix_v2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_phoenix_v2_serialize( * Deserialize data SubGhzProtocolDecoderPhoenix_V2. * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 1e8d10e9..d03282f7 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -192,18 +192,17 @@ static void subghz_protocol_power_smart_remote_controller(SubGhzBlockGeneric* in instance->cnt = ((instance->data >> 49) & 0x3F); } -bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderPowerSmart* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_power_smart_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_power_smart_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter @@ -213,11 +212,9 @@ bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperForma subghz_protocol_power_smart_remote_controller(&instance->generic); subghz_protocol_encoder_power_smart_get_upload(instance); instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_power_smart_stop(void* context) { @@ -345,7 +342,7 @@ uint8_t subghz_protocol_decoder_power_smart_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_power_smart_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_power_smart_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -354,22 +351,14 @@ bool subghz_protocol_decoder_power_smart_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderPowerSmart* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_power_smart_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_power_smart_const.min_count_bit_for_found); } void subghz_protocol_decoder_power_smart_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/power_smart.h b/lib/subghz/protocols/power_smart.h index 806729f8..5687cf8b 100644 --- a/lib/subghz/protocols/power_smart.h +++ b/lib/subghz/protocols/power_smart.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_power_smart_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_power_smart_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_power_smart_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_power_smart_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_power_smart_serialize( * Deserialize data SubGhzProtocolDecoderPowerSmart. * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index 7fc8f652..aa15b8b4 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -141,39 +141,41 @@ static bool return true; } -bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderPrinceton* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_princeton_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_princeton_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorParserTe; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_princeton_get_upload(instance)) break; + if(!subghz_protocol_encoder_princeton_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_princeton_stop(void* context) { @@ -308,46 +310,48 @@ uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_princeton_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_princeton_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderPrinceton* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { FURI_LOG_E(TAG, "Unable to add TE"); - res = false; + ret = SubGhzProtocolStatusErrorParserTe; } - return res; + return ret; } -bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderPrinceton* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_princeton_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_princeton_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); + ret = SubGhzProtocolStatusErrorParserTe; break; } - res = true; } while(false); - return res; + return ret; } void subghz_protocol_decoder_princeton_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/princeton.h b/lib/subghz/protocols/princeton.h index f63004db..da73b6c3 100644 --- a/lib/subghz/protocols/princeton.h +++ b/lib/subghz/protocols/princeton.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_princeton_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderPrinceton instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderPrinceton instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_princeton_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_princeton_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_princeton_serialize( * Deserialize data SubGhzProtocolDecoderPrinceton. * @param context Pointer to a SubGhzProtocolDecoderPrinceton instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index ac3492e7..66358698 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -259,12 +259,13 @@ void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t durati } } -bool subghz_protocol_decoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); UNUSED(context); UNUSED(flipper_format); //ToDo stub, for backwards compatibility - return true; + return SubGhzProtocolStatusOk; } void subghz_protocol_decoder_raw_get_string(void* context, FuriString* output) { @@ -342,25 +343,32 @@ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* } while(false); } -bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderRAW* instance = context; - bool res = false; + SubGhzProtocolStatus res = SubGhzProtocolStatusError; FuriString* temp_str; temp_str = furi_string_alloc(); do { if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + res = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_string(flipper_format, "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); + res = SubGhzProtocolStatusErrorParserOthers; break; } furi_string_set(instance->file_name, temp_str); - res = subghz_protocol_encoder_raw_worker_init(instance); + if(!subghz_protocol_encoder_raw_worker_init(instance)) { + res = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } + res = SubGhzProtocolStatusOk; } while(false); furi_string_free(temp_str); return res; diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 44c7faec..4f67a4e2 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -73,9 +73,10 @@ void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t durati * Deserialize data SubGhzProtocolDecoderRAW. * @param context Pointer to a SubGhzProtocolDecoderRAW instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_raw_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_raw_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. @@ -132,9 +133,10 @@ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderRAW instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting the level and duration of the upload to be loaded into DMA. diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c index 955104bc..bf8de10c 100644 --- a/lib/subghz/protocols/scher_khan.c +++ b/lib/subghz/protocols/scher_khan.c @@ -248,7 +248,7 @@ uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_scher_khan_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -257,7 +257,8 @@ bool subghz_protocol_decoder_scher_khan_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderScherKhan* instance = context; return subghz_block_generic_deserialize(&instance->generic, flipper_format); diff --git a/lib/subghz/protocols/scher_khan.h b/lib/subghz/protocols/scher_khan.h index b7e84ea1..58545069 100644 --- a/lib/subghz/protocols/scher_khan.h +++ b/lib/subghz/protocols/scher_khan.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_scher_khan_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_scher_khan_serialize( * Deserialize data SubGhzProtocolDecoderScherKhan. * @param context Pointer to a SubGhzProtocolDecoderScherKhan instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index a1161101..783351c6 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -264,18 +264,17 @@ static bool subghz_protocol_secplus_v1_encode(SubGhzProtocolEncoderSecPlus_v1* i return true; } -bool subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderSecPlus_v1* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - 2 * subghz_protocol_secplus_v1_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + 2 * subghz_protocol_secplus_v1_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } //optional parameter parameter @@ -283,9 +282,12 @@ bool subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); if(!subghz_protocol_secplus_v1_encode(instance)) { + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!subghz_protocol_encoder_secplus_v1_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + ; break; } @@ -295,15 +297,14 @@ bool subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat } if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Key"); + ret = SubGhzProtocolStatusErrorParserKey; break; } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_secplus_v1_stop(void* context) { @@ -516,7 +517,7 @@ uint8_t subghz_protocol_decoder_secplus_v1_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_secplus_v1_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_secplus_v1_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -525,22 +526,14 @@ bool subghz_protocol_decoder_secplus_v1_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderSecPlus_v1* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - 2 * subghz_protocol_secplus_v1_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + 2 * subghz_protocol_secplus_v1_const.min_count_bit_for_found); } bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed) { diff --git a/lib/subghz/protocols/secplus_v1.h b/lib/subghz/protocols/secplus_v1.h index 99480b62..3490f2ca 100644 --- a/lib/subghz/protocols/secplus_v1.h +++ b/lib/subghz/protocols/secplus_v1.h @@ -27,9 +27,10 @@ void subghz_protocol_encoder_secplus_v1_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderSecPlus_v1 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -83,9 +84,9 @@ uint8_t subghz_protocol_decoder_secplus_v1_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderSecPlus_v1 instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_secplus_v1_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_secplus_v1_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -94,9 +95,10 @@ bool subghz_protocol_decoder_secplus_v1_serialize( * Deserialize data SubGhzProtocolDecoderSecPlus_v1. * @param context Pointer to a SubGhzProtocolDecoderSecPlus_v1 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format); /** * Validation of fixed parts SubGhzProtocolDecoderSecPlus_v1. diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index f7262bd1..4a3815f0 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -503,24 +503,24 @@ static void instance->encoder.size_upload = index; } -bool subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderSecPlus_v2* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_secplus_v2_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_secplus_v2_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } uint8_t key_data[sizeof(uint64_t)] = {0}; if(!flipper_format_read_hex( flipper_format, "Secplus_packet_1", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Secplus_packet_1"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } for(uint8_t i = 0; i < sizeof(uint64_t); i++) { @@ -541,6 +541,7 @@ bool subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat } if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Key"); + ret = SubGhzProtocolStatusErrorParserKey; break; } @@ -550,15 +551,14 @@ bool subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat if(!flipper_format_update_hex( flipper_format, "Secplus_packet_1", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Secplus_packet_1"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_secplus_v2_stop(void* context) { @@ -754,58 +754,59 @@ uint8_t subghz_protocol_decoder_secplus_v2_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_secplus_v2_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_secplus_v2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderSecPlus_v2* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); uint8_t key_data[sizeof(uint64_t)] = {0}; for(size_t i = 0; i < sizeof(uint64_t); i++) { key_data[sizeof(uint64_t) - i - 1] = (instance->secplus_packet_1 >> (i * 8)) & 0xFF; } - if(res && + if((ret == SubGhzProtocolStatusOk) && !flipper_format_write_hex(flipper_format, "Secplus_packet_1", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to add Secplus_packet_1"); - res = false; + ret = SubGhzProtocolStatusErrorParserOthers; } - return res; + return ret; } -bool subghz_protocol_decoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderSecPlus_v2* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_secplus_v2_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_secplus_v2_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } uint8_t key_data[sizeof(uint64_t)] = {0}; if(!flipper_format_read_hex( flipper_format, "Secplus_packet_1", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Missing Secplus_packet_1"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } for(uint8_t i = 0; i < sizeof(uint64_t); i++) { instance->secplus_packet_1 = instance->secplus_packet_1 << 8 | key_data[i]; } - res = true; } while(false); - return res; + return ret; } void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/secplus_v2.h b/lib/subghz/protocols/secplus_v2.h index bea8cdb5..0eea732a 100644 --- a/lib/subghz/protocols/secplus_v2.h +++ b/lib/subghz/protocols/secplus_v2.h @@ -27,9 +27,10 @@ void subghz_protocol_encoder_secplus_v2_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderSecPlus_v2 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -102,9 +103,9 @@ uint8_t subghz_protocol_decoder_secplus_v2_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderSecPlus_v2 instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_secplus_v2_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_secplus_v2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -113,9 +114,10 @@ bool subghz_protocol_decoder_secplus_v2_serialize( * Deserialize data SubGhzProtocolDecoderSecPlus_v2. * @param context Pointer to a SubGhzProtocolDecoderSecPlus_v2 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_secplus_v2_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/smc5326.c b/lib/subghz/protocols/smc5326.c index 9c9b5d4f..bfb36b76 100644 --- a/lib/subghz/protocols/smc5326.c +++ b/lib/subghz/protocols/smc5326.c @@ -155,39 +155,41 @@ static bool subghz_protocol_encoder_smc5326_get_upload(SubGhzProtocolEncoderSMC5 return true; } -bool subghz_protocol_encoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_encoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderSMC5326* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_smc5326_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_smc5326_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorParserTe; break; } //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - if(!subghz_protocol_encoder_smc5326_get_upload(instance)) break; + if(!subghz_protocol_encoder_smc5326_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } instance->encoder.is_running = true; - - res = true; } while(false); - return res; + return ret; } void subghz_protocol_encoder_smc5326_stop(void* context) { @@ -313,46 +315,48 @@ uint8_t subghz_protocol_decoder_smc5326_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_smc5326_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_smc5326_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderSMC5326* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { FURI_LOG_E(TAG, "Unable to add TE"); - res = false; + ret = SubGhzProtocolStatusErrorParserTe; } - return res; + return ret; } -bool subghz_protocol_decoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderSMC5326* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_smc5326_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_smc5326_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { FURI_LOG_E(TAG, "Missing TE"); + ret = SubGhzProtocolStatusErrorParserTe; break; } - res = true; } while(false); - return res; + return ret; } static void subghz_protocol_smc5326_get_event_serialize(uint8_t event, FuriString* output) { diff --git a/lib/subghz/protocols/smc5326.h b/lib/subghz/protocols/smc5326.h index ddc954bd..911226cf 100644 --- a/lib/subghz/protocols/smc5326.h +++ b/lib/subghz/protocols/smc5326.h @@ -28,9 +28,10 @@ void subghz_protocol_encoder_smc5326_free(void* context); * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderSMC5326 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_encoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_encoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format); /** * Forced transmission stop. @@ -84,9 +85,9 @@ uint8_t subghz_protocol_decoder_smc5326_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_smc5326_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_smc5326_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -95,9 +96,10 @@ bool subghz_protocol_decoder_smc5326_serialize( * Deserialize data SubGhzProtocolDecoderSMC5326. * @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 00bb8a8c..1e3cdc54 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -379,37 +379,39 @@ uint8_t subghz_protocol_decoder_somfy_keytis_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_somfy_keytis_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_somfy_keytis_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderSomfyKeytis* instance = context; - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_uint32( - flipper_format, "Duration_Counter", &instance->press_duration_counter, 1)) { + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_write_uint32( + flipper_format, "Duration_Counter", &instance->press_duration_counter, 1)) { FURI_LOG_E(TAG, "Unable to add Duration_Counter"); - res = false; + ret = SubGhzProtocolStatusErrorParserOthers; } - return res; + return ret; } -bool subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderSomfyKeytis* instance = context; - bool res = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_somfy_keytis_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_somfy_keytis_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { break; } if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } if(!flipper_format_read_uint32( @@ -418,12 +420,12 @@ bool subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperForm (uint32_t*)&instance->press_duration_counter, 1)) { FURI_LOG_E(TAG, "Missing Duration_Counter"); + ret = SubGhzProtocolStatusErrorParserOthers; break; } - res = true; } while(false); - return res; + return ret; } void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/somfy_keytis.h b/lib/subghz/protocols/somfy_keytis.h index 3b595061..15f63c43 100644 --- a/lib/subghz/protocols/somfy_keytis.h +++ b/lib/subghz/protocols/somfy_keytis.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_somfy_keytis_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderSomfyKeytis instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_somfy_keytis_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_somfy_keytis_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_somfy_keytis_serialize( * Deserialize data SubGhzProtocolDecoderSomfyKeytis. * @param context Pointer to a SubGhzProtocolDecoderSomfyKeytis instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 362b1b07..523bef6e 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -336,7 +336,7 @@ uint8_t subghz_protocol_decoder_somfy_telis_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_somfy_telis_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_somfy_telis_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -345,22 +345,14 @@ bool subghz_protocol_decoder_somfy_telis_serialize( return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -bool subghz_protocol_decoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderSomfyTelis* instance = context; - bool ret = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - if(instance->generic.data_count_bit != - subghz_protocol_somfy_telis_const.min_count_bit_for_found) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); - break; - } - ret = true; - } while(false); - return ret; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_somfy_telis_const.min_count_bit_for_found); } void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/somfy_telis.h b/lib/subghz/protocols/somfy_telis.h index a6a9fa5b..c7ddc3ca 100644 --- a/lib/subghz/protocols/somfy_telis.h +++ b/lib/subghz/protocols/somfy_telis.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_somfy_telis_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderSomfyTelis instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_somfy_telis_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_somfy_telis_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_somfy_telis_serialize( * Deserialize data SubGhzProtocolDecoderSomfyTelis. * @param context Pointer to a SubGhzProtocolDecoderSomfyTelis instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 8e5e07c1..e3b7d4a2 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -316,7 +316,7 @@ uint8_t subghz_protocol_decoder_star_line_get_hash_data(void* context) { &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -bool subghz_protocol_decoder_star_line_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_star_line_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { @@ -324,34 +324,29 @@ bool subghz_protocol_decoder_star_line_serialize( SubGhzProtocolDecoderStarLine* instance = context; subghz_protocol_star_line_check_remote_controller( &instance->generic, instance->keystore, &instance->manufacture_name); - bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + SubGhzProtocolStatus ret = + subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - if(res && !flipper_format_write_string_cstr( - flipper_format, "Manufacture", instance->manufacture_name)) { + if((ret == SubGhzProtocolStatusOk) && + !flipper_format_write_string_cstr( + flipper_format, "Manufacture", instance->manufacture_name)) { FURI_LOG_E(TAG, "Unable to add manufacture name"); - res = false; + ret = SubGhzProtocolStatusErrorParserOthers; } - if(res && instance->generic.data_count_bit != - subghz_protocol_star_line_const.min_count_bit_for_found) { + if((ret == SubGhzProtocolStatusOk) && + instance->generic.data_count_bit != + subghz_protocol_star_line_const.min_count_bit_for_found) { FURI_LOG_E(TAG, "Wrong number of bits in key"); - res = false; + ret = SubGhzProtocolStatusErrorParserOthers; } - return res; + return ret; } -bool subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderStarLine* instance = context; - bool res = false; - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - FURI_LOG_E(TAG, "Deserialize error"); - break; - } - res = true; - } while(false); - - return res; + return subghz_block_generic_deserialize(&instance->generic, flipper_format); } void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/star_line.h b/lib/subghz/protocols/star_line.h index 34c25150..6f352f24 100644 --- a/lib/subghz/protocols/star_line.h +++ b/lib/subghz/protocols/star_line.h @@ -50,9 +50,9 @@ uint8_t subghz_protocol_decoder_star_line_get_hash_data(void* context); * @param context Pointer to a SubGhzProtocolDecoderStarLine instance * @param flipper_format Pointer to a FlipperFormat instance * @param preset The modulation on which the signal was received, SubGhzRadioPreset - * @return true On success + * @return status */ -bool subghz_protocol_decoder_star_line_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_star_line_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); @@ -61,9 +61,10 @@ bool subghz_protocol_decoder_star_line_serialize( * Deserialize data SubGhzProtocolDecoderStarLine. * @param context Pointer to a SubGhzProtocolDecoderStarLine instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format); /** * Getting a textual representation of the received data. diff --git a/lib/subghz/transmitter.c b/lib/subghz/transmitter.c index 8507ee05..81be143b 100644 --- a/lib/subghz/transmitter.c +++ b/lib/subghz/transmitter.c @@ -47,9 +47,10 @@ bool subghz_transmitter_stop(SubGhzTransmitter* instance) { return ret; } -bool subghz_transmitter_deserialize(SubGhzTransmitter* instance, FlipperFormat* flipper_format) { +SubGhzProtocolStatus + subghz_transmitter_deserialize(SubGhzTransmitter* instance, FlipperFormat* flipper_format) { furi_assert(instance); - bool ret = false; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; if(instance->protocol && instance->protocol->encoder && instance->protocol->encoder->deserialize) { ret = diff --git a/lib/subghz/transmitter.h b/lib/subghz/transmitter.h index cce98a46..a1c4cda0 100644 --- a/lib/subghz/transmitter.h +++ b/lib/subghz/transmitter.h @@ -39,9 +39,10 @@ bool subghz_transmitter_stop(SubGhzTransmitter* instance); * Deserialize and generating an upload to send. * @param instance Pointer to a SubGhzTransmitter instance * @param flipper_format Pointer to a FlipperFormat instance - * @return true On success + * @return status */ -bool subghz_transmitter_deserialize(SubGhzTransmitter* instance, FlipperFormat* flipper_format); +SubGhzProtocolStatus + subghz_transmitter_deserialize(SubGhzTransmitter* instance, FlipperFormat* flipper_format); /** * Getting the level and duration of the upload to be loaded into DMA. diff --git a/lib/subghz/types.h b/lib/subghz/types.h index 1b8ef6a1..09eb07ee 100644 --- a/lib/subghz/types.h +++ b/lib/subghz/types.h @@ -29,14 +29,36 @@ typedef struct { size_t data_size; } SubGhzRadioPreset; +typedef enum { + SubGhzProtocolStatusOk = 0, + // Errors + SubGhzProtocolStatusError = (-1), ///< General unclassified error + // Serialize/De-serialize + SubGhzProtocolStatusErrorParserHeader = (-2), ///< Missing or invalid file header + SubGhzProtocolStatusErrorParserFrequency = (-3), ///< Missing `Frequency` + SubGhzProtocolStatusErrorParserPreset = (-4), ///< Missing `Preset` + SubGhzProtocolStatusErrorParserCustomPreset = (-5), ///< Missing `Custom_preset_module` + SubGhzProtocolStatusErrorParserProtocolName = (-6), ///< Missing `Protocol` name + SubGhzProtocolStatusErrorParserBitCount = (-7), ///< Missing `Bit` + SubGhzProtocolStatusErrorParserKey = (-8), ///< Missing `Key` + SubGhzProtocolStatusErrorParserTe = (-9), ///< Missing `Te` + SubGhzProtocolStatusErrorParserOthers = (-10), ///< Missing some other mandatory keys + // Invalid data + SubGhzProtocolStatusErrorValueBitCount = (-11), ///< Invalid bit count value + // Encoder issue + SubGhzProtocolStatusErrorEncoderGetUpload = (-12), ///< Payload encoder failure + // Special Values + SubGhzProtocolStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization. +} SubGhzProtocolStatus; + // Allocator and Deallocator typedef void* (*SubGhzAlloc)(SubGhzEnvironment* environment); typedef void (*SubGhzFree)(void* context); // Serialize and Deserialize -typedef bool ( +typedef SubGhzProtocolStatus ( *SubGhzSerialize)(void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); -typedef bool (*SubGhzDeserialize)(void* context, FlipperFormat* flipper_format); +typedef SubGhzProtocolStatus (*SubGhzDeserialize)(void* context, FlipperFormat* flipper_format); // Decoder specific typedef void (*SubGhzDecoderFeed)(void* decoder, bool level, uint32_t duration); From 0b7d205253cb10e5f725d6113c721160c91239e4 Mon Sep 17 00:00:00 2001 From: Ethanol0001 <126507963+Ethanol0001@users.noreply.github.com> Date: Fri, 3 Mar 2023 10:15:17 -0600 Subject: [PATCH 09/23] Update clock_app.c (#2446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/plugins/clock/clock_app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/plugins/clock/clock_app.c b/applications/plugins/clock/clock_app.c index 9d87ff95..c938125b 100644 --- a/applications/plugins/clock/clock_app.c +++ b/applications/plugins/clock/clock_app.c @@ -56,7 +56,7 @@ static void clock_render_callback(Canvas* canvas, void* ctx) { 31, AlignLeft, AlignCenter, - (data->datetime.hour > 12) ? "PM" : "AM"); + (data->datetime.hour > 11) ? "PM" : "AM"); } canvas_set_font(canvas, FontSecondary); @@ -133,4 +133,4 @@ int32_t clock_app(void* p) { free(clock); return 0; -} \ No newline at end of file +} From 5d4057f7228b528896578ab6cf9d9a61b80a7c58 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Fri, 3 Mar 2023 21:07:41 +0300 Subject: [PATCH 10/23] Archive browser: update path on dir leave (#2455) --- applications/main/archive/helpers/archive_browser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index f5efca46..9a7973cb 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -510,12 +510,16 @@ void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) { browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); furi_string_set(browser->path, path); + file_browser_worker_folder_enter(browser->worker, path, idx_temp); } void archive_leave_dir(ArchiveBrowserView* 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); } From 4ab832cc4619d238347fba9517289a7b8b90faec Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Mar 2023 09:17:33 +0400 Subject: [PATCH 11/23] github: check API versions for all targets to match on gh build (#2459) * github: check API versions for all targets to match on gh build * typo fix * gh: forcing target mismatch to test pipeline * reverted API version change --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 689dd203..46d95ede 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,6 +44,16 @@ jobs: echo random_hash=$(openssl rand -base64 40 | shasum -a 256 | awk '{print $1}') >> $GITHUB_OUTPUT echo "event_type=$TYPE" >> $GITHUB_OUTPUT + - name: 'Check API versions' + run: | + set -e + N_API_HEADER_SIGNATURES=`ls -1 firmware/targets/f*/api_symbols.csv | xargs -I {} sh -c "head -n2 {} | md5sum" | sort -u | wc -l` + if [ $N_API_HEADER_SIGNATURES != 1 ] ; then + echo API versions aren\'t matching for available targets. Please update! + head -n2 firmware/targets/f*/api_symbols.csv + exit 1 + fi + - name: 'Make artifacts directory' run: | rm -rf artifacts From c0e0403b44f6fd3a2d1420eb48db663ef4d57d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= Date: Mon, 6 Mar 2023 08:44:26 +0100 Subject: [PATCH 12/23] Fix SD card CID parsing (#2463) The recent SD rewrite dropped a couple of lines from the CID parsing function resulting in zero manufacturing date displayed. Signed-off-by: Michal Suchanek --- firmware/targets/f7/fatfs/sd_spi_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/targets/f7/fatfs/sd_spi_io.c b/firmware/targets/f7/fatfs/sd_spi_io.c index 68903acf..e8e542b3 100644 --- a/firmware/targets/f7/fatfs/sd_spi_io.c +++ b/firmware/targets/f7/fatfs/sd_spi_io.c @@ -585,6 +585,8 @@ static SdSpiStatus sd_spi_get_cid(SD_CID* Cid) { Cid->ProdSN |= cid_data[12]; Cid->Reserved1 = (cid_data[13] & 0xF0) >> 4; Cid->ManufactYear = (cid_data[13] & 0x0F) << 4; + Cid->ManufactYear |= (cid_data[14] & 0xF0) >> 4; + Cid->ManufactMonth = (cid_data[14] & 0x0F); Cid->CID_CRC = (cid_data[15] & 0xFE) >> 1; Cid->Reserved2 = 1; From 9dd1fb64b7fbe7731dea5a93d530c3dc176f59ce Mon Sep 17 00:00:00 2001 From: GuruSteve Date: Mon, 6 Mar 2023 00:59:48 -0700 Subject: [PATCH 13/23] Fixed picopass load save file overrun (#2464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/plugins/picopass/picopass_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/plugins/picopass/picopass_device.c b/applications/plugins/picopass/picopass_device.c index ec0bc5af..53778cfb 100644 --- a/applications/plugins/picopass/picopass_device.c +++ b/applications/plugins/picopass/picopass_device.c @@ -167,6 +167,8 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo } size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0]; + // Fix for unpersonalized cards that have app_limit set to 0xFF + if(app_limit > PICOPASS_MAX_APP_LIMIT) app_limit = PICOPASS_MAX_APP_LIMIT; for(size_t i = 6; i < app_limit; i++) { furi_string_printf(temp_str, "Block %d", i); if(!flipper_format_read_hex( From eefca9f498ea346128db62d1072010aaf75db17e Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Tue, 7 Mar 2023 02:53:52 -0800 Subject: [PATCH 14/23] Support reseting iCx cards (#2451) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support reseting iCx cards * add submenu * Fix auth * switch key derivation to use same method * test system keys using both elite and standard kdf Co-authored-by: あく --- .../plugins/picopass/picopass_worker.c | 59 +++++++---- .../plugins/picopass/picopass_worker.h | 2 +- .../plugins/picopass/picopass_worker_i.h | 2 +- .../scenes/picopass_scene_card_menu.c | 13 +++ .../picopass/scenes/picopass_scene_config.h | 1 + .../picopass/scenes/picopass_scene_key_menu.c | 100 ++++++++++++++++++ .../scenes/picopass_scene_read_card.c | 4 +- .../picopass_scene_read_factory_success.c | 3 + .../scenes/picopass_scene_write_key.c | 2 +- 9 files changed, 161 insertions(+), 25 deletions(-) create mode 100644 applications/plugins/picopass/scenes/picopass_scene_key_menu.c diff --git a/applications/plugins/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c index 6d904478..024c5112 100644 --- a/applications/plugins/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -7,6 +7,9 @@ const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78}; const uint8_t picopass_factory_credit_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; const uint8_t picopass_factory_debit_key[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; +const uint8_t picopass_xice_key[] = {0x20, 0x20, 0x66, 0x66, 0x66, 0x66, 0x88, 0x88}; +const uint8_t picopass_xicl_key[] = {0x20, 0x20, 0x66, 0x66, 0x66, 0x66, 0x88, 0x88}; +const uint8_t picopass_xics_key[] = {0x66, 0x66, 0x20, 0x20, 0x66, 0x66, 0x88, 0x88}; static void picopass_worker_enable_field() { furi_hal_nfc_ll_txrx_on(); @@ -192,7 +195,7 @@ static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) { } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_diversifyKey(csn, picopass_iclass_key, div_key); + loclass_iclass_calc_div_key(csn, (uint8_t*)picopass_iclass_key, div_key, false); loclass_opt_doReaderMAC(ccnr, div_key, mac); return rfalPicoPassPollerCheck(mac, &chkRes); @@ -214,7 +217,7 @@ static ReturnCode picopass_auth_factory(uint8_t* csn, uint8_t* div_key) { } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_diversifyKey(csn, picopass_factory_debit_key, div_key); + loclass_iclass_calc_div_key(csn, (uint8_t*)picopass_factory_debit_key, div_key, false); loclass_opt_doReaderMAC(ccnr, div_key, mac); return rfalPicoPassPollerCheck(mac, &chkRes); @@ -224,7 +227,8 @@ static ReturnCode picopass_auth_dict( uint8_t* csn, PicopassPacs* pacs, uint8_t* div_key, - IclassEliteDictType dict_type) { + IclassEliteDictType dict_type, + bool elite) { rfalPicoPassReadCheckRes rcRes; rfalPicoPassCheckRes chkRes; @@ -269,7 +273,7 @@ static ReturnCode picopass_auth_dict( } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_iclass_calc_div_key(csn, key, div_key, true); + loclass_iclass_calc_div_key(csn, key, div_key, elite); loclass_opt_doReaderMAC(ccnr, div_key, mac); err = rfalPicoPassPollerCheck(mac, &chkRes); @@ -303,22 +307,35 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { return ERR_NONE; } - FURI_LOG_I(TAG, "Starting user dictionary attack"); + FURI_LOG_I(TAG, "Starting user dictionary attack [Elite KDF]"); err = picopass_auth_dict( AA1[PICOPASS_CSN_BLOCK_INDEX].data, pacs, AA1[PICOPASS_KD_BLOCK_INDEX].data, - IclassEliteDictTypeUser); + IclassEliteDictTypeUser, + true); if(err == ERR_NONE) { return ERR_NONE; } - FURI_LOG_I(TAG, "Starting system dictionary attack"); + FURI_LOG_I(TAG, "Starting system dictionary attack [Elite KDF]"); err = picopass_auth_dict( AA1[PICOPASS_CSN_BLOCK_INDEX].data, pacs, AA1[PICOPASS_KD_BLOCK_INDEX].data, - IclassEliteDictTypeFlipper); + IclassEliteDictTypeFlipper, + true); + if(err == ERR_NONE) { + return ERR_NONE; + } + + FURI_LOG_I(TAG, "Starting system dictionary attack [Standard KDF]"); + err = picopass_auth_dict( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, + pacs, + AA1[PICOPASS_KD_BLOCK_INDEX].data, + IclassEliteDictTypeFlipper, + false); if(err == ERR_NONE) { return ERR_NONE; } @@ -396,7 +413,7 @@ ReturnCode picopass_write_card(PicopassBlock* AA1) { } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key); + loclass_iclass_calc_div_key(selRes.CSN, (uint8_t*)picopass_iclass_key, div_key, false); loclass_opt_doReaderMAC(ccnr, div_key, mac); err = rfalPicoPassPollerCheck(mac, &chkRes); @@ -438,7 +455,7 @@ ReturnCode picopass_write_card(PicopassBlock* AA1) { return ERR_NONE; } -ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* newBlock) { +ReturnCode picopass_write_block(PicopassBlock* AA1, uint8_t blockNo, uint8_t* newBlock) { rfalPicoPassIdentifyRes idRes; rfalPicoPassSelectRes selRes; rfalPicoPassReadCheckRes rcRes; @@ -446,7 +463,6 @@ ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* ne ReturnCode err; - uint8_t div_key[8] = {0}; uint8_t mac[4] = {0}; uint8_t ccnr[12] = {0}; @@ -469,9 +485,12 @@ ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* ne } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_diversifyKey(selRes.CSN, pacs->key, div_key); - loclass_opt_doReaderMAC(ccnr, div_key, mac); + if(memcmp(selRes.CSN, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN) != 0) { + FURI_LOG_E(TAG, "Wrong CSN for write"); + return ERR_REQUEST; + } + loclass_opt_doReaderMAC(ccnr, AA1[PICOPASS_KD_BLOCK_INDEX].data, mac); err = rfalPicoPassPollerCheck(mac, &chkRes); if(err != ERR_NONE) { FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); @@ -489,7 +508,7 @@ ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* ne newBlock[5], newBlock[6], newBlock[7]}; - loclass_doMAC_N(data, sizeof(data), div_key, mac); + loclass_doMAC_N(data, sizeof(data), AA1[PICOPASS_KD_BLOCK_INDEX].data, mac); FURI_LOG_D( TAG, "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x", @@ -524,8 +543,8 @@ int32_t picopass_worker_task(void* context) { picopass_worker_detect(picopass_worker); } else if(picopass_worker->state == PicopassWorkerStateWrite) { picopass_worker_write(picopass_worker); - } else if(picopass_worker->state == PicopassWorkerStateWriteStandardKey) { - picopass_worker_write_standard_key(picopass_worker); + } else if(picopass_worker->state == PicopassWorkerStateWriteKey) { + picopass_worker_write_key(picopass_worker); } picopass_worker_disable_field(ERR_NONE); @@ -633,7 +652,7 @@ void picopass_worker_write(PicopassWorker* picopass_worker) { } } -void picopass_worker_write_standard_key(PicopassWorker* picopass_worker) { +void picopass_worker_write_key(PicopassWorker* picopass_worker) { PicopassDeviceData* dev_data = picopass_worker->dev_data; PicopassBlock* AA1 = dev_data->AA1; PicopassPacs* pacs = &dev_data->pacs; @@ -646,7 +665,7 @@ void picopass_worker_write_standard_key(PicopassWorker* picopass_worker) { uint8_t* oldKey = AA1[PICOPASS_KD_BLOCK_INDEX].data; uint8_t newKey[PICOPASS_BLOCK_LEN] = {0}; - loclass_diversifyKey(csn, picopass_iclass_key, newKey); + loclass_iclass_calc_div_key(csn, pacs->key, newKey, false); if((fuses & 0x80) == 0x80) { FURI_LOG_D(TAG, "Plain write for personalized mode key change"); @@ -658,9 +677,9 @@ void picopass_worker_write_standard_key(PicopassWorker* picopass_worker) { } } - while(picopass_worker->state == PicopassWorkerStateWriteStandardKey) { + while(picopass_worker->state == PicopassWorkerStateWriteKey) { if(picopass_detect_card(1000) == ERR_NONE) { - err = picopass_write_block(pacs, PICOPASS_KD_BLOCK_INDEX, newKey); + err = picopass_write_block(AA1, PICOPASS_KD_BLOCK_INDEX, newKey); if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_write_block error %d", err); nextState = PicopassWorkerEventFail; diff --git a/applications/plugins/picopass/picopass_worker.h b/applications/plugins/picopass/picopass_worker.h index 775212c6..02b088b2 100644 --- a/applications/plugins/picopass/picopass_worker.h +++ b/applications/plugins/picopass/picopass_worker.h @@ -12,7 +12,7 @@ typedef enum { // Main worker states PicopassWorkerStateDetect, PicopassWorkerStateWrite, - PicopassWorkerStateWriteStandardKey, + PicopassWorkerStateWriteKey, // Transition PicopassWorkerStateStop, } PicopassWorkerState; diff --git a/applications/plugins/picopass/picopass_worker_i.h b/applications/plugins/picopass/picopass_worker_i.h index cf55fbdf..f41cfce4 100644 --- a/applications/plugins/picopass/picopass_worker_i.h +++ b/applications/plugins/picopass/picopass_worker_i.h @@ -31,4 +31,4 @@ int32_t picopass_worker_task(void* context); void picopass_worker_detect(PicopassWorker* picopass_worker); void picopass_worker_write(PicopassWorker* picopass_worker); -void picopass_worker_write_standard_key(PicopassWorker* picopass_worker); +void picopass_worker_write_key(PicopassWorker* picopass_worker); diff --git a/applications/plugins/picopass/scenes/picopass_scene_card_menu.c b/applications/plugins/picopass/scenes/picopass_scene_card_menu.c index a424b919..fe63f7c8 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_card_menu.c +++ b/applications/plugins/picopass/scenes/picopass_scene_card_menu.c @@ -3,6 +3,7 @@ enum SubmenuIndex { SubmenuIndexSave, SubmenuIndexSaveAsLF, + SubmenuIndexChangeKey, }; void picopass_scene_card_menu_submenu_callback(void* context, uint32_t index) { @@ -25,6 +26,13 @@ void picopass_scene_card_menu_on_enter(void* context) { picopass_scene_card_menu_submenu_callback, picopass); } + submenu_add_item( + submenu, + "Change Key", + SubmenuIndexChangeKey, + picopass_scene_card_menu_submenu_callback, + picopass); + submenu_set_selected_item( picopass->submenu, scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneCardMenu)); @@ -49,6 +57,11 @@ bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) { picopass->dev->format = PicopassDeviceSaveFormatLF; scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); consumed = true; + } else if(event.event == SubmenuIndexChangeKey) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexChangeKey); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneKeyMenu); + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { consumed = scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/plugins/picopass/scenes/picopass_scene_config.h b/applications/plugins/picopass/scenes/picopass_scene_config.h index 95700787..f5a90d46 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_config.h +++ b/applications/plugins/picopass/scenes/picopass_scene_config.h @@ -13,3 +13,4 @@ ADD_SCENE(picopass, write_card, WriteCard) ADD_SCENE(picopass, write_card_success, WriteCardSuccess) ADD_SCENE(picopass, read_factory_success, ReadFactorySuccess) ADD_SCENE(picopass, write_key, WriteKey) +ADD_SCENE(picopass, key_menu, KeyMenu) diff --git a/applications/plugins/picopass/scenes/picopass_scene_key_menu.c b/applications/plugins/picopass/scenes/picopass_scene_key_menu.c new file mode 100644 index 00000000..b1db37f8 --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_key_menu.c @@ -0,0 +1,100 @@ +#include "../picopass_i.h" + +enum SubmenuIndex { + SubmenuIndexWriteStandard, + SubmenuIndexWriteiCE, + SubmenuIndexWriteiCL, + SubmenuIndexWriteiCS, + SubmenuIndexWriteCustom, //TODO: user input of key +}; + +extern const uint8_t picopass_xice_key[]; +extern const uint8_t picopass_xicl_key[]; +extern const uint8_t picopass_xics_key[]; +extern const uint8_t picopass_iclass_key[]; + +void picopass_scene_key_menu_submenu_callback(void* context, uint32_t index) { + Picopass* picopass = context; + + view_dispatcher_send_custom_event(picopass->view_dispatcher, index); +} + +void picopass_scene_key_menu_on_enter(void* context) { + Picopass* picopass = context; + Submenu* submenu = picopass->submenu; + + submenu_add_item( + submenu, + "Write Standard", + SubmenuIndexWriteStandard, + picopass_scene_key_menu_submenu_callback, + picopass); + submenu_add_item( + submenu, + "Write iCE", + SubmenuIndexWriteiCE, + picopass_scene_key_menu_submenu_callback, + picopass); + submenu_add_item( + submenu, + "Write iCL", + SubmenuIndexWriteiCL, + picopass_scene_key_menu_submenu_callback, + picopass); + submenu_add_item( + submenu, + "Write iCS", + SubmenuIndexWriteiCS, + picopass_scene_key_menu_submenu_callback, + picopass); + + submenu_set_selected_item( + picopass->submenu, + scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneKeyMenu)); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewMenu); +} + +bool picopass_scene_key_menu_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWriteStandard) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteStandard); + memcpy(picopass->dev->dev_data.pacs.key, picopass_iclass_key, PICOPASS_BLOCK_LEN); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); + consumed = true; + } else if(event.event == SubmenuIndexWriteiCE) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCE); + memcpy(picopass->dev->dev_data.pacs.key, picopass_xice_key, PICOPASS_BLOCK_LEN); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); + consumed = true; + } else if(event.event == SubmenuIndexWriteiCL) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCE); + memcpy(picopass->dev->dev_data.pacs.key, picopass_xicl_key, PICOPASS_BLOCK_LEN); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); + consumed = true; + } else if(event.event == SubmenuIndexWriteiCS) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCE); + memcpy(picopass->dev->dev_data.pacs.key, picopass_xics_key, PICOPASS_BLOCK_LEN); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + picopass->scene_manager, PicopassSceneStart); + } + + return consumed; +} + +void picopass_scene_key_menu_on_exit(void* context) { + Picopass* picopass = context; + + submenu_reset(picopass->submenu); +} diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_card.c b/applications/plugins/picopass/scenes/picopass_scene_read_card.c index 90422a2e..c62cba8e 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_card.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card.c @@ -1,7 +1,7 @@ #include "../picopass_i.h" #include -const uint8_t picopass_factory_key_check[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; +extern const uint8_t picopass_factory_debit_key[]; void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context) { UNUSED(event); @@ -38,7 +38,7 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) { if(event.event == PicopassCustomEventWorkerExit) { if(memcmp( picopass->dev->dev_data.pacs.key, - picopass_factory_key_check, + picopass_factory_debit_key, PICOPASS_BLOCK_LEN) == 0) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadFactorySuccess); } else { diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c index 8e32d21f..b98951dc 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c @@ -1,6 +1,8 @@ #include "../picopass_i.h" #include +extern const uint8_t picopass_iclass_key[]; + void picopass_scene_read_factory_success_widget_callback( GuiButtonType result, InputType type, @@ -63,6 +65,7 @@ bool picopass_scene_read_factory_success_on_event(void* context, SceneManagerEve if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(picopass->scene_manager); } else if(event.event == GuiButtonTypeCenter) { + memcpy(picopass->dev->dev_data.pacs.key, picopass_iclass_key, PICOPASS_BLOCK_LEN); scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); consumed = true; } diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_key.c b/applications/plugins/picopass/scenes/picopass_scene_write_key.c index 83d594ca..0f417e1c 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_write_key.c +++ b/applications/plugins/picopass/scenes/picopass_scene_write_key.c @@ -20,7 +20,7 @@ void picopass_scene_write_key_on_enter(void* context) { view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); picopass_worker_start( picopass->worker, - PicopassWorkerStateWriteStandardKey, + PicopassWorkerStateWriteKey, &picopass->dev->dev_data, picopass_write_key_worker_callback, picopass); From 98193067314b230ad660762aa415c21f4bb6c781 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:09:45 +0200 Subject: [PATCH 15/23] [Fl-3147] Remove ValueMutex (#2467) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move keypad_test to furi_mutex * Move text_box_test to furi_mutex * Move snake_game to furi_mutex * Remove ValueMutex completely * Snake Game: simplify code and fix PVS warning * F18: sync API symbols Co-authored-by: あく --- applications/debug/keypad_test/keypad_test.c | 54 ++++--- .../debug/text_box_test/text_box_test.c | 30 ++-- .../debug/unit_tests/furi/furi_test.c | 6 - .../unit_tests/furi/furi_valuemutex_test.c | 41 ----- applications/plugins/snake_game/snake_game.c | 24 +-- firmware/targets/f18/api_symbols.csv | 18 ++- firmware/targets/f7/api_symbols.csv | 8 +- furi/core/valuemutex.c | 59 ------- furi/core/valuemutex.h | 149 ------------------ furi/furi.h | 1 - 10 files changed, 68 insertions(+), 322 deletions(-) delete mode 100644 applications/debug/unit_tests/furi/furi_valuemutex_test.c delete mode 100644 furi/core/valuemutex.c delete mode 100644 furi/core/valuemutex.h diff --git a/applications/debug/keypad_test/keypad_test.c b/applications/debug/keypad_test/keypad_test.c index 2470baf8..9e8881de 100644 --- a/applications/debug/keypad_test/keypad_test.c +++ b/applications/debug/keypad_test/keypad_test.c @@ -11,6 +11,7 @@ typedef struct { uint16_t left; uint16_t right; uint16_t ok; + FuriMutex* mutex; } KeypadTestState; static void keypad_test_reset_state(KeypadTestState* state) { @@ -22,7 +23,8 @@ static void keypad_test_reset_state(KeypadTestState* state) { } static void keypad_test_render_callback(Canvas* canvas, void* ctx) { - KeypadTestState* state = (KeypadTestState*)acquire_mutex((ValueMutex*)ctx, 25); + KeypadTestState* state = ctx; + furi_mutex_acquire(state->mutex, FuriWaitForever); canvas_clear(canvas); char strings[5][20]; @@ -51,7 +53,7 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) { canvas_draw_str(canvas, 10, 63, "[back] - reset, hold to exit"); - release_mutex((ValueMutex*)ctx, state); + furi_mutex_release(state->mutex); } static void keypad_test_input_callback(InputEvent* input_event, void* ctx) { @@ -64,17 +66,17 @@ int32_t keypad_test_app(void* p) { FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); furi_check(event_queue); - KeypadTestState _state = {{false, false, false, false, false}, 0, 0, 0, 0, 0}; + KeypadTestState state = {{false, false, false, false, false}, 0, 0, 0, 0, 0, NULL}; + state.mutex = furi_mutex_alloc(FuriMutexTypeNormal); - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, &_state, sizeof(KeypadTestState))) { + if(!state.mutex) { FURI_LOG_E(TAG, "cannot create mutex"); return 0; } ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, keypad_test_render_callback, &state_mutex); + view_port_draw_callback_set(view_port, keypad_test_render_callback, &state); view_port_input_callback_set(view_port, keypad_test_input_callback, event_queue); // Open GUI and register view_port @@ -83,7 +85,7 @@ int32_t keypad_test_app(void* p) { InputEvent event; while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - KeypadTestState* state = (KeypadTestState*)acquire_mutex_block(&state_mutex); + furi_mutex_acquire(state.mutex, FuriWaitForever); FURI_LOG_I( TAG, "key: %s type: %s", @@ -92,54 +94,54 @@ int32_t keypad_test_app(void* p) { if(event.key == InputKeyRight) { if(event.type == InputTypePress) { - state->press[0] = true; + state.press[0] = true; } else if(event.type == InputTypeRelease) { - state->press[0] = false; + state.press[0] = false; } else if(event.type == InputTypeShort) { - ++state->right; + ++state.right; } } else if(event.key == InputKeyLeft) { if(event.type == InputTypePress) { - state->press[1] = true; + state.press[1] = true; } else if(event.type == InputTypeRelease) { - state->press[1] = false; + state.press[1] = false; } else if(event.type == InputTypeShort) { - ++state->left; + ++state.left; } } else if(event.key == InputKeyUp) { if(event.type == InputTypePress) { - state->press[2] = true; + state.press[2] = true; } else if(event.type == InputTypeRelease) { - state->press[2] = false; + state.press[2] = false; } else if(event.type == InputTypeShort) { - ++state->up; + ++state.up; } } else if(event.key == InputKeyDown) { if(event.type == InputTypePress) { - state->press[3] = true; + state.press[3] = true; } else if(event.type == InputTypeRelease) { - state->press[3] = false; + state.press[3] = false; } else if(event.type == InputTypeShort) { - ++state->down; + ++state.down; } } else if(event.key == InputKeyOk) { if(event.type == InputTypePress) { - state->press[4] = true; + state.press[4] = true; } else if(event.type == InputTypeRelease) { - state->press[4] = false; + state.press[4] = false; } else if(event.type == InputTypeShort) { - ++state->ok; + ++state.ok; } } else if(event.key == InputKeyBack) { if(event.type == InputTypeLong) { - release_mutex(&state_mutex, state); + furi_mutex_release(state.mutex); break; } else if(event.type == InputTypeShort) { - keypad_test_reset_state(state); + keypad_test_reset_state(&state); } } - release_mutex(&state_mutex, state); + furi_mutex_release(state.mutex); view_port_update(view_port); } @@ -147,7 +149,7 @@ int32_t keypad_test_app(void* p) { gui_remove_view_port(gui, view_port); view_port_free(view_port); furi_message_queue_free(event_queue); - delete_mutex(&state_mutex); + furi_mutex_free(state.mutex); furi_record_close(RECORD_GUI); diff --git a/applications/debug/text_box_test/text_box_test.c b/applications/debug/text_box_test/text_box_test.c index d7194ffe..b980f686 100644 --- a/applications/debug/text_box_test/text_box_test.c +++ b/applications/debug/text_box_test/text_box_test.c @@ -53,15 +53,17 @@ static void (*text_box_test_render[])(Canvas* canvas) = { typedef struct { uint32_t idx; + FuriMutex* mutex; } TextBoxTestState; static void text_box_test_render_callback(Canvas* canvas, void* ctx) { - TextBoxTestState* state = acquire_mutex((ValueMutex*)ctx, 25); + TextBoxTestState* state = ctx; + furi_mutex_acquire(state->mutex, FuriWaitForever); canvas_clear(canvas); text_box_test_render[state->idx](canvas); - release_mutex((ValueMutex*)ctx, state); + furi_mutex_release(state->mutex); } static void text_box_test_input_callback(InputEvent* input_event, void* ctx) { @@ -74,17 +76,17 @@ int32_t text_box_test_app(void* p) { FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); furi_check(event_queue); - TextBoxTestState _state = {.idx = 0}; + TextBoxTestState state = {.idx = 0, .mutex = NULL}; + state.mutex = furi_mutex_alloc(FuriMutexTypeNormal); - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, &_state, sizeof(TextBoxTestState))) { + if(!state.mutex) { FURI_LOG_E(TAG, "Cannot create mutex"); return 0; } ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, text_box_test_render_callback, &state_mutex); + view_port_draw_callback_set(view_port, text_box_test_render_callback, &state); view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue); // Open GUI and register view_port @@ -94,24 +96,24 @@ int32_t text_box_test_app(void* p) { uint32_t test_renders_num = COUNT_OF(text_box_test_render); InputEvent event; while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - TextBoxTestState* state = acquire_mutex_block(&state_mutex); + furi_mutex_acquire(state.mutex, FuriWaitForever); if(event.type == InputTypeShort) { if(event.key == InputKeyRight) { - if(state->idx < test_renders_num - 1) { - state->idx++; + if(state.idx < test_renders_num - 1) { + state.idx++; } } else if(event.key == InputKeyLeft) { - if(state->idx > 0) { - state->idx--; + if(state.idx > 0) { + state.idx--; } } else if(event.key == InputKeyBack) { - release_mutex(&state_mutex, state); + furi_mutex_release(state.mutex); break; } } - release_mutex(&state_mutex, state); + furi_mutex_release(state.mutex); view_port_update(view_port); } @@ -119,7 +121,7 @@ int32_t text_box_test_app(void* p) { gui_remove_view_port(gui, view_port); view_port_free(view_port); furi_message_queue_free(event_queue); - delete_mutex(&state_mutex); + furi_mutex_free(state.mutex); furi_record_close(RECORD_GUI); diff --git a/applications/debug/unit_tests/furi/furi_test.c b/applications/debug/unit_tests/furi/furi_test.c index eed9e420..33ec5fd0 100644 --- a/applications/debug/unit_tests/furi/furi_test.c +++ b/applications/debug/unit_tests/furi/furi_test.c @@ -5,7 +5,6 @@ // v2 tests void test_furi_create_open(); -void test_furi_valuemutex(); void test_furi_concurrent_access(); void test_furi_pubsub(); @@ -30,10 +29,6 @@ MU_TEST(mu_test_furi_create_open) { test_furi_create_open(); } -MU_TEST(mu_test_furi_valuemutex) { - test_furi_valuemutex(); -} - MU_TEST(mu_test_furi_pubsub) { test_furi_pubsub(); } @@ -51,7 +46,6 @@ MU_TEST_SUITE(test_suite) { // v2 tests MU_RUN_TEST(mu_test_furi_create_open); - MU_RUN_TEST(mu_test_furi_valuemutex); MU_RUN_TEST(mu_test_furi_pubsub); MU_RUN_TEST(mu_test_furi_memmgr); } diff --git a/applications/debug/unit_tests/furi/furi_valuemutex_test.c b/applications/debug/unit_tests/furi/furi_valuemutex_test.c deleted file mode 100644 index 02fd47ee..00000000 --- a/applications/debug/unit_tests/furi/furi_valuemutex_test.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include - -#include "../minunit.h" - -void test_furi_valuemutex() { - const int init_value = 0xdeadbeef; - const int changed_value = 0x12345678; - - int value = init_value; - bool result; - ValueMutex valuemutex; - - // init mutex case - result = init_mutex(&valuemutex, &value, sizeof(value)); - mu_assert(result, "init mutex failed"); - - // acquire mutex case - int* value_pointer = acquire_mutex(&valuemutex, 100); - mu_assert_pointers_eq(value_pointer, &value); - - // second acquire mutex case - int* value_pointer_second = acquire_mutex(&valuemutex, 100); - mu_assert_pointers_eq(value_pointer_second, NULL); - - // change value case - *value_pointer = changed_value; - mu_assert_int_eq(value, changed_value); - - // release mutex case - result = release_mutex(&valuemutex, &value); - mu_assert(result, "release mutex failed"); - - // TODO - //acquire mutex blocking case - //write mutex blocking case - //read mutex blocking case - - mu_check(delete_mutex(&valuemutex)); -} diff --git a/applications/plugins/snake_game/snake_game.c b/applications/plugins/snake_game/snake_game.c index 2815e2f3..3cf9b6d5 100644 --- a/applications/plugins/snake_game/snake_game.c +++ b/applications/plugins/snake_game/snake_game.c @@ -50,6 +50,7 @@ typedef struct { Direction nextMovement; // if backward of currentMovement, ignore Point fruit; GameState state; + FuriMutex* mutex; } SnakeState; typedef enum { @@ -92,12 +93,10 @@ const NotificationSequence sequence_eat = { }; static void snake_game_render_callback(Canvas* const canvas, void* ctx) { - const SnakeState* snake_state = acquire_mutex((ValueMutex*)ctx, 25); - if(snake_state == NULL) { - return; - } + furi_assert(ctx); + const SnakeState* snake_state = ctx; - // Before the function is called, the state is set with the canvas_reset(canvas) + furi_mutex_acquire(snake_state->mutex, FuriWaitForever); // Frame canvas_draw_frame(canvas, 0, 0, 128, 64); @@ -134,7 +133,7 @@ static void snake_game_render_callback(Canvas* const canvas, void* ctx) { canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); } - release_mutex((ValueMutex*)ctx, snake_state); + furi_mutex_release(snake_state->mutex); } static void snake_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { @@ -324,15 +323,16 @@ int32_t snake_game_app(void* p) { SnakeState* snake_state = malloc(sizeof(SnakeState)); snake_game_init_game(snake_state); - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, snake_state, sizeof(SnakeState))) { + snake_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + if(!snake_state->mutex) { FURI_LOG_E("SnakeGame", "cannot create mutex\r\n"); free(snake_state); return 255; } ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, snake_game_render_callback, &state_mutex); + view_port_draw_callback_set(view_port, snake_game_render_callback, snake_state); view_port_input_callback_set(view_port, snake_game_input_callback, event_queue); FuriTimer* timer = @@ -352,7 +352,7 @@ int32_t snake_game_app(void* p) { for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - SnakeState* snake_state = (SnakeState*)acquire_mutex_block(&state_mutex); + furi_mutex_acquire(snake_state->mutex, FuriWaitForever); if(event_status == FuriStatusOk) { // press events @@ -391,7 +391,7 @@ int32_t snake_game_app(void* p) { } view_port_update(view_port); - release_mutex(&state_mutex, snake_state); + furi_mutex_release(snake_state->mutex); } // Return backlight to normal state @@ -404,7 +404,7 @@ int32_t snake_game_app(void* p) { furi_record_close(RECORD_NOTIFICATION); view_port_free(view_port); furi_message_queue_free(event_queue); - delete_mutex(&state_mutex); + furi_mutex_free(snake_state->mutex); free(snake_state); return 0; diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 608f5b19..8060d38a 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,17.0,, +Version,+,18.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -156,6 +156,7 @@ Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/md5.h,, Header,+,lib/toolbox/path.h,, +Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/random_name.h,, Header,+,lib/toolbox/saved_struct.h,, @@ -439,7 +440,6 @@ Function,-,_wctomb_r,int,"_reent*, char*, wchar_t, _mbstate_t*" Function,-,a64l,long,const char* Function,+,abort,void, Function,-,abs,int,int -Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" Function,-,aligned_alloc,void*,"size_t, size_t" Function,+,aligned_free,void,void* Function,+,aligned_malloc,void*,"size_t, size_t" @@ -573,7 +573,6 @@ Function,-,ctermid,char*,char* Function,-,ctime,char*,const time_t* Function,-,ctime_r,char*,"const time_t*, char*" Function,-,cuserid,char*,char* -Function,+,delete_mutex,_Bool,ValueMutex* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* Function,+,dialog_ex_enable_extended_events,void,DialogEx* @@ -684,6 +683,7 @@ Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, Browser Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" Function,+,file_browser_worker_set_long_load_callback,void,"BrowserWorker*, BrowserWorkerLongLoadCallback" +Function,+,file_info_is_dir,_Bool,const FileInfo* Function,+,file_stream_alloc,Stream*,Storage* Function,+,file_stream_close,_Bool,Stream* Function,+,file_stream_get_error,FS_Error,Stream* @@ -707,6 +707,7 @@ Function,-,flipper_application_preload_status_to_string,const char*,FlipperAppli Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* +Function,+,flipper_format_buffered_file_open_always,_Bool,"FlipperFormat*, const char*" Function,+,flipper_format_buffered_file_open_existing,_Bool,"FlipperFormat*, const char*" Function,+,flipper_format_delete_key,_Bool,"FlipperFormat*, const char*" Function,+,flipper_format_file_alloc,FlipperFormat*,Storage* @@ -1234,6 +1235,7 @@ Function,+,furi_thread_flags_get,uint32_t, Function,+,furi_thread_flags_set,uint32_t,"FuriThreadId, uint32_t" Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" Function,+,furi_thread_free,void,FuriThread* +Function,+,furi_thread_get_appid,const char*,FuriThreadId Function,+,furi_thread_get_current,FuriThread*, Function,+,furi_thread_get_current_id,FuriThreadId, Function,+,furi_thread_get_current_priority,FuriThreadPriority, @@ -1248,6 +1250,7 @@ Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* Function,+,furi_thread_mark_as_service,void,FuriThread* Function,+,furi_thread_resume,void,FuriThreadId +Function,+,furi_thread_set_appid,void,"FuriThread*, const char*" Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" Function,+,furi_thread_set_context,void,"FuriThread*, void*" Function,+,furi_thread_set_current_priority,void,FuriThreadPriority @@ -1312,7 +1315,6 @@ Function,+,icon_get_data,const uint8_t*,const Icon* Function,+,icon_get_height,uint8_t,const Icon* Function,+,icon_get_width,uint8_t,const Icon* Function,-,index,char*,"const char*, int" -Function,+,init_mutex,_Bool,"ValueMutex*, void*, size_t" Function,-,initstate,char*,"unsigned, char*, size_t" Function,+,input_get_key_name,const char*,InputKey Function,+,input_get_type_name,const char*,InputType @@ -1491,6 +1493,7 @@ Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* Function,+,power_reboot,void,PowerBootMode +Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" Function,-,printf,int,"const char*, ..." Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" @@ -1534,12 +1537,10 @@ Function,+,rand,int, Function,-,rand_r,int,unsigned* Function,+,random,long, Function,-,rawmemchr,void*,"const void*, int" -Function,-,read_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" Function,+,realloc,void*,"void*, size_t" Function,-,reallocarray,void*,"void*, size_t, size_t" Function,-,reallocf,void*,"void*, size_t" Function,-,realpath,char*,"const char*, char*" -Function,+,release_mutex,_Bool,"ValueMutex*, const void*" Function,-,remove,int,const char* Function,-,rename,int,"const char*, const char*" Function,-,renameat,int,"int, const char*, int, const char*" @@ -1617,14 +1618,18 @@ Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*" Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*" Function,+,storage_common_remove,FS_Error,"Storage*, const char*" Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_resolve_path_and_ensure_app_directory,void,"Storage*, FuriString*" Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" Function,+,storage_common_timestamp,FS_Error,"Storage*, const char*, uint32_t*" Function,+,storage_dir_close,_Bool,File* +Function,+,storage_dir_exists,_Bool,"Storage*, const char*" Function,+,storage_dir_open,_Bool,"File*, const char*" Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" Function,-,storage_dir_rewind,_Bool,File* @@ -1995,7 +2000,6 @@ Function,+,widget_alloc,Widget*, Function,+,widget_free,void,Widget* Function,+,widget_get_view,View*,Widget* Function,+,widget_reset,void,Widget* -Function,-,write_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" Function,-,xPortGetFreeHeapSize,size_t, Function,-,xPortGetMinimumEverFreeHeapSize,size_t, Function,-,xPortStartScheduler,BaseType_t, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1c35abd3..57c1a2fa 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,17.0,, +Version,+,18.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -491,7 +491,6 @@ Function,-,acosh,double,double Function,-,acoshf,float,float Function,-,acoshl,long double,long double Function,-,acosl,long double,long double -Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" Function,-,aligned_alloc,void*,"size_t, size_t" Function,+,aligned_free,void,void* Function,+,aligned_malloc,void*,"size_t, size_t" @@ -703,7 +702,6 @@ Function,-,ctermid,char*,char* Function,-,ctime,char*,const time_t* Function,-,ctime_r,char*,"const time_t*, char*" Function,-,cuserid,char*,char* -Function,+,delete_mutex,_Bool,ValueMutex* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* Function,+,dialog_ex_enable_extended_events,void,DialogEx* @@ -1692,7 +1690,6 @@ Function,+,infrared_worker_tx_set_get_signal_callback,void,"InfraredWorker*, Inf Function,+,infrared_worker_tx_set_signal_sent_callback,void,"InfraredWorker*, InfraredWorkerMessageSentCallback, void*" Function,+,infrared_worker_tx_start,void,InfraredWorker* Function,+,infrared_worker_tx_stop,void,InfraredWorker* -Function,+,init_mutex,_Bool,"ValueMutex*, void*, size_t" Function,-,initstate,char*,"unsigned, char*, size_t" Function,+,input_get_key_name,const char*,InputKey Function,+,input_get_type_name,const char*,InputType @@ -2164,12 +2161,10 @@ Function,+,rand,int, Function,-,rand_r,int,unsigned* Function,+,random,long, Function,-,rawmemchr,void*,"const void*, int" -Function,-,read_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" Function,+,realloc,void*,"void*, size_t" Function,-,reallocarray,void*,"void*, size_t, size_t" Function,-,reallocf,void*,"void*, size_t" Function,-,realpath,char*,"const char*, char*" -Function,+,release_mutex,_Bool,"ValueMutex*, const void*" Function,-,remainder,double,"double, double" Function,-,remainderf,float,"float, float" Function,-,remainderl,long double,"long double, long double" @@ -2967,7 +2962,6 @@ Function,+,widget_alloc,Widget*, Function,+,widget_free,void,Widget* Function,+,widget_get_view,View*,Widget* Function,+,widget_reset,void,Widget* -Function,-,write_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" Function,-,xPortGetFreeHeapSize,size_t, Function,-,xPortGetMinimumEverFreeHeapSize,size_t, Function,-,xPortStartScheduler,BaseType_t, diff --git a/furi/core/valuemutex.c b/furi/core/valuemutex.c deleted file mode 100644 index bf4e6130..00000000 --- a/furi/core/valuemutex.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "valuemutex.h" - -#include - -bool init_mutex(ValueMutex* valuemutex, void* value, size_t size) { - // mutex without name, - // no attributes (unfortunately robust mutex is not supported by FreeRTOS), - // with dynamic memory allocation - valuemutex->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(valuemutex->mutex == NULL) return false; - - valuemutex->value = value; - valuemutex->size = size; - - return true; -} - -bool delete_mutex(ValueMutex* valuemutex) { - if(furi_mutex_acquire(valuemutex->mutex, FuriWaitForever) == FuriStatusOk) { - furi_mutex_free(valuemutex->mutex); - return true; - } else { - return false; - } -} - -void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout) { - if(furi_mutex_acquire(valuemutex->mutex, timeout) == FuriStatusOk) { - return valuemutex->value; - } else { - return NULL; - } -} - -bool release_mutex(ValueMutex* valuemutex, const void* value) { - if(value != valuemutex->value) return false; - - if(furi_mutex_release(valuemutex->mutex) != FuriStatusOk) return false; - - return true; -} - -bool read_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout) { - void* value = acquire_mutex(valuemutex, timeout); - if(value == NULL || len > valuemutex->size) return false; - memcpy(data, value, len > 0 ? len : valuemutex->size); - if(!release_mutex(valuemutex, value)) return false; - - return true; -} - -bool write_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout) { - void* value = acquire_mutex(valuemutex, timeout); - if(value == NULL || len > valuemutex->size) return false; - memcpy(value, data, len > 0 ? len : valuemutex->size); - if(!release_mutex(valuemutex, value)) return false; - - return true; -} diff --git a/furi/core/valuemutex.h b/furi/core/valuemutex.h deleted file mode 100644 index 0d867a1d..00000000 --- a/furi/core/valuemutex.h +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once - -#include -#include "mutex.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * == ValueMutex == - - * The most simple concept is ValueMutex. - * It is wrapper around mutex and value pointer. - * You can take and give mutex to work with value and read and write value. - */ - -typedef struct { - void* value; - size_t size; - FuriMutex* mutex; -} ValueMutex; - -/** - * Creates ValueMutex. - */ -bool init_mutex(ValueMutex* valuemutex, void* value, size_t size); - -/** - * Free resources allocated by `init_mutex`. - * This function doesn't free the memory occupied by `ValueMutex` itself. - */ -bool delete_mutex(ValueMutex* valuemutex); - -/** - * Call for work with data stored in mutex. - * @return pointer to data if success, NULL otherwise. - */ -void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout); - -/** - * Helper: infinitely wait for mutex - */ -static inline void* acquire_mutex_block(ValueMutex* valuemutex) { - return acquire_mutex(valuemutex, FuriWaitForever); -} - -/** - * With statement for value mutex, acts as lambda - * @param name a resource name, const char* - * @param function_body a (){} lambda declaration, - * executed within you parent function context. - */ -#define with_value_mutex(value_mutex, function_body) \ - { \ - void* p = acquire_mutex_block(value_mutex); \ - furi_check(p); \ - ({ void __fn__ function_body __fn__; })(p); \ - release_mutex(value_mutex, p); \ - } - -/** - * Release mutex after end of work with data. - * Call `release_mutex` and pass ValueData instance and pointer to data. - */ -bool release_mutex(ValueMutex* valuemutex, const void* value); - -/** - * Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions. - * Both functions return true in case of success, false otherwise. - */ -bool read_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout); - -bool write_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout); - -inline static bool write_mutex_block(ValueMutex* valuemutex, void* data, size_t len) { - return write_mutex(valuemutex, data, len, FuriWaitForever); -} - -inline static bool read_mutex_block(ValueMutex* valuemutex, void* data, size_t len) { - return read_mutex(valuemutex, data, len, FuriWaitForever); -} - -#ifdef __cplusplus -} -#endif - -/* - -Usage example - -```C -// MANIFEST -// name="example-provider-app" -// stack=128 - -void provider_app(void* _p) { - // create record with mutex - uint32_t example_value = 0; - ValueMutex example_mutex; - // call `init_mutex`. - if(!init_mutex(&example_mutex, (void*)&example_value, sizeof(uint32_t))) { - printf("critical error\n"); - flapp_exit(NULL); - } - - furi_record_create("provider/example", (void*)&example_mutex); - - // we are ready to provide record to other apps - flapp_ready(); - - // get value and increment it - while(1) { - uint32_t* value = acquire_mutex(&example_mutex, OsWaitForever); - if(value != NULL) { - value++; - } - release_mutex(&example_mutex, value); - - furi_delay_ms(100); - } -} - -// MANIFEST -// name="example-consumer-app" -// stack=128 -// require="example-provider-app" -void consumer_app(void* _p) { - // this app run after flapp_ready call in all requirements app - - // open mutex value - ValueMutex* counter_mutex = furi_record_open("provider/example"); - if(counter_mutex == NULL) { - printf("critical error\n"); - flapp_exit(NULL); - } - - // continuously read value every 1s - uint32_t counter; - while(1) { - if(read_mutex(counter_mutex, &counter, sizeof(counter), OsWaitForever)) { - printf("counter value: %d\n", counter); - } - - furi_delay_ms(1000); - } -} -``` -*/ diff --git a/furi/furi.h b/furi/furi.h index 3ce83422..cfdeb2c0 100644 --- a/furi/furi.h +++ b/furi/furi.h @@ -16,7 +16,6 @@ #include "core/semaphore.h" #include "core/thread.h" #include "core/timer.h" -#include "core/valuemutex.h" #include "core/string.h" #include "core/stream_buffer.h" From eb5dae1cda00d254641b29700d4e38ef4f55d04f Mon Sep 17 00:00:00 2001 From: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Date: Tue, 7 Mar 2023 21:33:59 +0300 Subject: [PATCH 16/23] NFC: Support reading Mifare Classic key B from sector trailer, reading sector with B key where A key can't read block, Nfc Magic app not using NFC folder by default (in file select) (#2437) * NFC: Support reading Mifare Classic key B from sector trailer and reusing it for other sectors * NFC: Fix my pointer typo * NFC: Fix reading sector with B key where A key can't read block (fixes #2413) and fix Nfc Magic app not using NFC folder by default (in file select) * NFC: Fix strange bug Co-authored-by: Aleksandr Kutuzov --- .../scenes/nfc_magic_scene_file_select.c | 4 ++ firmware/targets/f7/api_symbols.csv | 2 +- lib/nfc/nfc_worker.c | 49 +++++++++++++++++++ lib/nfc/protocols/mifare_classic.c | 13 +++-- lib/nfc/protocols/mifare_classic.h | 1 + 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c index a19237ed..d78422ee 100644 --- a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -11,6 +11,10 @@ void nfc_magic_scene_file_select_on_enter(void* context) { // Process file_select return nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic); + if(!furi_string_size(nfc_magic->nfc_dev->load_path)) { + furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER); + } + if(nfc_file_select(nfc_magic->nfc_dev)) { if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 57c1a2fa..f505b943 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1892,7 +1892,7 @@ Function,+,menu_free,void,Menu* Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" -Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, MfClassicAuthContext*, uint64_t" +Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 54bdbb24..062a3953 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -569,6 +569,32 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { } } +static bool nfc_worker_mf_get_b_key_from_sector_trailer( + FuriHalNfcTxRxContext* tx_rx, + uint16_t sector, + uint64_t key, + uint64_t* found_key) { + // Some access conditions allow reading B key via A key + + uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + + Crypto1 crypto = {}; + MfClassicBlock block_tmp = {}; + MfClassicAuthContext auth_context = {.sector = sector, .key_a = MF_CLASSIC_NO_KEY, .key_b = 0}; + + furi_hal_nfc_sleep(); + + if(mf_classic_auth_attempt(tx_rx, &crypto, &auth_context, key)) { + if(mf_classic_read_block(tx_rx, &crypto, block, &block_tmp)) { + *found_key = nfc_util_bytes2num(&block_tmp.value[10], sizeof(uint8_t) * 6); + + return *found_key; + } + } + + return false; +} + static void nfc_worker_mf_classic_key_attack( NfcWorker* nfc_worker, uint64_t key, @@ -614,6 +640,16 @@ static void nfc_worker_mf_classic_key_attack( mf_classic_set_key_found(data, i, MfClassicKeyA, key); FURI_LOG_D(TAG, "Key found"); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + + uint64_t found_key; + if(nfc_worker_mf_get_b_key_from_sector_trailer(tx_rx, i, key, &found_key)) { + FURI_LOG_D(TAG, "Found B key via reading sector %d", i); + mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); + + if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { + nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + } + } } } if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { @@ -705,6 +741,19 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { mf_classic_set_key_found(data, i, MfClassicKeyA, key); FURI_LOG_D(TAG, "Key found"); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); + + uint64_t found_key; + if(nfc_worker_mf_get_b_key_from_sector_trailer( + &tx_rx, i, key, &found_key)) { + FURI_LOG_D(TAG, "Found B key via reading sector %d", i); + mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); + + if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { + nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); + } + + nfc_worker_mf_classic_key_attack(nfc_worker, found_key, &tx_rx, i + 1); + } nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); } furi_hal_nfc_sleep(); diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index e4d5e027..a8a90889 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -541,6 +541,7 @@ bool mf_classic_authenticate_skip_activate( bool mf_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, MfClassicAuthContext* auth_ctx, uint64_t key) { furi_assert(tx_rx); @@ -549,15 +550,14 @@ bool mf_classic_auth_attempt( bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) && (auth_ctx->key_b == MF_CLASSIC_NO_KEY); - Crypto1 crypto; if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) { // Try AUTH with key A if(mf_classic_auth( tx_rx, - mf_classic_get_first_block_num_of_sector(auth_ctx->sector), + mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), key, MfClassicKeyA, - &crypto, + crypto, false, 0)) { auth_ctx->key_a = key; @@ -573,10 +573,10 @@ bool mf_classic_auth_attempt( // Try AUTH with key B if(mf_classic_auth( tx_rx, - mf_classic_get_first_block_num_of_sector(auth_ctx->sector), + mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), key, MfClassicKeyB, - &crypto, + crypto, false, 0)) { auth_ctx->key_b = key; @@ -671,6 +671,9 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u do { if(blocks_read == total_blocks) break; if(!key_b_found) break; + if(key_a_found) { + furi_hal_nfc_sleep(); + } FURI_LOG_D(TAG, "Try to read blocks with key B"); key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break; diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index a88781f9..c03350f2 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -174,6 +174,7 @@ bool mf_classic_authenticate_skip_activate( bool mf_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, MfClassicAuthContext* auth_ctx, uint64_t key); From 90958a6d23ca48c68b69347505d8ef0ed24e54ca Mon Sep 17 00:00:00 2001 From: Liam Hays Date: Wed, 8 Mar 2023 04:27:21 -0700 Subject: [PATCH 17/23] More UI fixes and improvements (#2419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Unify spelling of confirm exit/retry across apps. * Unify infrared exit/retry confirm menus? * "Keyboard Layout", not "Keyboard layout". * Make iButton read scene prompt less awkward. * "Detect Reader" in MF Classic saved menu instead of "Detect reader" * NFC menu spelling changes only. * Remove \n in strings in widget_add_string_element() calls. Co-authored-by: あく --- .../main/bad_usb/scenes/bad_usb_scene_config.c | 2 +- .../main/ibutton/scenes/ibutton_scene_exit_confirm.c | 2 +- applications/main/ibutton/scenes/ibutton_scene_read.c | 2 +- .../main/ibutton/scenes/ibutton_scene_retry_confirm.c | 2 +- .../main/infrared/scenes/infrared_scene_ask_back.c | 6 +++--- .../main/infrared/scenes/infrared_scene_ask_retry.c | 4 ++-- .../main/lfrfid/scenes/lfrfid_scene_retry_confirm.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_classic_menu.c | 2 +- applications/main/nfc/scenes/nfc_scene_retry_confirm.c | 2 +- applications/main/nfc/scenes/nfc_scene_saved_menu.c | 10 +++++----- .../main/subghz/scenes/subghz_scene_need_saving.c | 4 ++-- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.c b/applications/main/bad_usb/scenes/bad_usb_scene_config.c index 2a9f2f76..c88cae03 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config.c @@ -17,7 +17,7 @@ void bad_usb_scene_config_on_enter(void* context) { submenu_add_item( submenu, - "Keyboard layout", + "Keyboard Layout", SubmenuIndexKeyboardLayout, bad_usb_scene_config_submenu_callback, bad_usb); diff --git a/applications/main/ibutton/scenes/ibutton_scene_exit_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_exit_confirm.c index 2367e121..9029a4b7 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_exit_confirm.c +++ b/applications/main/ibutton/scenes/ibutton_scene_exit_confirm.c @@ -19,7 +19,7 @@ void ibutton_scene_exit_confirm_on_enter(void* context) { widget_add_button_element( widget, GuiButtonTypeRight, "Stay", ibutton_scene_exit_confirm_widget_callback, ibutton); widget_add_string_element( - widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?"); + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton Menu?"); widget_add_string_element( widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); diff --git a/applications/main/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c index 2c43b82b..a840fb7b 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read.c @@ -13,7 +13,7 @@ void ibutton_scene_read_on_enter(void* context) { iButtonWorker* worker = ibutton->worker; popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); - popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); + popup_set_text(popup, "Apply key to\nFlipper's back", 95, 30, AlignCenter, AlignTop); popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); diff --git a/applications/main/ibutton/scenes/ibutton_scene_retry_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_retry_confirm.c index 7f8c95b1..34de5b87 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_retry_confirm.c +++ b/applications/main/ibutton/scenes/ibutton_scene_retry_confirm.c @@ -19,7 +19,7 @@ void ibutton_scene_retry_confirm_on_enter(void* context) { widget_add_button_element( widget, GuiButtonTypeRight, "Stay", ibutton_scene_retry_confirm_widget_callback, ibutton); widget_add_string_element( - widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Retry Reading?"); widget_add_string_element( widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); diff --git a/applications/main/infrared/scenes/infrared_scene_ask_back.c b/applications/main/infrared/scenes/infrared_scene_ask_back.c index 493458ad..77fc97f9 100644 --- a/applications/main/infrared/scenes/infrared_scene_ask_back.c +++ b/applications/main/infrared/scenes/infrared_scene_ask_back.c @@ -10,13 +10,13 @@ void infrared_scene_ask_back_on_enter(void* context) { DialogEx* dialog_ex = infrared->dialog_ex; if(infrared->app_state.is_learning_new_remote) { - dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 11, AlignCenter, AlignTop); } else { - dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 11, AlignCenter, AlignTop); } dialog_ex_set_text( - dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter); + dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); dialog_ex_set_icon(dialog_ex, 0, 0, NULL); dialog_ex_set_left_button_text(dialog_ex, "Exit"); dialog_ex_set_center_button_text(dialog_ex, NULL); diff --git a/applications/main/infrared/scenes/infrared_scene_ask_retry.c b/applications/main/infrared/scenes/infrared_scene_ask_retry.c index c87d9e6d..602e470c 100644 --- a/applications/main/infrared/scenes/infrared_scene_ask_retry.c +++ b/applications/main/infrared/scenes/infrared_scene_ask_retry.c @@ -9,9 +9,9 @@ void infrared_scene_ask_retry_on_enter(void* context) { Infrared* infrared = context; DialogEx* dialog_ex = infrared->dialog_ex; - dialog_ex_set_header(dialog_ex, "Return to Reading?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop); dialog_ex_set_text( - dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter); + dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); dialog_ex_set_icon(dialog_ex, 0, 0, NULL); dialog_ex_set_left_button_text(dialog_ex, "Exit"); dialog_ex_set_center_button_text(dialog_ex, NULL); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c b/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c index f639f0ae..ddac3e8b 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_retry_confirm.c @@ -7,7 +7,7 @@ void lfrfid_scene_retry_confirm_on_enter(void* context) { widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app); widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app); widget_add_string_element( - widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Retry Reading?"); widget_add_string_element( widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!"); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 5fbdabe3..67b2a853 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -25,7 +25,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, - "Detect reader", + "Detect Reader", SubmenuIndexDetectReader, nfc_scene_mf_classic_menu_submenu_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 366582ea..5f4f7985 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -14,7 +14,7 @@ void nfc_scene_retry_confirm_on_enter(void* context) { dialog_ex_set_right_button_text(dialog_ex, "Stay"); dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop); dialog_ex_set_text( - dialog_ex, "All unsaved data will be\nlost!", 64, 25, AlignCenter, AlignTop); + dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback); diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index f42e0fe9..ba1f9653 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -51,20 +51,20 @@ void nfc_scene_saved_menu_on_enter(void* context) { if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, - "Detect reader", + "Detect Reader", SubmenuIndexDetectReader, nfc_scene_saved_menu_submenu_callback, nfc); } submenu_add_item( submenu, - "Write To Initial Card", + "Write to Initial Card", SubmenuIndexWrite, nfc_scene_saved_menu_submenu_callback, nfc); submenu_add_item( submenu, - "Update From Initial Card", + "Update from Initial Card", SubmenuIndexUpdate, nfc_scene_saved_menu_submenu_callback, nfc); @@ -75,13 +75,13 @@ void nfc_scene_saved_menu_on_enter(void* context) { !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { submenu_add_item( submenu, - "Unlock With Reader", + "Unlock with Reader", SubmenuIndexMfUlUnlockByReader, nfc_scene_saved_menu_submenu_callback, nfc); submenu_add_item( submenu, - "Unlock With Password", + "Unlock with Password", SubmenuIndexMfUlUnlockByPassword, nfc_scene_saved_menu_submenu_callback, nfc); diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index 53bffedc..e157246a 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -16,7 +16,7 @@ void subghz_scene_need_saving_on_enter(void* context) { SubGhz* subghz = context; widget_add_string_multiline_element( - subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Sub-GHz menu?"); + subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Sub-GHz Menu?"); widget_add_string_multiline_element( subghz->widget, 64, @@ -24,7 +24,7 @@ void subghz_scene_need_saving_on_enter(void* context) { AlignCenter, AlignCenter, FontSecondary, - "All unsaved will be\nlost."); + "All unsaved data\nwill be lost!"); widget_add_button_element( subghz->widget, GuiButtonTypeRight, "Stay", subghz_scene_need_saving_callback, subghz); From 5be15152ebccaafe750db78aa293515779fed640 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Wed, 8 Mar 2023 03:46:30 -0800 Subject: [PATCH 18/23] PicoPass: auth cleanup (#2470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove redundant auth methods * Move picopass keys to new file * CTF key * Format sources * PicoPass: add pragma once to picopass_keys.h Co-authored-by: あく --- applications/plugins/picopass/picopass_keys.c | 8 ++ applications/plugins/picopass/picopass_keys.h | 10 +++ .../plugins/picopass/picopass_worker.c | 81 ++----------------- .../plugins/picopass/picopass_worker.h | 1 + .../picopass/scenes/picopass_scene_key_menu.c | 6 +- .../scenes/picopass_scene_read_card.c | 3 +- .../picopass_scene_read_factory_success.c | 3 +- .../picopass/assets/iclass_elite_dict.txt | 2 + 8 files changed, 31 insertions(+), 83 deletions(-) create mode 100644 applications/plugins/picopass/picopass_keys.c create mode 100644 applications/plugins/picopass/picopass_keys.h diff --git a/applications/plugins/picopass/picopass_keys.c b/applications/plugins/picopass/picopass_keys.c new file mode 100644 index 00000000..43dfc631 --- /dev/null +++ b/applications/plugins/picopass/picopass_keys.c @@ -0,0 +1,8 @@ +#include "picopass_keys.h" + +const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78}; +const uint8_t picopass_factory_credit_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; +const uint8_t picopass_factory_debit_key[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; +const uint8_t picopass_xice_key[] = {0x20, 0x20, 0x66, 0x66, 0x66, 0x66, 0x88, 0x88}; +const uint8_t picopass_xicl_key[] = {0x20, 0x20, 0x66, 0x66, 0x66, 0x66, 0x88, 0x88}; +const uint8_t picopass_xics_key[] = {0x66, 0x66, 0x20, 0x20, 0x66, 0x66, 0x88, 0x88}; diff --git a/applications/plugins/picopass/picopass_keys.h b/applications/plugins/picopass/picopass_keys.h new file mode 100644 index 00000000..2b5dba66 --- /dev/null +++ b/applications/plugins/picopass/picopass_keys.h @@ -0,0 +1,10 @@ +#pragma once + +#include "picopass_device.h" + +extern const uint8_t picopass_iclass_key[PICOPASS_BLOCK_LEN]; +extern const uint8_t picopass_factory_credit_key[PICOPASS_BLOCK_LEN]; +extern const uint8_t picopass_factory_debit_key[PICOPASS_BLOCK_LEN]; +extern const uint8_t picopass_xice_key[PICOPASS_BLOCK_LEN]; +extern const uint8_t picopass_xicl_key[PICOPASS_BLOCK_LEN]; +extern const uint8_t picopass_xics_key[PICOPASS_BLOCK_LEN]; diff --git a/applications/plugins/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c index 024c5112..f2e9e82b 100644 --- a/applications/plugins/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -4,13 +4,6 @@ #define TAG "PicopassWorker" -const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78}; -const uint8_t picopass_factory_credit_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; -const uint8_t picopass_factory_debit_key[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; -const uint8_t picopass_xice_key[] = {0x20, 0x20, 0x66, 0x66, 0x66, 0x66, 0x88, 0x88}; -const uint8_t picopass_xicl_key[] = {0x20, 0x20, 0x66, 0x66, 0x66, 0x66, 0x88, 0x88}; -const uint8_t picopass_xics_key[] = {0x66, 0x66, 0x20, 0x20, 0x66, 0x66, 0x88, 0x88}; - static void picopass_worker_enable_field() { furi_hal_nfc_ll_txrx_on(); furi_hal_nfc_exit_sleep(); @@ -179,50 +172,6 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) { return ERR_NONE; } -static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) { - rfalPicoPassReadCheckRes rcRes; - rfalPicoPassCheckRes chkRes; - - ReturnCode err; - - uint8_t mac[4] = {0}; - uint8_t ccnr[12] = {0}; - - err = rfalPicoPassPollerReadCheck(&rcRes); - if(err != ERR_NONE) { - FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); - return err; - } - memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - - loclass_iclass_calc_div_key(csn, (uint8_t*)picopass_iclass_key, div_key, false); - loclass_opt_doReaderMAC(ccnr, div_key, mac); - - return rfalPicoPassPollerCheck(mac, &chkRes); -} - -static ReturnCode picopass_auth_factory(uint8_t* csn, uint8_t* div_key) { - rfalPicoPassReadCheckRes rcRes; - rfalPicoPassCheckRes chkRes; - - ReturnCode err; - - uint8_t mac[4] = {0}; - uint8_t ccnr[12] = {0}; - - err = rfalPicoPassPollerReadCheck(&rcRes); - if(err != ERR_NONE) { - FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); - return err; - } - memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - - loclass_iclass_calc_div_key(csn, (uint8_t*)picopass_factory_debit_key, div_key, false); - loclass_opt_doReaderMAC(ccnr, div_key, mac); - - return rfalPicoPassPollerCheck(mac, &chkRes); -} - static ReturnCode picopass_auth_dict( uint8_t* csn, PicopassPacs* pacs, @@ -291,19 +240,14 @@ static ReturnCode picopass_auth_dict( ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { ReturnCode err; - FURI_LOG_I(TAG, "Trying standard legacy key"); - err = picopass_auth_standard( - AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); + FURI_LOG_I(TAG, "Starting system dictionary attack [Standard KDF]"); + err = picopass_auth_dict( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, + pacs, + AA1[PICOPASS_KD_BLOCK_INDEX].data, + IclassEliteDictTypeFlipper, + false); if(err == ERR_NONE) { - memcpy(pacs->key, picopass_iclass_key, PICOPASS_BLOCK_LEN); - return ERR_NONE; - } - - FURI_LOG_I(TAG, "Trying factory default key"); - err = picopass_auth_factory( - AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); - if(err == ERR_NONE) { - memcpy(pacs->key, picopass_factory_debit_key, PICOPASS_BLOCK_LEN); return ERR_NONE; } @@ -329,17 +273,6 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { return ERR_NONE; } - FURI_LOG_I(TAG, "Starting system dictionary attack [Standard KDF]"); - err = picopass_auth_dict( - AA1[PICOPASS_CSN_BLOCK_INDEX].data, - pacs, - AA1[PICOPASS_KD_BLOCK_INDEX].data, - IclassEliteDictTypeFlipper, - false); - if(err == ERR_NONE) { - return ERR_NONE; - } - return err; } diff --git a/applications/plugins/picopass/picopass_worker.h b/applications/plugins/picopass/picopass_worker.h index 02b088b2..f5e9f303 100644 --- a/applications/plugins/picopass/picopass_worker.h +++ b/applications/plugins/picopass/picopass_worker.h @@ -1,6 +1,7 @@ #pragma once #include "picopass_device.h" +#include "picopass_keys.h" typedef struct PicopassWorker PicopassWorker; diff --git a/applications/plugins/picopass/scenes/picopass_scene_key_menu.c b/applications/plugins/picopass/scenes/picopass_scene_key_menu.c index b1db37f8..8aac6cb2 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_key_menu.c +++ b/applications/plugins/picopass/scenes/picopass_scene_key_menu.c @@ -1,4 +1,5 @@ #include "../picopass_i.h" +#include "../picopass_keys.h" enum SubmenuIndex { SubmenuIndexWriteStandard, @@ -8,11 +9,6 @@ enum SubmenuIndex { SubmenuIndexWriteCustom, //TODO: user input of key }; -extern const uint8_t picopass_xice_key[]; -extern const uint8_t picopass_xicl_key[]; -extern const uint8_t picopass_xics_key[]; -extern const uint8_t picopass_iclass_key[]; - void picopass_scene_key_menu_submenu_callback(void* context, uint32_t index) { Picopass* picopass = context; diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_card.c b/applications/plugins/picopass/scenes/picopass_scene_read_card.c index c62cba8e..96ec7c66 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_card.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card.c @@ -1,7 +1,6 @@ #include "../picopass_i.h" #include - -extern const uint8_t picopass_factory_debit_key[]; +#include "../picopass_keys.h" void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context) { UNUSED(event); diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c index b98951dc..bc07bb95 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c @@ -1,7 +1,6 @@ #include "../picopass_i.h" #include - -extern const uint8_t picopass_iclass_key[]; +#include "../picopass_keys.h" void picopass_scene_read_factory_success_widget_callback( GuiButtonType result, diff --git a/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt b/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt index 46808ef6..5da2a2fa 100644 --- a/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt +++ b/assets/resources/apps_data/picopass/assets/iclass_elite_dict.txt @@ -45,3 +45,5 @@ C1B74D7478053AE2 # default iCLASS RFIDeas 6B65797374726B72 + +5C100DF7042EAE64 From 50ef5deefc2f6b4dc1a5c89432e7a03094e9ba7d Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:24:47 +0200 Subject: [PATCH 19/23] [FL-3118] Dumb mode menu freeze fix (#2456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/services/desktop/desktop.c | 2 ++ applications/services/desktop/desktop_i.h | 2 ++ applications/services/desktop/scenes/desktop_scene_main.c | 1 + 3 files changed, 5 insertions(+) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index f8716e6c..556f4233 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -144,11 +144,13 @@ void desktop_unlock(Desktop* desktop) { } void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { + desktop->in_transition = true; view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled); desktop_main_set_dummy_mode_state(desktop->main_view, enabled); animation_manager_set_dummy_mode_state(desktop->animation_manager, enabled); desktop->settings.dummy_mode = enabled; DESKTOP_SETTINGS_SAVE(&desktop->settings); + desktop->in_transition = false; } Desktop* desktop_alloc() { diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 8034bbc3..2f3ec9b5 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -69,6 +69,8 @@ struct Desktop { FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; FuriTimer* auto_lock_timer; + + bool in_transition; }; Desktop* desktop_alloc(); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index b02958b6..4d1fa495 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -79,6 +79,7 @@ static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* void desktop_scene_main_callback(DesktopEvent event, void* context) { Desktop* desktop = (Desktop*)context; + if(desktop->in_transition) return; view_dispatcher_send_custom_event(desktop->view_dispatcher, event); } From 4fd043398a17b3965b7045c711fc5e36dbce984a Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Thu, 9 Mar 2023 18:01:53 +0300 Subject: [PATCH 20/23] Embed assets in elf file (#2466) * FBT: file_assets generator * Elf file: process manifest section externally * FBT, file_assets generator: add assets signature * Storage: assets path alias * Flipper application: assets unpacker * Apps, Storage: use '/data' alias for apps data * Storage: copy file to file * Assets: log flag, fixes * Update f18 api * Assets: asserts * Assets: fix signature_data check * App assets: example * Example assets: fix folder structure in readme * Assets: fix error handling * Assets builder: use ansii instead of utf-8, use .fapassets section instead of .fapfiles, add assets path to signature * Elf file: comment strange places * Storage: totaly optimized storage_file_copy_to_file --- .../debug/unit_tests/storage/storage_test.c | 6 +- .../examples/example_apps_assets/README.md | 58 +++ .../example_apps_assets/application.fam | 10 + .../example_apps_assets/example_apps_assets.c | 48 +++ .../files/poems/a jelly-fish.txt | 24 ++ .../files/poems/my shadow.txt | 23 ++ .../files/poems/theme in yellow.txt | 19 + .../example_apps_assets/files/test_asset.txt | 1 + .../examples/example_apps_data/README.md | 12 +- applications/services/storage/storage.h | 15 +- .../services/storage/storage_external_api.c | 21 + applications/services/storage/storage_i.h | 1 + .../services/storage/storage_processing.c | 14 +- firmware/targets/f18/api_symbols.csv | 3 +- firmware/targets/f7/api_symbols.csv | 3 +- lib/flipper_application/application_assets.c | 361 ++++++++++++++++++ lib/flipper_application/application_assets.h | 17 + lib/flipper_application/elf/elf_file.c | 116 +++--- lib/flipper_application/elf/elf_file.h | 34 +- lib/flipper_application/flipper_application.c | 78 +++- scripts/fbt/appmanifest.py | 1 + scripts/fbt_tools/fbt_extapps.py | 185 ++++++++- 22 files changed, 937 insertions(+), 113 deletions(-) create mode 100644 applications/examples/example_apps_assets/README.md create mode 100644 applications/examples/example_apps_assets/application.fam create mode 100644 applications/examples/example_apps_assets/example_apps_assets.c create mode 100644 applications/examples/example_apps_assets/files/poems/a jelly-fish.txt create mode 100644 applications/examples/example_apps_assets/files/poems/my shadow.txt create mode 100644 applications/examples/example_apps_assets/files/poems/theme in yellow.txt create mode 100644 applications/examples/example_apps_assets/files/test_asset.txt create mode 100644 lib/flipper_application/application_assets.c create mode 100644 lib/flipper_application/application_assets.h diff --git a/applications/debug/unit_tests/storage/storage_test.c b/applications/debug/unit_tests/storage/storage_test.c index 582be790..f0b45c59 100644 --- a/applications/debug/unit_tests/storage/storage_test.c +++ b/applications/debug/unit_tests/storage/storage_test.c @@ -362,8 +362,8 @@ 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"); + storage_common_remove(storage, "/data/test"); + int32_t ret = storage_file_create(storage, "/data/test", "test"); furi_record_close(RECORD_STORAGE); return ret; } @@ -401,7 +401,7 @@ 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_open(file, "/data")); mu_check(storage_dir_close(file)); storage_file_free(file); diff --git a/applications/examples/example_apps_assets/README.md b/applications/examples/example_apps_assets/README.md new file mode 100644 index 00000000..a24183e8 --- /dev/null +++ b/applications/examples/example_apps_assets/README.md @@ -0,0 +1,58 @@ +# Apps Assets folder Example + +This example shows how to use the Apps Assets folder to store data that is not part of the application itself, but is required for its operation, and that data is provided with the application. + +## What is the Apps Assets Folder? + +The **Apps Assets** folder is a folder where external applications unpack their assets. + +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 Assets 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 Assets folder will be `/ext/apps_assets/snake_game`. But using raw paths is not recommended, because the path to the Apps Assets folder can change in the future. Use the `/assets` alias instead. + +## How to get the path to the Apps Assets folder? + +You can use `/assets` alias to get the path to the current application data folder. For example, if you want to open a file `database.txt` in the Apps Assets folder, you can use the next path: `/data/database.txt`. But this way is not recommended, because even the `/assets` alias can change in the future. + +We recommend to use the `APP_ASSETS_PATH` macro to get the path to the Apps Assets folder. For example, if you want to open a file `database.txt` in the Apps Assets folder, you can use the next path: `APP_ASSETS_PATH("database.txt")`. + +## What is the difference between the Apps Assets folder and the Apps Data folder? + +The Apps Assets folder is used to store the data provided with the application. For example, if you want to create a game, you can store game levels (contant data) in the Apps Assets folder. + +The Apps Data folder is used to store data generated by the application. For example, if you want to create a game, you can save the progress of the game (user-generated data) in the Apps Data folder. + +## How to provide the data with the app? + +To provide data with an application, you need to create a folder inside your application folder (eg "files") and place the data in it. After that, you need to add `fap_file_assets="files"` to your application.fam file. + +For example, if you want to provide game levels with the application, you need to create a "levels" folder inside the "files" folder and put the game levels in it. After that, you need to add `fap_file_assets="files"` to your application.fam file. The final application folder structure will look like this: + +``` +snake_game +├── application.fam +├── snake_game.c +└── files + └── levels + ├── level1.txt + ├── level2.txt + └── level3.txt +``` + +When app is launched, the `files` folder will be unpacked to the Apps Assets folder. The final structure of the Apps Assets folder will look like this: + +``` +/assets +├── .assets.signature +└── levels + ├── level1.txt + ├── level2.txt + └── level3.txt +``` + +## When will the data be unpacked? + +The data is unpacked when the application starts, if the application is launched for the first time, or if the data within the application is updated. + +When an application is compiled, the contents of the "files" folder are hashed and stored within the application itself. When the application starts, this hash is compared to the hash stored in the `.assets.signature` file. If the hashes differ or the `.assets.signature` file does not exist, the application folder is deleted and the new data is unpacked. \ No newline at end of file diff --git a/applications/examples/example_apps_assets/application.fam b/applications/examples/example_apps_assets/application.fam new file mode 100644 index 00000000..4f324277 --- /dev/null +++ b/applications/examples/example_apps_assets/application.fam @@ -0,0 +1,10 @@ +App( + appid="example_apps_assets", + name="Example: Apps Assets", + apptype=FlipperAppType.EXTERNAL, + entry_point="example_apps_assets_main", + requires=["gui"], + stack_size=4 * 1024, + fap_category="Examples", + fap_file_assets="files", +) diff --git a/applications/examples/example_apps_assets/example_apps_assets.c b/applications/examples/example_apps_assets/example_apps_assets.c new file mode 100644 index 00000000..f2d0272f --- /dev/null +++ b/applications/examples/example_apps_assets/example_apps_assets.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +// Define log tag +#define TAG "example_apps_assets" + +static void example_apps_data_print_file_content(Storage* storage, const char* path) { + Stream* stream = file_stream_alloc(storage); + FuriString* line = furi_string_alloc(); + + FURI_LOG_I(TAG, "----------------------------------------"); + FURI_LOG_I(TAG, "File \"%s\" content:", path); + if(file_stream_open(stream, path, FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, line)) { + furi_string_replace_all(line, "\r", ""); + furi_string_replace_all(line, "\n", ""); + FURI_LOG_I(TAG, "%s", furi_string_get_cstr(line)); + } + } else { + FURI_LOG_E(TAG, "Failed to open file"); + } + FURI_LOG_I(TAG, "----------------------------------------"); + + furi_string_free(line); + file_stream_close(stream); + stream_free(stream); +} + +// Application entry point +int32_t example_apps_assets_main(void* p) { + // Mark argument as unused + UNUSED(p); + + // Open storage + Storage* storage = furi_record_open(RECORD_STORAGE); + + example_apps_data_print_file_content(storage, APP_ASSETS_PATH("test_asset.txt")); + example_apps_data_print_file_content(storage, APP_ASSETS_PATH("poems/a jelly-fish.txt")); + example_apps_data_print_file_content(storage, APP_ASSETS_PATH("poems/theme in yellow.txt")); + example_apps_data_print_file_content(storage, APP_ASSETS_PATH("poems/my shadow.txt")); + + // Close storage + furi_record_close(RECORD_STORAGE); + + return 0; +} diff --git a/applications/examples/example_apps_assets/files/poems/a jelly-fish.txt b/applications/examples/example_apps_assets/files/poems/a jelly-fish.txt new file mode 100644 index 00000000..46a5a4df --- /dev/null +++ b/applications/examples/example_apps_assets/files/poems/a jelly-fish.txt @@ -0,0 +1,24 @@ +A Jelly-Fish by Marianne Moore + +Visible, invisible, +A fluctuating charm, +An amber-colored amethyst +Inhabits it; your arm +Approaches, and +It opens and +It closes; +You have meant +To catch it, +And it shrivels; +You abandon +Your intent— +It opens, and it +Closes and you +Reach for it— +The blue +Surrounding it +Grows cloudy, and +It floats away +From you. + +source: "https://poets.org/anthology/poems-your-poetry-project-public-domain" \ No newline at end of file diff --git a/applications/examples/example_apps_assets/files/poems/my shadow.txt b/applications/examples/example_apps_assets/files/poems/my shadow.txt new file mode 100644 index 00000000..e113e7df --- /dev/null +++ b/applications/examples/example_apps_assets/files/poems/my shadow.txt @@ -0,0 +1,23 @@ +My Shadow by Robert Louis Stevenson + +I have a little shadow that goes in and out with me, +And what can be the use of him is more than I can see. +He is very, very like me from the heels up to the head; +And I see him jump before me, when I jump into my bed. + +The funniest thing about him is the way he likes to grow— +Not at all like proper children, which is always very slow; +For he sometimes shoots up taller like an India-rubber ball, +And he sometimes gets so little that there’s none of him at all. + +He hasn’t got a notion of how children ought to play, +And can only make a fool of me in every sort of way. +He stays so close beside me, he’s a coward you can see; +I’d think shame to stick to nursie as that shadow sticks to me! + +One morning, very early, before the sun was up, +I rose and found the shining dew on every buttercup; +But my lazy little shadow, like an arrant sleepy-head, +Had stayed at home behind me and was fast asleep in bed. + +source: "https://poets.org/anthology/poems-your-poetry-project-public-domain" \ No newline at end of file diff --git a/applications/examples/example_apps_assets/files/poems/theme in yellow.txt b/applications/examples/example_apps_assets/files/poems/theme in yellow.txt new file mode 100644 index 00000000..f392287b --- /dev/null +++ b/applications/examples/example_apps_assets/files/poems/theme in yellow.txt @@ -0,0 +1,19 @@ +Theme in Yellow by Carl Sandburg + +I spot the hills +With yellow balls in autumn. +I light the prairie cornfields +Orange and tawny gold clusters +And I am called pumpkins. +On the last of October +When dusk is fallen +Children join hands +And circle round me +Singing ghost songs +And love to the harvest moon; +I am a jack-o'-lantern +With terrible teeth +And the children know +I am fooling. + +source: "https://poets.org/anthology/poems-your-poetry-project-public-domain" \ No newline at end of file diff --git a/applications/examples/example_apps_assets/files/test_asset.txt b/applications/examples/example_apps_assets/files/test_asset.txt new file mode 100644 index 00000000..1adcb55e --- /dev/null +++ b/applications/examples/example_apps_assets/files/test_asset.txt @@ -0,0 +1 @@ +## This is test file content \ No newline at end of file diff --git a/applications/examples/example_apps_data/README.md b/applications/examples/example_apps_data/README.md index fd866607..c70ac055 100644 --- a/applications/examples/example_apps_data/README.md +++ b/applications/examples/example_apps_data/README.md @@ -9,10 +9,16 @@ The **Apps Data** folder is a folder used to store data for external apps that a 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. +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 `/data` 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. +You can use `/data` 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: `/data/config.txt`. But this way is not recommended, because even the `/data` 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")`. \ No newline at end of file +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")`. + +## What is the difference between the Apps Assets folder and the Apps Data folder? + +The Apps Assets folder is used to store the data provided with the application. For example, if you want to create a game, you can store game levels (contant data) in the Apps Assets folder. + +The Apps Data folder is used to store data generated by the application. For example, if you want to create a game, you can save the progress of the game (user-generated data) in the Apps Data folder. \ No newline at end of file diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index e35b8164..a1267575 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -10,12 +10,14 @@ extern "C" { #define STORAGE_INT_PATH_PREFIX "/int" #define STORAGE_EXT_PATH_PREFIX "/ext" #define STORAGE_ANY_PATH_PREFIX "/any" -#define STORAGE_APP_DATA_PATH_PREFIX "/app" +#define STORAGE_APP_DATA_PATH_PREFIX "/data" +#define STORAGE_APP_ASSETS_PATH_PREFIX "/assets" #define INT_PATH(path) STORAGE_INT_PATH_PREFIX "/" path #define EXT_PATH(path) STORAGE_EXT_PATH_PREFIX "/" path #define ANY_PATH(path) STORAGE_ANY_PATH_PREFIX "/" path #define APP_DATA_PATH(path) STORAGE_APP_DATA_PATH_PREFIX "/" path +#define APP_ASSETS_PATH(path) STORAGE_APP_ASSETS_PATH_PREFIX "/" path #define RECORD_STORAGE "storage" @@ -146,6 +148,17 @@ bool storage_file_eof(File* file); */ bool storage_file_exists(Storage* storage, const char* path); +/** + * @brief Copy data from one opened file to another opened file + * Size bytes will be copied from current position of source file to current position of destination file + * + * @param source source file + * @param destination destination file + * @param size size of data to copy + * @return bool success flag + */ +bool storage_file_copy_to_file(File* source, File* destination, uint32_t size); + /******************* Dir Functions *******************/ /** Opens a directory to get objects from it diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 8d8220f8..ffc3da4b 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -9,6 +9,7 @@ #define MAX_NAME_LENGTH 256 #define MAX_EXT_LEN 16 +#define FILE_BUFFER_SIZE 512 #define TAG "StorageAPI" @@ -251,6 +252,26 @@ bool storage_file_exists(Storage* storage, const char* path) { return exist; } +bool storage_file_copy_to_file(File* source, File* destination, uint32_t size) { + uint8_t* buffer = malloc(FILE_BUFFER_SIZE); + + while(size) { + uint32_t read_size = size > FILE_BUFFER_SIZE ? FILE_BUFFER_SIZE : size; + if(storage_file_read(source, buffer, read_size) != read_size) { + break; + } + + if(storage_file_write(destination, buffer, read_size) != read_size) { + break; + } + + size -= read_size; + } + + free(buffer); + return size == 0; +} + /****************** DIR ******************/ static bool storage_dir_open_internal(File* file, const char* path) { diff --git a/applications/services/storage/storage_i.h b/applications/services/storage/storage_i.h index 85df5d92..cb7f16e4 100644 --- a/applications/services/storage/storage_i.h +++ b/applications/services/storage/storage_i.h @@ -13,6 +13,7 @@ extern "C" { #define STORAGE_COUNT (ST_INT + 1) #define APPS_DATA_PATH EXT_PATH("apps_data") +#define APPS_ASSETS_PATH EXT_PATH("apps_assets") typedef struct { ViewPort* view_port; diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index cab1edff..2a335e36 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -454,7 +454,7 @@ void storage_process_alias( FuriString* apps_data_path_with_appsid = furi_string_alloc_set(APPS_DATA_PATH "/"); furi_string_cat(apps_data_path_with_appsid, furi_thread_get_appid(thread_id)); - // "/app" -> "/ext/apps_data/appsid" + // "/data" -> "/ext/apps_data/appsid" furi_string_replace_at( path, 0, @@ -472,6 +472,18 @@ void storage_process_alias( } furi_string_free(apps_data_path_with_appsid); + } else if(furi_string_start_with(path, STORAGE_APP_ASSETS_PATH_PREFIX)) { + FuriString* apps_assets_path_with_appsid = furi_string_alloc_set(APPS_ASSETS_PATH "/"); + furi_string_cat(apps_assets_path_with_appsid, furi_thread_get_appid(thread_id)); + + // "/assets" -> "/ext/apps_assets/appsid" + furi_string_replace_at( + path, + 0, + strlen(STORAGE_APP_ASSETS_PATH_PREFIX), + furi_string_get_cstr(apps_assets_path_with_appsid)); + + furi_string_free(apps_assets_path_with_appsid); } } diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 8060d38a..07c323a1 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,18.0,, +Version,+,18.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1636,6 +1636,7 @@ Function,-,storage_dir_rewind,_Bool,File* Function,+,storage_error_get_desc,const char*,FS_Error Function,+,storage_file_alloc,File*,Storage* Function,+,storage_file_close,_Bool,File* +Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" Function,+,storage_file_free,void,File* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index f505b943..fcacaeee 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,18.0,, +Version,+,18.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2461,6 +2461,7 @@ Function,-,storage_dir_rewind,_Bool,File* Function,+,storage_error_get_desc,const char*,FS_Error Function,+,storage_file_alloc,File*,Storage* Function,+,storage_file_close,_Bool,File* +Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" Function,+,storage_file_free,void,File* diff --git a/lib/flipper_application/application_assets.c b/lib/flipper_application/application_assets.c new file mode 100644 index 00000000..1262870d --- /dev/null +++ b/lib/flipper_application/application_assets.c @@ -0,0 +1,361 @@ +#include "application_assets.h" +#include +#include + +// #define ELF_ASSETS_DEBUG_LOG 1 + +#ifndef ELF_ASSETS_DEBUG_LOG +#undef FURI_LOG_D +#define FURI_LOG_D(...) +#undef FURI_LOG_E +#define FURI_LOG_E(...) +#endif + +#define FLIPPER_APPLICATION_ASSETS_MAGIC 0x4F4C5A44 +#define FLIPPER_APPLICATION_ASSETS_VERSION 1 +#define FLIPPER_APPLICATION_ASSETS_SIGNATURE_FILENAME ".assets.signature" + +#define BUFFER_SIZE 512 + +#define TAG "fap_assets" + +#pragma pack(push, 1) + +typedef struct { + uint32_t magic; + uint32_t version; + uint32_t dirs_count; + uint32_t files_count; +} FlipperApplicationAssetsHeader; + +#pragma pack(pop) + +typedef enum { + AssetsSignatureResultEqual, + AssetsSignatureResultNotEqual, + AssetsSignatureResultError, +} AssetsSignatureResult; + +static FuriString* flipper_application_assets_alloc_app_full_path(FuriString* app_name) { + furi_assert(app_name); + FuriString* full_path = furi_string_alloc_set(APPS_ASSETS_PATH "/"); + furi_string_cat(full_path, app_name); + return full_path; +} + +static FuriString* flipper_application_assets_alloc_signature_file_path(FuriString* app_name) { + furi_assert(app_name); + FuriString* signature_file_path = flipper_application_assets_alloc_app_full_path(app_name); + furi_string_cat(signature_file_path, "/" FLIPPER_APPLICATION_ASSETS_SIGNATURE_FILENAME); + + return signature_file_path; +} + +static uint8_t* flipper_application_assets_alloc_and_load_data(File* file, size_t* size) { + furi_assert(file); + + uint8_t* data = NULL; + uint32_t length = 0; + + // read data length + if(storage_file_read(file, &length, sizeof(length)) != sizeof(length)) { + return NULL; + } + + data = malloc(length); + + // read data + if(storage_file_read(file, (void*)data, length) != length) { + free((void*)data); + return NULL; + } + + if(size != NULL) { + *size = length; + } + + return data; +} + +static bool flipper_application_assets_process_files( + Storage* storage, + File* file, + FuriString* app_name, + uint32_t files_count) { + furi_assert(storage); + furi_assert(file); + furi_assert(app_name); + + UNUSED(storage); + + bool success = false; + uint32_t length = 0; + char* path = NULL; + FuriString* file_path = furi_string_alloc(); + File* destination = storage_file_alloc(storage); + + FuriString* full_path = flipper_application_assets_alloc_app_full_path(app_name); + + for(uint32_t i = 0; i < files_count; i++) { + path = (char*)flipper_application_assets_alloc_and_load_data(file, NULL); + + if(path == NULL) { + break; + } + + // read file size + if(storage_file_read(file, &length, sizeof(length)) != sizeof(length)) { + break; + } + + furi_string_set(file_path, full_path); + furi_string_cat(file_path, "/"); + furi_string_cat(file_path, path); + + if(!storage_file_open( + destination, furi_string_get_cstr(file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + FURI_LOG_E(TAG, "Can't create file: %s", furi_string_get_cstr(file_path)); + break; + } + + // copy data to file + if(!storage_file_copy_to_file(file, destination, length)) { + FURI_LOG_E(TAG, "Can't copy data to file: %s", furi_string_get_cstr(file_path)); + break; + } + + storage_file_close(destination); + + free(path); + path = NULL; + + if(i == files_count - 1) { + success = true; + } + } + + if(path != NULL) { + free(path); + } + + storage_file_free(destination); + furi_string_free(file_path); + + return success; +} + +static bool flipper_application_assets_process_dirs( + Storage* storage, + File* file, + FuriString* app_name, + uint32_t dirs_count) { + furi_assert(storage); + furi_assert(file); + furi_assert(app_name); + + bool success = false; + FuriString* full_path = flipper_application_assets_alloc_app_full_path(app_name); + + do { + if(!storage_simply_mkdir(storage, APPS_ASSETS_PATH)) { + break; + } + + if(!storage_simply_mkdir(storage, furi_string_get_cstr(full_path))) { + break; + } + + FuriString* dir_path = furi_string_alloc(); + char* path = NULL; + + for(uint32_t i = 0; i < dirs_count; i++) { + path = (char*)flipper_application_assets_alloc_and_load_data(file, NULL); + + if(path == NULL) { + break; + } + + furi_string_set(dir_path, full_path); + furi_string_cat(dir_path, "/"); + furi_string_cat(dir_path, path); + + if(!storage_simply_mkdir(storage, furi_string_get_cstr(dir_path))) { + FURI_LOG_E(TAG, "Can't create directory: %s", furi_string_get_cstr(dir_path)); + break; + } + + free(path); + path = NULL; + + if(i == dirs_count - 1) { + success = true; + } + } + + if(path != NULL) { + free(path); + } + + furi_string_free(dir_path); + } while(false); + + furi_string_free(full_path); + + return success; +} + +static AssetsSignatureResult flipper_application_assets_process_signature( + Storage* storage, + File* file, + FuriString* app_name, + uint8_t** signature_data, + size_t* signature_data_size) { + furi_assert(storage); + furi_assert(file); + furi_assert(app_name); + furi_assert(signature_data); + furi_assert(signature_data_size); + + AssetsSignatureResult result = AssetsSignatureResultError; + File* signature_file = storage_file_alloc(storage); + FuriString* signature_file_path = + flipper_application_assets_alloc_signature_file_path(app_name); + + do { + // read signature + *signature_data = + flipper_application_assets_alloc_and_load_data(file, signature_data_size); + + if(*signature_data == NULL) { //-V547 + FURI_LOG_E(TAG, "Can't read signature"); + break; + } + + result = AssetsSignatureResultNotEqual; + + if(!storage_file_open( + signature_file, + furi_string_get_cstr(signature_file_path), + FSAM_READ_WRITE, + FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "Can't open signature file"); + break; + } + + size_t signature_size = storage_file_size(signature_file); + uint8_t* signature_file_data = malloc(signature_size); + if(storage_file_read(signature_file, signature_file_data, signature_size) != + signature_size) { + FURI_LOG_E(TAG, "Can't read signature file"); + free(signature_file_data); + break; + } + + if(memcmp(*signature_data, signature_file_data, signature_size) == 0) { + FURI_LOG_D(TAG, "Assets signature is equal"); + result = AssetsSignatureResultEqual; + } + + free(signature_file_data); + } while(0); + + storage_file_free(signature_file); + furi_string_free(signature_file_path); + + return result; +} + +bool flipper_application_assets_load(File* file, const char* elf_path, size_t offset, size_t size) { + UNUSED(size); + furi_assert(file); + furi_assert(elf_path); + FlipperApplicationAssetsHeader header; + bool result = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + uint8_t* signature_data = NULL; + size_t signature_data_size = 0; + FuriString* app_name = furi_string_alloc(); + path_extract_filename_no_ext(elf_path, app_name); + + FURI_LOG_D(TAG, "Loading assets for %s", furi_string_get_cstr(app_name)); + + do { + if(!storage_file_seek(file, offset, true)) { + break; + } + + // read header + if(storage_file_read(file, &header, sizeof(header)) != sizeof(header)) { + break; + } + + if(header.magic != FLIPPER_APPLICATION_ASSETS_MAGIC) { + break; + } + + if(header.version != FLIPPER_APPLICATION_ASSETS_VERSION) { + break; + } + + // process signature + AssetsSignatureResult signature_result = flipper_application_assets_process_signature( + storage, file, app_name, &signature_data, &signature_data_size); + + if(signature_result == AssetsSignatureResultError) { + FURI_LOG_E(TAG, "Assets signature error"); + break; + } else if(signature_result == AssetsSignatureResultEqual) { + FURI_LOG_D(TAG, "Assets signature equal, skip loading"); + result = true; + break; + } else { + FURI_LOG_D(TAG, "Assets signature not equal, loading"); + + // remove old assets + FuriString* full_path = flipper_application_assets_alloc_app_full_path(app_name); + storage_simply_remove_recursive(storage, furi_string_get_cstr(full_path)); + furi_string_free(full_path); + + FURI_LOG_D(TAG, "Assets removed"); + } + + // process directories + if(!flipper_application_assets_process_dirs(storage, file, app_name, header.dirs_count)) { + break; + } + + // process files + if(!flipper_application_assets_process_files(storage, file, app_name, header.files_count)) { + break; + } + + // write signature + FuriString* signature_file_path = + flipper_application_assets_alloc_signature_file_path(app_name); + File* signature_file = storage_file_alloc(storage); + + if(storage_file_open( + signature_file, + furi_string_get_cstr(signature_file_path), + FSAM_WRITE, + FSOM_CREATE_ALWAYS)) { + storage_file_write(signature_file, signature_data, signature_data_size); + } + + storage_file_free(signature_file); + furi_string_free(signature_file_path); + + result = true; + } while(false); + + if(signature_data != NULL) { + free(signature_data); + } + + furi_record_close(RECORD_STORAGE); + furi_string_free(app_name); + + FURI_LOG_D(TAG, "Assets loading %s", result ? "success" : "failed"); + + return result; +} \ No newline at end of file diff --git a/lib/flipper_application/application_assets.h b/lib/flipper_application/application_assets.h new file mode 100644 index 00000000..83bb14fb --- /dev/null +++ b/lib/flipper_application/application_assets.h @@ -0,0 +1,17 @@ +/** + * @file application_assets.h + * Flipper application assets + */ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool flipper_application_assets_load(File* file, const char* elf_path, size_t offset, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 64d5755e..58e31533 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -241,7 +241,7 @@ static void elf_relocate_jmp_call(ELFFile* elf, Elf32_Addr relAddr, int type, El if(to_thumb || (symAddr & 2) || (!is_call)) { FURI_LOG_D( TAG, - "can't relocate value at %x, %s, doing trampoline", + "can't relocate value at %lx, %s, doing trampoline", relAddr, elf_reloc_type_to_str(type)); @@ -421,29 +421,11 @@ typedef enum { SectionTypeRelData = 1 << 2, SectionTypeSymTab = 1 << 3, SectionTypeStrTab = 1 << 4, - SectionTypeManifest = 1 << 5, - SectionTypeDebugLink = 1 << 6, + SectionTypeDebugLink = 1 << 5, - SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab | SectionTypeManifest, + SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab, } SectionType; -static bool elf_load_metadata( - ELFFile* elf, - Elf32_Shdr* section_header, - FlipperApplicationManifest* manifest) { - if(section_header->sh_size < sizeof(FlipperApplicationManifest)) { - return false; - } - - if(manifest == NULL) { - return true; - } - - return storage_file_seek(elf->fd, section_header->sh_offset, true) && - storage_file_read(elf->fd, manifest, section_header->sh_size) == - section_header->sh_size; -} - static bool elf_load_debug_link(ELFFile* elf, Elf32_Shdr* section_header) { elf->debug_link_info.debug_link_size = section_header->sh_size; elf->debug_link_info.debug_link = malloc(section_header->sh_size); @@ -478,7 +460,7 @@ static bool elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* return false; } - FURI_LOG_D(TAG, "0x%X", section->data); + FURI_LOG_D(TAG, "0x%p", section->data); return true; } @@ -486,8 +468,7 @@ static SectionType elf_preload_section( ELFFile* elf, size_t section_idx, Elf32_Shdr* section_header, - FuriString* name_string, - FlipperApplicationManifest* manifest) { + FuriString* name_string) { const char* name = furi_string_get_cstr(name_string); #ifdef ELF_DEBUG_LOG @@ -572,16 +553,6 @@ static SectionType elf_preload_section( return SectionTypeStrTab; } - // Load manifest section - if(strcmp(name, ".fapmeta") == 0) { - FURI_LOG_D(TAG, "Found .fapmeta section"); - if(elf_load_metadata(elf, section_header, manifest)) { - return SectionTypeManifest; - } else { - return SectionTypeERROR; - } - } - // Load debug link section if(strcmp(name, ".gnu_debuglink") == 0) { FURI_LOG_D(TAG, "Found .gnu_debuglink section"); @@ -692,41 +663,12 @@ bool elf_file_open(ELFFile* elf, const char* path) { return true; } -bool elf_file_load_manifest(ELFFile* elf, FlipperApplicationManifest* manifest) { - bool result = false; - FuriString* name; - name = furi_string_alloc(); - - FURI_LOG_D(TAG, "Looking for manifest section"); - for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) { - Elf32_Shdr section_header; - - furi_string_reset(name); - if(!elf_read_section(elf, section_idx, §ion_header, name)) { - break; - } - - if(furi_string_cmp(name, ".fapmeta") == 0) { - if(elf_load_metadata(elf, §ion_header, manifest)) { - FURI_LOG_D(TAG, "Load manifest done"); - result = true; - break; - } else { - break; - } - } - } - - furi_string_free(name); - return result; -} - -bool elf_file_load_section_table(ELFFile* elf, FlipperApplicationManifest* manifest) { +bool elf_file_load_section_table(ELFFile* elf) { SectionType loaded_sections = SectionTypeERROR; - FuriString* name; - name = furi_string_alloc(); + FuriString* name = furi_string_alloc(); FURI_LOG_D(TAG, "Scan ELF indexs..."); + // TODO: why we start from 1? for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) { Elf32_Shdr section_header; @@ -738,8 +680,7 @@ bool elf_file_load_section_table(ELFFile* elf, FlipperApplicationManifest* manif FURI_LOG_D( TAG, "Preloading data for section #%d %s", section_idx, furi_string_get_cstr(name)); - SectionType section_type = - elf_preload_section(elf, section_idx, §ion_header, name, manifest); + SectionType section_type = elf_preload_section(elf, section_idx, §ion_header, name); loaded_sections |= section_type; if(section_type == SectionTypeERROR) { @@ -753,14 +694,49 @@ bool elf_file_load_section_table(ELFFile* elf, FlipperApplicationManifest* manif return IS_FLAGS_SET(loaded_sections, SectionTypeValid); } +ElfProcessSectionResult elf_process_section( + ELFFile* elf, + const char* name, + ElfProcessSection* process_section, + void* context) { + ElfProcessSectionResult result = ElfProcessSectionResultNotFound; + FuriString* section_name = furi_string_alloc(); + Elf32_Shdr section_header; + + // find section + // TODO: why we start from 1? + for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) { + furi_string_reset(section_name); + if(!elf_read_section(elf, section_idx, §ion_header, section_name)) { + break; + } + + if(furi_string_cmp(section_name, name) == 0) { + result = ElfProcessSectionResultCannotProcess; + break; + } + } + + if(result != ElfProcessSectionResultNotFound) { //-V547 + if(process_section(elf->fd, section_header.sh_offset, section_header.sh_size, context)) { + result = ElfProcessSectionResultSuccess; + } else { + result = ElfProcessSectionResultCannotProcess; + } + } + + furi_string_free(section_name); + + return result; +} + ELFFileLoadStatus elf_file_load_sections(ELFFile* elf) { ELFFileLoadStatus status = ELFFileLoadStatusSuccess; ELFSectionDict_it_t it; AddressCache_init(elf->relocation_cache); - for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); - ELFSectionDict_next(it)) { + for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) { ELFSectionDict_itref_t* itref = ELFSectionDict_ref(it); FURI_LOG_D(TAG, "Relocating section '%s'", itref->key); if(!elf_relocate_section(elf, &itref->value)) { diff --git a/lib/flipper_application/elf/elf_file.h b/lib/flipper_application/elf/elf_file.h index 673f165c..f371cdb2 100644 --- a/lib/flipper_application/elf/elf_file.h +++ b/lib/flipper_application/elf/elf_file.h @@ -37,6 +37,14 @@ typedef enum { ELFFileLoadStatusMissingImports, } ELFFileLoadStatus; +typedef enum { + ElfProcessSectionResultNotFound, + ElfProcessSectionResultCannotProcess, + ElfProcessSectionResultSuccess, +} ElfProcessSectionResult; + +typedef bool(ElfProcessSection)(File* file, size_t offset, size_t size, void* context); + /** * @brief Allocate ELFFile instance * @param storage @@ -59,21 +67,12 @@ void elf_file_free(ELFFile* elf_file); */ bool elf_file_open(ELFFile* elf_file, const char* path); -/** - * @brief Load ELF file manifest - * @param elf - * @param manifest - * @return bool - */ -bool elf_file_load_manifest(ELFFile* elf, FlipperApplicationManifest* manifest); - /** * @brief Load ELF file section table (load stage #1) * @param elf_file - * @param manifest * @return bool */ -bool elf_file_load_section_table(ELFFile* elf_file, FlipperApplicationManifest* manifest); +bool elf_file_load_section_table(ELFFile* elf_file); /** * @brief Load and relocate ELF file sections (load stage #2) @@ -122,6 +121,21 @@ void elf_file_init_debug_info(ELFFile* elf_file, ELFDebugInfo* debug_info); */ void elf_file_clear_debug_info(ELFDebugInfo* debug_info); +/** + * @brief Process ELF file section + * + * @param elf_file + * @param name + * @param process_section + * @param context + * @return ElfProcessSectionResult + */ +ElfProcessSectionResult elf_process_section( + ELFFile* elf_file, + const char* name, + ElfProcessSection* process_section, + void* context); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index 58909218..6e20c080 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -1,6 +1,7 @@ #include "flipper_application.h" #include "elf/elf_file.h" #include +#include "application_assets.h" #define TAG "fapp" @@ -55,24 +56,83 @@ static FlipperApplicationPreloadStatus return FlipperApplicationPreloadStatusSuccess; } -/* Parse headers, load manifest */ -FlipperApplicationPreloadStatus - flipper_application_preload_manifest(FlipperApplication* app, const char* path) { - if(!elf_file_open(app->elf, path) || !elf_file_load_manifest(app->elf, &app->manifest)) { +static bool flipper_application_process_manifest_section( + File* file, + size_t offset, + size_t size, + void* context) { + FlipperApplicationManifest* manifest = context; + + if(size < sizeof(FlipperApplicationManifest)) { + return false; + } + + if(manifest == NULL) { + return true; + } + + return storage_file_seek(file, offset, true) && + storage_file_read(file, manifest, size) == size; +} + +// we can't use const char* as context because we will lose the const qualifier +typedef struct { + const char* path; +} FlipperApplicationPreloadAssetsContext; + +static bool flipper_application_process_assets_section( + File* file, + size_t offset, + size_t size, + void* context) { + FlipperApplicationPreloadAssetsContext* preload_context = context; + return flipper_application_assets_load(file, preload_context->path, offset, size); +} + +static FlipperApplicationPreloadStatus + flipper_application_load(FlipperApplication* app, const char* path, bool load_full) { + if(!elf_file_open(app->elf, path)) { + return FlipperApplicationPreloadStatusInvalidFile; + } + + // if we are loading full file + if(load_full) { + // load section table + if(!elf_file_load_section_table(app->elf)) { + return FlipperApplicationPreloadStatusInvalidFile; + } + + // load assets section + FlipperApplicationPreloadAssetsContext preload_context = {.path = path}; + if(elf_process_section( + app->elf, + ".fapassets", + flipper_application_process_assets_section, + &preload_context) == ElfProcessSectionResultCannotProcess) { + return FlipperApplicationPreloadStatusInvalidFile; + } + } + + // load manifest section + if(elf_process_section( + app->elf, ".fapmeta", flipper_application_process_manifest_section, &app->manifest) != + ElfProcessSectionResultSuccess) { return FlipperApplicationPreloadStatusInvalidFile; } return flipper_application_validate_manifest(app); } +/* Parse headers, load manifest */ +FlipperApplicationPreloadStatus + flipper_application_preload_manifest(FlipperApplication* app, const char* path) { + return flipper_application_load(app, path, false); +} + /* Parse headers, load full file */ FlipperApplicationPreloadStatus flipper_application_preload(FlipperApplication* app, const char* path) { - if(!elf_file_open(app->elf, path) || !elf_file_load_section_table(app->elf, &app->manifest)) { - return FlipperApplicationPreloadStatusInvalidFile; - } - - return flipper_application_validate_manifest(app); + return flipper_application_load(app, path, true); } const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app) { diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 64b9f6f3..eb1652b7 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -67,6 +67,7 @@ class FlipperApplication: fap_icon_assets_symbol: Optional[str] = None fap_extbuild: List[ExternallyBuiltFile] = field(default_factory=list) fap_private_libs: List[Library] = field(default_factory=list) + fap_file_assets: Optional[str] = None # Internally used by fbt _appdir: Optional[object] = None _apppath: Optional[str] = None diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 214afd8a..d26b1b79 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Optional +from typing import Optional, TypedDict from SCons.Builder import Builder from SCons.Action import Action from SCons.Errors import UserError @@ -15,6 +15,8 @@ import os import pathlib import itertools import shutil +import struct +import hashlib from ansi.color import fg @@ -151,12 +153,24 @@ def BuildAppElf(env, app): app_artifacts.compact, [app_env["SDK_DEFINITION"], app_env.Value(manifest_vals)], ) + + # Add dependencies on icon files if app.fap_icon: app_env.Depends( app_artifacts.compact, app_env.File(f"{app._apppath}/{app.fap_icon}"), ) + # Add dependencies on file assets + if app.fap_file_assets: + app_env.Depends( + app_artifacts.compact, + app_env.GlobRecursive( + "*", + app._appdir.Dir(app.fap_file_assets), + ), + ) + app_artifacts.validator = app_env.ValidateAppImports(app_artifacts.compact) app_env.AlwaysBuild(app_artifacts.validator) app_env.Alias(app_alias, app_artifacts.validator) @@ -266,6 +280,159 @@ def resources_fap_dist_action(target, source, env): shutil.copy(src.path, target.path) +def generate_embed_app_metadata_emitter(target, source, env): + app = env["APP"] + + meta_file_name = source[0].path + ".meta" + target.append("#" + meta_file_name) + + if app.fap_file_assets: + files_section = source[0].path + ".files.section" + target.append("#" + files_section) + + return (target, source) + + +class File(TypedDict): + path: str + size: int + content_path: str + + +class Dir(TypedDict): + path: str + + +def prepare_app_files(target, source, env): + app = env["APP"] + + directory = app._appdir.Dir(app.fap_file_assets) + directory_path = directory.abspath + + if not directory.exists(): + raise UserError(f"File asset directory {directory} does not exist") + + file_list: list[File] = [] + directory_list: list[Dir] = [] + + for root, dirs, files in os.walk(directory_path): + for file_info in files: + file_path = os.path.join(root, file_info) + file_size = os.path.getsize(file_path) + file_list.append( + { + "path": os.path.relpath(file_path, directory_path), + "size": file_size, + "content_path": file_path, + } + ) + + for dir_info in dirs: + dir_path = os.path.join(root, dir_info) + dir_size = sum( + os.path.getsize(os.path.join(dir_path, f)) for f in os.listdir(dir_path) + ) + directory_list.append( + { + "path": os.path.relpath(dir_path, directory_path), + } + ) + + file_list.sort(key=lambda f: f["path"]) + directory_list.sort(key=lambda d: d["path"]) + + files_section = source[0].path + ".files.section" + + with open(files_section, "wb") as f: + # u32 magic + # u32 version + # u32 dirs_count + # u32 files_count + # u32 signature_size + # u8[] signature + # Dirs: + # u32 dir_name length + # u8[] dir_name + # Files: + # u32 file_name length + # u8[] file_name + # u32 file_content_size + # u8[] file_content + + # Write header magic and version + f.write(struct.pack(" Date: Thu, 9 Mar 2023 18:13:18 +0100 Subject: [PATCH 21/23] Upside down / left handed orientation support (#2462) * Add backup files to .gitignore * Added lefty support in Settings > System > hand Orient: Fixes: #1015 * Left handed mode * Fix lefthanded mode on vertical interfaces * Input: new composite sequence identifier * Gui: move input mapping from Canvas to ViewPort, properly handle input mapping on View switch in ViewDispatcher * Rpc: proper input sequencing and tagging in RpcGui * Rpc: remove magic from RpcGui Co-authored-by: MrDaGree <5050898+MrDaGree@users.noreply.github.com> Co-authored-by: Willy-JL Co-authored-by: Aleksandr Kutuzov Co-authored-by: Sergey Gavrilov --- .gitignore | 1 + applications/services/gui/canvas.c | 38 +++++++-------- applications/services/gui/gui.c | 8 +++- applications/services/gui/gui_i.h | 1 + applications/services/gui/view_dispatcher.c | 22 +++++---- applications/services/gui/view_port.c | 48 +++++++++++++------ applications/services/input/input.c | 8 ++-- applications/services/input/input.h | 10 +++- applications/services/rpc/rpc_gui.c | 21 ++++++++ .../settings/system/system_settings.c | 23 +++++++++ .../targets/furi_hal_include/furi_hal_rtc.h | 1 + 11 files changed, 133 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 542652eb..45ac9113 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*~ *.swp *.swo *.gdb_history diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index d47bba6b..9c29a39f 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -376,39 +377,36 @@ void canvas_set_bitmap_mode(Canvas* canvas, bool alpha) { void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { furi_assert(canvas); + const u8g2_cb_t* rotate_cb = NULL; + bool need_swap = false; if(canvas->orientation != orientation) { switch(orientation) { case CanvasOrientationHorizontal: - if(canvas->orientation == CanvasOrientationVertical || - canvas->orientation == CanvasOrientationVerticalFlip) { - FURI_SWAP(canvas->width, canvas->height); - } - u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); + need_swap = canvas->orientation == CanvasOrientationVertical || + canvas->orientation == CanvasOrientationVerticalFlip; + rotate_cb = U8G2_R0; break; case CanvasOrientationHorizontalFlip: - if(canvas->orientation == CanvasOrientationVertical || - canvas->orientation == CanvasOrientationVerticalFlip) { - FURI_SWAP(canvas->width, canvas->height); - } - u8g2_SetDisplayRotation(&canvas->fb, U8G2_R2); + need_swap = canvas->orientation == CanvasOrientationVertical || + canvas->orientation == CanvasOrientationVerticalFlip; + rotate_cb = U8G2_R2; break; case CanvasOrientationVertical: - if(canvas->orientation == CanvasOrientationHorizontal || - canvas->orientation == CanvasOrientationHorizontalFlip) { - FURI_SWAP(canvas->width, canvas->height); - }; - u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); + need_swap = canvas->orientation == CanvasOrientationHorizontal || + canvas->orientation == CanvasOrientationHorizontalFlip; + rotate_cb = U8G2_R3; break; case CanvasOrientationVerticalFlip: - if(canvas->orientation == CanvasOrientationHorizontal || - canvas->orientation == CanvasOrientationHorizontalFlip) { - FURI_SWAP(canvas->width, canvas->height); - } - u8g2_SetDisplayRotation(&canvas->fb, U8G2_R1); + need_swap = canvas->orientation == CanvasOrientationHorizontal || + canvas->orientation == CanvasOrientationHorizontalFlip; + rotate_cb = U8G2_R1; break; default: furi_assert(0); } + + if(need_swap) FURI_SWAP(canvas->width, canvas->height); + u8g2_SetDisplayRotation(&canvas->fb, rotate_cb); canvas->orientation = orientation; } } diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index 94bab140..24b48a83 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -50,7 +50,13 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { uint8_t left_used = 0; uint8_t right_used = 0; uint8_t width; - canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) { + canvas_set_orientation(gui->canvas, CanvasOrientationHorizontalFlip); + } else { + canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal); + } + canvas_frame_set( gui->canvas, GUI_STATUS_BAR_X, GUI_STATUS_BAR_Y, GUI_DISPLAY_WIDTH, GUI_STATUS_BAR_HEIGHT); diff --git a/applications/services/gui/gui_i.h b/applications/services/gui/gui_i.h index 45061bd5..a5cd8412 100644 --- a/applications/services/gui/gui_i.h +++ b/applications/services/gui/gui_i.h @@ -8,6 +8,7 @@ #include "gui.h" #include +#include #include #include #include diff --git a/applications/services/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c index 04695874..920b3c13 100644 --- a/applications/services/gui/view_dispatcher.c +++ b/applications/services/gui/view_dispatcher.c @@ -320,6 +320,13 @@ void view_dispatcher_send_custom_event(ViewDispatcher* view_dispatcher, uint32_t furi_message_queue_put(view_dispatcher->queue, &message, FuriWaitForever) == FuriStatusOk); } +static const ViewPortOrientation view_dispatcher_view_port_orientation_table[] = { + [ViewOrientationVertical] = ViewPortOrientationVertical, + [ViewOrientationVerticalFlip] = ViewPortOrientationVerticalFlip, + [ViewOrientationHorizontal] = ViewPortOrientationHorizontal, + [ViewOrientationHorizontalFlip] = ViewPortOrientationHorizontalFlip, +}; + void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* view) { furi_assert(view_dispatcher); // Dispatch view exit event @@ -330,15 +337,12 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie view_dispatcher->current_view = view; // Dispatch view enter event if(view_dispatcher->current_view) { - if(view->orientation == ViewOrientationVertical) { - view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationVertical); - } else if(view->orientation == ViewOrientationVerticalFlip) { - view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationVerticalFlip); - } else if(view->orientation == ViewOrientationHorizontal) { - view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationHorizontal); - } else if(view->orientation == ViewOrientationHorizontalFlip) { - view_port_set_orientation( - view_dispatcher->view_port, ViewPortOrientationHorizontalFlip); + ViewPortOrientation orientation = + view_dispatcher_view_port_orientation_table[view->orientation]; + if(view_port_get_orientation(view_dispatcher->view_port) != orientation) { + view_port_set_orientation(view_dispatcher->view_port, orientation); + // we just rotated input keys, now it's time to sacrifice some input + view_dispatcher->ongoing_input = 0; } view_enter(view_dispatcher->current_view); view_port_enabled_set(view_dispatcher->view_port, true); diff --git a/applications/services/gui/view_port.c b/applications/services/gui/view_port.c index 5760ed57..8c2ff6fe 100644 --- a/applications/services/gui/view_port.c +++ b/applications/services/gui/view_port.c @@ -1,6 +1,8 @@ #include "view_port_i.h" #include +#include +#include #include "gui.h" #include "gui_i.h" @@ -48,27 +50,45 @@ static const InputKey view_port_input_mapping[ViewPortOrientationMAX][InputKeyMA InputKeyBack}, //ViewPortOrientationVerticalFlip }; +static const InputKey view_port_left_hand_input_mapping[InputKeyMAX] = + {InputKeyDown, InputKeyUp, InputKeyLeft, InputKeyRight, InputKeyOk, InputKeyBack}; + +static const CanvasOrientation view_port_orientation_mapping[ViewPortOrientationMAX] = { + [ViewPortOrientationHorizontal] = CanvasOrientationHorizontal, + [ViewPortOrientationHorizontalFlip] = CanvasOrientationHorizontalFlip, + [ViewPortOrientationVertical] = CanvasOrientationVertical, + [ViewPortOrientationVerticalFlip] = CanvasOrientationVerticalFlip, +}; + // Remaps directional pad buttons on Flipper based on ViewPort orientation static void view_port_map_input(InputEvent* event, ViewPortOrientation orientation) { furi_assert(orientation < ViewPortOrientationMAX && event->key < InputKeyMAX); + + if(event->sequence_source != INPUT_SEQUENCE_SOURCE_HARDWARE) { + return; + } + + if(orientation == ViewPortOrientationHorizontal || + orientation == ViewPortOrientationHorizontalFlip) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) { + event->key = view_port_left_hand_input_mapping[event->key]; + } + } event->key = view_port_input_mapping[orientation][event->key]; } static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { - switch(view_port->orientation) { - case ViewPortOrientationHorizontalFlip: - canvas_set_orientation(canvas, CanvasOrientationHorizontalFlip); - break; - case ViewPortOrientationVertical: - canvas_set_orientation(canvas, CanvasOrientationVertical); - break; - case ViewPortOrientationVerticalFlip: - canvas_set_orientation(canvas, CanvasOrientationVerticalFlip); - break; - default: - canvas_set_orientation(canvas, CanvasOrientationHorizontal); - break; - }; + CanvasOrientation orientation = view_port_orientation_mapping[view_port->orientation]; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) { + if(orientation == CanvasOrientationHorizontal) { + orientation = CanvasOrientationHorizontalFlip; + } else if(orientation == CanvasOrientationHorizontalFlip) { + orientation = CanvasOrientationHorizontal; + } + } + + canvas_set_orientation(canvas, orientation); } ViewPort* view_port_alloc() { diff --git a/applications/services/input/input.c b/applications/services/input/input.c index e1e581c9..8da0a340 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -23,7 +23,8 @@ inline static void input_timer_stop(FuriTimer* timer_id) { void input_press_timer_callback(void* arg) { InputPinState* input_pin = arg; InputEvent event; - event.sequence = input_pin->counter; + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; + event.sequence_counter = input_pin->counter; event.key = input_pin->pin->key; input_pin->press_counter++; if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { @@ -114,16 +115,17 @@ int32_t input_srv(void* p) { // Common state info InputEvent event; + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; event.key = input->pin_states[i].pin->key; // Short / Long / Repeat timer routine if(state) { input->counter++; input->pin_states[i].counter = input->counter; - event.sequence = input->pin_states[i].counter; + event.sequence_counter = input->pin_states[i].counter; input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); } else { - event.sequence = input->pin_states[i].counter; + event.sequence_counter = input->pin_states[i].counter; input_timer_stop(input->pin_states[i].press_timer); if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { event.type = InputTypeShort; diff --git a/applications/services/input/input.h b/applications/services/input/input.h index 062dc0fa..a62e8456 100644 --- a/applications/services/input/input.h +++ b/applications/services/input/input.h @@ -12,6 +12,8 @@ extern "C" { #endif #define RECORD_INPUT_EVENTS "input_events" +#define INPUT_SEQUENCE_SOURCE_HARDWARE (0u) +#define INPUT_SEQUENCE_SOURCE_SOFTWARE (1u) /** Input Types * Some of them are physical events and some logical @@ -27,7 +29,13 @@ typedef enum { /** Input Event, dispatches with FuriPubSub */ typedef struct { - uint32_t sequence; + union { + uint32_t sequence; + struct { + uint8_t sequence_source : 2; + uint32_t sequence_counter : 30; + }; + }; InputKey key; InputType type; } InputEvent; diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index e66553d5..c2af425e 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -12,6 +12,8 @@ typedef enum { #define RpcGuiWorkerFlagAny (RpcGuiWorkerFlagTransmit | RpcGuiWorkerFlagExit) +#define RPC_GUI_INPUT_RESET (0u) + typedef struct { RpcSession* session; Gui* gui; @@ -26,6 +28,9 @@ typedef struct { bool virtual_display_not_empty; bool is_streaming; + + uint32_t input_key_counter[InputKeyMAX]; + uint32_t input_counter; } RpcGuiSystem; static void @@ -194,6 +199,22 @@ static void return; } + // Event sequence shenanigans + event.sequence_source = INPUT_SEQUENCE_SOURCE_SOFTWARE; + if(event.type == InputTypePress) { + rpc_gui->input_counter++; + if(rpc_gui->input_counter == RPC_GUI_INPUT_RESET) rpc_gui->input_counter++; + rpc_gui->input_key_counter[event.key] = rpc_gui->input_counter; + } + if(rpc_gui->input_key_counter[event.key] == RPC_GUI_INPUT_RESET) { + FURI_LOG_W(TAG, "Out of sequence input event: key %d, type %d,", event.key, event.type); + } + event.sequence_counter = rpc_gui->input_key_counter[event.key]; + if(event.type == InputTypeRelease) { + rpc_gui->input_key_counter[event.key] = RPC_GUI_INPUT_RESET; + } + + // Submit event FuriPubSub* input_events = furi_record_open(RECORD_INPUT_EVENTS); furi_check(input_events); furi_pubsub_publish(input_events, &event); diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 5eade211..cb74d7a8 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -124,6 +124,23 @@ static void date_format_changed(VariableItem* item) { locale_set_date_format(date_format_value[index]); } +const char* const hand_mode[] = { + "Righty", + "Lefty", +}; + +static void hand_orient_changed(VariableItem* item) { + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, hand_mode[index]); + if(index) { + furi_hal_rtc_set_flag(FuriHalRtcFlagHandOrient); + } else { + furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); + } + + loader_update_menu(); +} + static uint32_t system_settings_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -145,6 +162,12 @@ SystemSettings* system_settings_alloc() { uint8_t value_index; app->var_item_list = variable_item_list_alloc(); + item = variable_item_list_add( + app->var_item_list, "Hand Orient", COUNT_OF(hand_mode), hand_orient_changed, app); + value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient) ? 1 : 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, hand_mode[value_index]); + item = variable_item_list_add( app->var_item_list, "Units", diff --git a/firmware/targets/furi_hal_include/furi_hal_rtc.h b/firmware/targets/furi_hal_include/furi_hal_rtc.h index fe095e74..b16b04a6 100644 --- a/firmware/targets/furi_hal_include/furi_hal_rtc.h +++ b/firmware/targets/furi_hal_include/furi_hal_rtc.h @@ -29,6 +29,7 @@ typedef enum { FuriHalRtcFlagFactoryReset = (1 << 1), FuriHalRtcFlagLock = (1 << 2), FuriHalRtcFlagC2Update = (1 << 3), + FuriHalRtcFlagHandOrient = (1 << 4), } FuriHalRtcFlag; typedef enum { From 5b05aeea827c7740184bfcbe47e03eef6e3858f8 Mon Sep 17 00:00:00 2001 From: Leo Smith <19672114+p4p1@users.noreply.github.com> Date: Thu, 9 Mar 2023 18:42:34 +0100 Subject: [PATCH 22/23] [#1989] updated parser and added stringln, hold and release (#2448) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updated parser and added stringln, hold and release * removed unused code as requested from PR * BadUsb: tiny change to trigger rebuild Co-authored-by: p4p1 Co-authored-by: あく --- applications/main/bad_usb/bad_usb_script.c | 287 ++++-------------- applications/main/bad_usb/bad_usb_script.h | 27 +- applications/main/bad_usb/mnemonic.c | 327 +++++++++++++++++++++ applications/main/bad_usb/mnemonic.h | 96 ++++++ 4 files changed, 512 insertions(+), 225 deletions(-) create mode 100644 applications/main/bad_usb/mnemonic.c create mode 100644 applications/main/bad_usb/mnemonic.h diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index beb35b89..12abc766 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -6,11 +6,11 @@ #include #include #include "bad_usb_script.h" +#include "mnemonic.h" #include #define TAG "BadUSB" #define WORKER_TAG TAG "Worker" -#define FILE_BUFFER_LEN 16 #define SCRIPT_STATE_ERROR (-1) #define SCRIPT_STATE_END (-2) @@ -26,24 +26,6 @@ typedef enum { WorkerEvtDisconnect = (1 << 3), } WorkerEvtFlags; -struct BadUsbScript { - FuriHalUsbHidConfig hid_cfg; - BadUsbState st; - FuriString* file_path; - uint32_t defdelay; - uint16_t layout[128]; - uint32_t stringdelay; - FuriThread* thread; - uint8_t file_buf[FILE_BUFFER_LEN + 1]; - uint8_t buf_start; - uint8_t buf_len; - bool file_end; - FuriString* line; - - FuriString* line_prev; - uint32_t repeat_cnt; -}; - typedef struct { char* name; uint16_t keycode; @@ -112,40 +94,21 @@ static const char ducky_cmd_comment[] = {"REM"}; static const char ducky_cmd_id[] = {"ID"}; static const char ducky_cmd_delay[] = {"DELAY "}; static const char ducky_cmd_string[] = {"STRING "}; +static const char ducky_cmd_stringln[] = {"STRINGLN "}; static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; static const char ducky_cmd_stringdelay_1[] = {"STRINGDELAY "}; static const char ducky_cmd_stringdelay_2[] = {"STRING_DELAY "}; static const char ducky_cmd_repeat[] = {"REPEAT "}; static const char ducky_cmd_sysrq[] = {"SYSRQ "}; +static const char ducky_cmd_hold[] = {"HOLD "}; +static const char ducky_cmd_release[] = {"RELEASE "}; static const char ducky_cmd_altchar[] = {"ALTCHAR "}; static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; -static const uint8_t numpad_keys[10] = { - HID_KEYPAD_0, - HID_KEYPAD_1, - HID_KEYPAD_2, - HID_KEYPAD_3, - HID_KEYPAD_4, - HID_KEYPAD_5, - HID_KEYPAD_6, - HID_KEYPAD_7, - HID_KEYPAD_8, - HID_KEYPAD_9, -}; - -static bool ducky_get_number(const char* param, uint32_t* val) { - uint32_t value = 0; - if(sscanf(param, "%lu", &value) == 1) { - *val = value; - return true; - } - return false; -} - -static uint32_t ducky_get_command_len(const char* line) { +uint32_t ducky_get_command_len(const char* line) { uint32_t len = strlen(line); for(uint32_t i = 0; i < len; i++) { if(line[i] == ' ') return i; @@ -153,84 +116,11 @@ static uint32_t ducky_get_command_len(const char* line) { return 0; } -static bool ducky_is_line_end(const char chr) { +bool ducky_is_line_end(const char chr) { return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); } -static void ducky_numlock_on() { - if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { - furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); - furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); - } -} - -static bool ducky_numpad_press(const char num) { - if((num < '0') || (num > '9')) return false; - - uint16_t key = numpad_keys[num - '0']; - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); - - return true; -} - -static bool ducky_altchar(const char* charcode) { - uint8_t i = 0; - bool state = false; - - FURI_LOG_I(WORKER_TAG, "char %s", charcode); - - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); - - while(!ducky_is_line_end(charcode[i])) { - state = ducky_numpad_press(charcode[i]); - if(state == false) break; - i++; - } - - furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); - return state; -} - -static bool ducky_altstring(const char* param) { - uint32_t i = 0; - bool state = false; - - while(param[i] != '\0') { - if((param[i] < ' ') || (param[i] > '~')) { - i++; - continue; // Skip non-printable chars - } - - char temp_str[4]; - snprintf(temp_str, 4, "%u", param[i]); - - state = ducky_altchar(temp_str); - if(state == false) break; - i++; - } - return state; -} - -static bool ducky_string(BadUsbScript* bad_usb, const char* param) { - uint32_t i = 0; - - while(param[i] != '\0') { - uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); - if(keycode != HID_KEYBOARD_NONE) { - furi_hal_hid_kb_press(keycode); - furi_hal_hid_kb_release(keycode); - if(bad_usb->stringdelay > 0) { - furi_delay_ms(bad_usb->stringdelay); - } - } - i++; - } - bad_usb->stringdelay = 0; - return true; -} - -static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { +uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { size_t key_cmd_len = strlen(ducky_keys[i].name); if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && @@ -248,119 +138,68 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { uint32_t line_len = furi_string_size(line); const char* line_tmp = furi_string_get_cstr(line); - bool state = false; + const char* ducky_cmd_table[] = { + ducky_cmd_comment, + ducky_cmd_id, + ducky_cmd_delay, + ducky_cmd_string, + ducky_cmd_defdelay_1, + ducky_cmd_defdelay_2, + ducky_cmd_stringdelay_1, + ducky_cmd_stringdelay_2, + ducky_cmd_repeat, + ducky_cmd_sysrq, + ducky_cmd_altchar, + ducky_cmd_altstr_1, + ducky_cmd_altstr_2, + ducky_cmd_stringln, + ducky_cmd_hold, + ducky_cmd_release, + NULL}; + int32_t (*fnc_ptr[])(BadUsbScript*, FuriString*, const char*, char*, size_t) = { + &ducky_fnc_noop, + &ducky_fnc_noop, + &ducky_fnc_delay, + &ducky_fnc_string, + &ducky_fnc_defdelay, + &ducky_fnc_defdelay, + &ducky_fnc_strdelay, + &ducky_fnc_strdelay, + &ducky_fnc_repeat, + &ducky_fnc_sysrq, + &ducky_fnc_altchar, + &ducky_fnc_altstring, + &ducky_fnc_altstring, + &ducky_fnc_stringln, + &ducky_fnc_hold, + &ducky_fnc_release, + NULL}; if(line_len == 0) { return SCRIPT_STATE_NEXT_LINE; // Skip empty lines } - FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); - - // General commands - if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) { - // REM - comment line - return (0); - } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { - // ID - executed in ducky_script_preload - return (0); - } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) { - // DELAY - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint32_t delay_val = 0; - state = ducky_get_number(line_tmp, &delay_val); - if((state) && (delay_val > 0)) { - return (int32_t)delay_val; - } - if(error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) { - // DEFAULT_DELAY - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->defdelay); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_stringdelay_1, strlen(ducky_cmd_stringdelay_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_stringdelay_2, strlen(ducky_cmd_stringdelay_2)) == 0)) { - //STRINGDELAY, finally it's here - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->stringdelay); - if((state) && (bad_usb->stringdelay > 0)) { - return state; - } - if(error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - - } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { - // STRING - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_string(bad_usb, line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid string %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { - // ALTCHAR - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - ducky_numlock_on(); - state = ducky_altchar(line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid altchar %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) { - // ALTSTRING - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - ducky_numlock_on(); - state = ducky_altstring(line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid altstring %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { - // REPEAT - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { - // SYSRQ - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release_all(); - return (0); - } else { - // Special keys + modifiers - uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); - if(key == HID_KEYBOARD_NONE) { - if(error != NULL) { - snprintf(error, error_len, "No keycode defined for %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - } - if((key & 0xFF00) != 0) { - // It's a modifier key - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - key |= ducky_get_keycode(bad_usb, line_tmp, true); - } - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); - return (0); + // Ducky Lang Functions + for(size_t i = 0; ducky_cmd_table[i]; i++) { + if(strncmp(line_tmp, ducky_cmd_table[i], strlen(ducky_cmd_table[i])) == 0) + return ((fnc_ptr[i])(bad_usb, line, line_tmp, error, error_len)); } + // Special keys + modifiers + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); + if(key == HID_KEYBOARD_NONE) { + if(error != NULL) { + snprintf(error, error_len, "No keycode defined for %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } + if((key & 0xFF00) != 0) { + // It's a modifier key + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + key |= ducky_get_keycode(bad_usb, line_tmp, true); + } + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release(key); + return (0); } static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { diff --git a/applications/main/bad_usb/bad_usb_script.h b/applications/main/bad_usb/bad_usb_script.h index 1e4d98fe..fef2deae 100644 --- a/applications/main/bad_usb/bad_usb_script.h +++ b/applications/main/bad_usb/bad_usb_script.h @@ -5,8 +5,9 @@ extern "C" { #endif #include +#include -typedef struct BadUsbScript BadUsbScript; +#define FILE_BUFFER_LEN 16 typedef enum { BadUsbStateInit, @@ -29,6 +30,24 @@ typedef struct { char error[64]; } BadUsbState; +typedef struct BadUsbScript { + FuriHalUsbHidConfig hid_cfg; + BadUsbState st; + FuriString* file_path; + uint32_t defdelay; + uint16_t layout[128]; + uint32_t stringdelay; + FuriThread* thread; + uint8_t file_buf[FILE_BUFFER_LEN + 1]; + uint8_t buf_start; + uint8_t buf_len; + bool file_end; + FuriString* line; + + FuriString* line_prev; + uint32_t repeat_cnt; +} BadUsbScript; + BadUsbScript* bad_usb_script_open(FuriString* file_path); void bad_usb_script_close(BadUsbScript* bad_usb); @@ -43,6 +62,12 @@ void bad_usb_script_toggle(BadUsbScript* bad_usb); BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); +uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars); + +uint32_t ducky_get_command_len(const char* line); + +bool ducky_is_line_end(const char chr); + #ifdef __cplusplus } #endif diff --git a/applications/main/bad_usb/mnemonic.c b/applications/main/bad_usb/mnemonic.c new file mode 100644 index 00000000..f21cc98b --- /dev/null +++ b/applications/main/bad_usb/mnemonic.c @@ -0,0 +1,327 @@ +#include +#include +#include "mnemonic.h" + +#define TAG "BadUSB" +#define WORKER_TAG TAG "Worker" + +#define FILE_BUFFER_LEN 16 +#define SCRIPT_STATE_ERROR (-1) +#define SCRIPT_STATE_END (-2) +#define SCRIPT_STATE_NEXT_LINE (-3) + +#define BADUSB_ASCII_TO_KEY(script, x) \ + (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) + +static const uint8_t numpad_keys[10] = { + HID_KEYPAD_0, + HID_KEYPAD_1, + HID_KEYPAD_2, + HID_KEYPAD_3, + HID_KEYPAD_4, + HID_KEYPAD_5, + HID_KEYPAD_6, + HID_KEYPAD_7, + HID_KEYPAD_8, + HID_KEYPAD_9, +}; + +static bool ducky_get_number(const char* param, uint32_t* val) { + uint32_t value = 0; + if(sscanf(param, "%lu", &value) == 1) { + *val = value; + return true; + } + return false; +} + +static void ducky_numlock_on() { + if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { + furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); + furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); + } +} +static bool ducky_numpad_press(const char num) { + if((num < '0') || (num > '9')) return false; + + uint16_t key = numpad_keys[num - '0']; + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release(key); + + return true; +} + +static bool ducky_altchar(const char* charcode) { + uint8_t i = 0; + bool state = false; + + FURI_LOG_I(WORKER_TAG, "char %s", charcode); + + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); + + while(!ducky_is_line_end(charcode[i])) { + state = ducky_numpad_press(charcode[i]); + if(state == false) break; + i++; + } + + furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); + return state; +} + +static bool ducky_altstring(const char* param) { + uint32_t i = 0; + bool state = false; + + while(param[i] != '\0') { + if((param[i] < ' ') || (param[i] > '~')) { + i++; + continue; // Skip non-printable chars + } + + char temp_str[4]; + snprintf(temp_str, 4, "%u", param[i]); + + state = ducky_altchar(temp_str); + if(state == false) break; + i++; + } + return state; +} + +static bool ducky_string(BadUsbScript* bad_usb, const char* param) { + uint32_t i = 0; + + while(param[i] != '\0') { + uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); + if(keycode != HID_KEYBOARD_NONE) { + furi_hal_hid_kb_press(keycode); + furi_hal_hid_kb_release(keycode); + if(bad_usb->stringdelay > 0) { + furi_delay_ms(bad_usb->stringdelay); + } + } + i++; + } + bad_usb->stringdelay = 0; + return true; +} + +int32_t ducky_fnc_noop( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + (void)bad_usb; + (void)line; + (void)line_tmp; + (void)error; + (void)error_len; + return (0); +} + +int32_t ducky_fnc_delay( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)bad_usb; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint32_t delay_val = 0; + state = ducky_get_number(line_tmp, &delay_val); + if((state) && (delay_val > 0)) { + return (int32_t)delay_val; + } + if(error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_defdelay( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_usb->defdelay); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_strdelay( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_usb->stringdelay); + if((state) && (bad_usb->stringdelay > 0)) { + return state; + } + if(error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_string( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_string(bad_usb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid string %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_repeat( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_sysrq( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + (void)error; + (void)error_len; + (void)line; + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release_all(); + return (0); +} + +int32_t ducky_fnc_altchar( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)bad_usb; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + ducky_numlock_on(); + state = ducky_altchar(line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid altchar %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_altstring( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)bad_usb; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + ducky_numlock_on(); + state = ducky_altstring(line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid altstring %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_stringln( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + bool state = false; + (void)line; + + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_string(bad_usb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid string %s", line_tmp); + } + furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); + furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); + return (state) ? (0) : SCRIPT_STATE_ERROR; +} + +int32_t ducky_fnc_hold( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + (void)line; + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); + if(key == HID_KEYBOARD_NONE) { + if(error != NULL) { + snprintf(error, error_len, "No keycode defined for %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } + furi_hal_hid_kb_press(key); + return (0); +} + +int32_t ducky_fnc_release( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len) { + (void)line; + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); + if(key == HID_KEYBOARD_NONE) { + if(error != NULL) { + snprintf(error, error_len, "No keycode defined for %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } + furi_hal_hid_kb_release(key); + return (0); +} diff --git a/applications/main/bad_usb/mnemonic.h b/applications/main/bad_usb/mnemonic.h new file mode 100644 index 00000000..a85627c3 --- /dev/null +++ b/applications/main/bad_usb/mnemonic.h @@ -0,0 +1,96 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bad_usb_script.h" + +// A no opperation function +int32_t ducky_fnc_noop( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// DELAY +int32_t ducky_fnc_delay( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// DEFAULTDELAY +int32_t ducky_fnc_defdelay( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// STRINGDELAY +int32_t ducky_fnc_strdelay( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// STRING +int32_t ducky_fnc_string( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// STRINGLN +int32_t ducky_fnc_stringln( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// REPEAT +int32_t ducky_fnc_repeat( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// SYSRQ +int32_t ducky_fnc_sysrq( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// ALTCHAR +int32_t ducky_fnc_altchar( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// ALTSTRING +int32_t ducky_fnc_altstring( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// HOLD +int32_t ducky_fnc_hold( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); +// RELEASE +int32_t ducky_fnc_release( + BadUsbScript* bad_usb, + FuriString* line, + const char* line_tmp, + char* error, + size_t error_len); + +#ifdef __cplusplus +} +#endif From 0190a161ba1cb292b894dce66fff15dcb1ed08c4 Mon Sep 17 00:00:00 2001 From: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Date: Thu, 9 Mar 2023 20:50:25 +0300 Subject: [PATCH 23/23] NFC: Fix 0 block write possibility in Mifare Classic emulation (#2474) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/nfc/protocols/mifare_classic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index a8a90889..71242871 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -291,6 +291,10 @@ bool mf_classic_is_allowed_access_data_block( uint8_t* sector_trailer = data->block[mf_classic_get_sector_trailer_num_by_block(block_num)].value; + if(block_num == 0 && action == MfClassicActionDataWrite) { + return false; + } + uint8_t sector_block; if(block_num <= 128) { sector_block = block_num & 0x03;