From a959fa32bc65620460d2bcfd593a12ddcf55def3 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 10 Nov 2022 15:55:11 +0400 Subject: [PATCH 1/7] fbt: 'target' field for apps; lib debugging support (#1995) * fbt: added 'target' field to application manifest * fbt: earlier pagination setup for gdb * fbt: added LIB_DEBUG flag * fbt: sdk: added SDK_MAP_FILE_SUBST --- SConstruct | 9 +++------ documentation/AppManifests.md | 1 + firmware.scons | 4 ++-- scripts/fbt/appmanifest.py | 20 +++++++++++++++++--- scripts/fbt/util.py | 7 ++++++- scripts/fbt_tools/fbt_apps.py | 13 +++++++------ scripts/fbt_tools/fbt_debugopts.py | 4 ++-- scripts/fbt_tools/fbt_sdk.py | 22 ++++++++++++++-------- site_scons/commandline.scons | 5 +++++ site_scons/extapps.scons | 10 +++++++++- 10 files changed, 66 insertions(+), 29 deletions(-) diff --git a/SConstruct b/SConstruct index 3ee89f646..34ff80bc9 100644 --- a/SConstruct +++ b/SConstruct @@ -7,6 +7,7 @@ # construction of certain targets behind command-line options. import os +from fbt.util import path_as_posix DefaultEnvironment(tools=[]) @@ -200,9 +201,7 @@ firmware_debug = distenv.PhonyTarget( source=firmware_env["FW_ELF"], GDBOPTS="${GDBOPTS_BASE}", GDBREMOTE="${OPENOCD_GDB_PIPE}", - FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace( - "\\", "/" - ), + FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")), ) distenv.Depends(firmware_debug, firmware_flash) @@ -212,9 +211,7 @@ distenv.PhonyTarget( source=firmware_env["FW_ELF"], GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", GDBREMOTE="${BLACKMAGIC_ADDR}", - FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace( - "\\", "/" - ), + FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")), ) # Debug alien elf diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index f4814ee5d..d70a12f9c 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -40,6 +40,7 @@ Only 2 parameters are mandatory: ***appid*** and ***apptype***, others are optio * **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware. * **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.* * **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications. +* **targets**: list of strings, target names, which this application is compatible with. If not specified, application is built for all targets. Default value is `["all"]`. #### Parameters for external applications diff --git a/firmware.scons b/firmware.scons index 6a9237477..da5caba53 100644 --- a/firmware.scons +++ b/firmware.scons @@ -40,11 +40,11 @@ env = ENV.Clone( FW_LIB_OPTS={ "Default": { "CCFLAGS": [ - "-Os", + "-Og" if ENV["LIB_DEBUG"] else "-Os", ], "CPPDEFINES": [ "NDEBUG", - "FURI_NDEBUG", + "FURI_DEBUG" if ENV["LIB_DEBUG"] else "FURI_NDEBUG", ], # You can add other entries named after libraries # If they are present, they have precedence over Default diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index de7c6b682..908a64a6f 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -52,6 +52,8 @@ class FlipperApplication: icon: Optional[str] = None order: int = 0 sdk_headers: List[str] = field(default_factory=list) + targets: List[str] = field(default_factory=lambda: ["all"]) + # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) fap_version: Tuple[int] = field(default_factory=lambda: (0, 1)) @@ -135,8 +137,8 @@ class AppManager: raise FlipperManifestException(f"Duplicate app declaration: {app.appid}") self.known_apps[app.appid] = app - def filter_apps(self, applist: List[str]): - return AppBuildset(self, applist) + def filter_apps(self, applist: List[str], hw_target: str): + return AppBuildset(self, applist, hw_target) class AppBuilderException(Exception): @@ -155,11 +157,13 @@ class AppBuildset: FlipperAppType.STARTUP, ) - def __init__(self, appmgr: AppManager, appnames: List[str]): + def __init__(self, appmgr: AppManager, appnames: List[str], hw_target: str): self.appmgr = appmgr self.appnames = set(appnames) + self.hw_target = hw_target self._orig_appnames = appnames self._process_deps() + self._filter_by_target() self._check_conflicts() self._check_unsatisfied() # unneeded? self.apps = sorted( @@ -170,6 +174,16 @@ class AppBuildset: def _is_missing_dep(self, dep_name: str): return dep_name not in self.appnames + def _filter_by_target(self): + for appname in self.appnames.copy(): + app = self.appmgr.get(appname) + # if app.apptype not in self.BUILTIN_APP_TYPES: + if not any(map(lambda t: t in app.targets, ["all", self.hw_target])): + print( + f"Removing {appname} due to target mismatch (building for {self.hw_target}, app supports {app.targets}" + ) + self.appnames.remove(appname) + def _process_deps(self): while True: provided = [] diff --git a/scripts/fbt/util.py b/scripts/fbt/util.py index b8e9c5928..ee7562058 100644 --- a/scripts/fbt/util.py +++ b/scripts/fbt/util.py @@ -1,7 +1,6 @@ import SCons from SCons.Subst import quote_spaces from SCons.Errors import StopError -from SCons.Node.FS import _my_normcase import re import os @@ -58,3 +57,9 @@ def extract_abs_dir_path(node): raise StopError(f"Can't find absolute path for {node.name}") return abs_dir_node.abspath + + +def path_as_posix(path): + if SCons.Platform.platform_default() == "win32": + return path.replace(os.path.sep, os.path.altsep) + return path diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index 55e282017..96528f4e5 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,7 +1,6 @@ from SCons.Builder import Builder from SCons.Action import Action from SCons.Warnings import warn, WarningOnByDefault -import SCons from ansi.color import fg from fbt.appmanifest import ( @@ -33,14 +32,12 @@ def LoadAppManifest(env, entry): def PrepareApplicationsBuild(env): - appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) + appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps( + env["APPS"], env.subst("f${TARGET_HW}") + ) env.Append( SDK_HEADERS=appbuild.get_sdk_headers(), ) - env["APPBUILD_DUMP"] = env.Action( - DumpApplicationConfig, - "\tINFO\t", - ) def DumpApplicationConfig(target, source, env): @@ -68,6 +65,10 @@ def generate(env): env.AddMethod(PrepareApplicationsBuild) env.SetDefault( APPMGR=AppManager(), + APPBUILD_DUMP=env.Action( + DumpApplicationConfig, + "\tINFO\t", + ), ) env.Append( diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index c3be5ca47..9ff05cb73 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -41,12 +41,12 @@ def generate(env, **kw): "|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}" ], GDBOPTS_BASE=[ + "-ex", + "set pagination off", "-ex", "target extended-remote ${GDBREMOTE}", "-ex", "set confirm off", - "-ex", - "set pagination off", ], GDBOPTS_BLACKMAGIC=[ "-ex", diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index c46346b65..3a37eacc9 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -14,6 +14,7 @@ import json from fbt.sdk.collector import SdkCollector from fbt.sdk.cache import SdkCache +from fbt.util import path_as_posix def ProcessSdkDepends(env, filename): @@ -52,6 +53,8 @@ def prebuild_sdk_create_origin_file(target, source, env): class SdkMeta: + MAP_FILE_SUBST = "SDK_MAP_FILE_SUBST" + def __init__(self, env, tree_builder: "SdkTreeBuilder"): self.env = env self.treebuilder = tree_builder @@ -67,6 +70,7 @@ class SdkMeta: "linker_libs": self.env.subst("${LIBS}"), "app_ep_subst": self.env.subst("${APP_ENTRY}"), "sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"), + "map_file_subst": self.MAP_FILE_SUBST, "hardware": self.env.subst("${TARGET_HW}"), } with open(json_manifest_path, "wt") as f: @@ -75,9 +79,9 @@ class SdkMeta: def _wrap_scons_vars(self, vars: str): expanded_vars = self.env.subst( vars, - target=Entry("dummy"), + target=Entry(self.MAP_FILE_SUBST), ) - return expanded_vars.replace("\\", "/") + return path_as_posix(expanded_vars) class SdkTreeBuilder: @@ -142,13 +146,15 @@ class SdkTreeBuilder: meta.save_to(self.target[0].path) def build_sdk_file_path(self, orig_path: str) -> str: - return posixpath.normpath( - posixpath.join( - self.SDK_DIR_SUBST, - self.target_sdk_dir_name, - orig_path, + return path_as_posix( + posixpath.normpath( + posixpath.join( + self.SDK_DIR_SUBST, + self.target_sdk_dir_name, + orig_path, + ) ) - ).replace("\\", "/") + ) def emitter(self, target, source, env): target_folder = target[0] diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 044de6b30..6087c1c7a 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -63,6 +63,11 @@ vars.AddVariables( help="Enable debug build", default=True, ), + BoolVariable( + "LIB_DEBUG", + help="Enable debug build for libraries", + default=False, + ), BoolVariable( "COMPACT", help="Optimize for size", diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 670d71fd0..b8f210563 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -1,6 +1,6 @@ from dataclasses import dataclass, field -from SCons.Errors import UserError from SCons.Node import NodeList +from SCons.Warnings import warn, WarningOnByDefault Import("ENV") @@ -80,6 +80,14 @@ if extra_app_list := GetOption("extra_ext_apps"): known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(","))) for app in known_extapps: + if not any(map(lambda t: t in app.targets, ["all", appenv.subst("f${TARGET_HW}")])): + warn( + WarningOnByDefault, + f"Can't build '{app.name}' (id '{app.appid}'): target mismatch" + f" (building for {appenv.subst('f${TARGET_HW}')}, app supports {app.targets}", + ) + continue + appenv.BuildAppElf(app) From f94e8f4ac8978118489f1086fa2c979995f71964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 10 Nov 2022 22:56:08 +0900 Subject: [PATCH 2/7] Rpc: increase stack size, fix stack overflow (#1997) --- applications/services/rpc/rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 73eaadfb1..f1e0cbd66 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -372,7 +372,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { session->thread = furi_thread_alloc(); furi_thread_set_name(session->thread, "RpcSessionWorker"); - furi_thread_set_stack_size(session->thread, 2048); + furi_thread_set_stack_size(session->thread, 3072); furi_thread_set_context(session->thread, session); furi_thread_set_callback(session->thread, rpc_session_worker); From a66e8d9ac98d1845714f28d60e3c63f2584ef0b9 Mon Sep 17 00:00:00 2001 From: Rom1 Date: Thu, 10 Nov 2022 16:21:28 +0100 Subject: [PATCH 3/7] corr: bad path for furi core (#1975) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * corr: bad path for furi core * Documentation: exclude submodules * Documentation: wider folder list Co-authored-by: Sergey Gavrilov Co-authored-by: あく --- documentation/.gitignore | 2 ++ documentation/Doxyfile | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 documentation/.gitignore diff --git a/documentation/.gitignore b/documentation/.gitignore new file mode 100644 index 000000000..c18ff03bb --- /dev/null +++ b/documentation/.gitignore @@ -0,0 +1,2 @@ +/html +/latex \ No newline at end of file diff --git a/documentation/Doxyfile b/documentation/Doxyfile index 6d6bb8aa8..1824e5a52 100644 --- a/documentation/Doxyfile +++ b/documentation/Doxyfile @@ -872,12 +872,9 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = applications \ - core \ - lib/infrared \ - lib/subghz \ - lib/toolbox \ - lib/onewire \ - firmware/targets/furi_hal_include + lib \ + firmware \ + furi # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -930,7 +927,18 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = \ + lib/mlib \ + lib/STM32CubeWB \ + lib/littlefs \ + lib/nanopb \ + assets/protobuf \ + lib/libusb_stm32 \ + lib/FreeRTOS-Kernel \ + lib/microtar \ + lib/mbedtls \ + lib/cxxheaderparser \ + applications/plugins/dap_link/lib/free-dap # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded From 820afd2aec377629c3e514ceb57ecdd0f9163b6c Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 10 Nov 2022 18:20:35 +0200 Subject: [PATCH 4/7] NFC Unit tests part 1.1 (#1927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Mifare Classic 1/4K, 4/7b uid, NFC-A: NFC-A is not complete yet, as there are no 4b uid tests. Also, Mifare Classic tests don't cover the key cache yet. * NFC unit tests require access to the NFC app * Made nfc_device_save accept full path as an argument * Move from cstrs to furi strings and fix logic * nfc tests: fix memory leak * nfc: add mf_classic_get_total_blocks() to API * nfc tests: simplify nfc tests * nfc: fix memory leak in shadow file saving * nfc: fix set uid scene * nfc: fix saving files * nfc: fix preload nfc file path * nfc: remove comments Co-authored-by: Sergey Gavrilov Co-authored-by: gornekich Co-authored-by: あく --- applications/debug/unit_tests/nfc/nfc_test.c | 197 ++++++++++++++++++ .../main/nfc/helpers/nfc_generators.c | 7 +- .../main/nfc/helpers/nfc_generators.h | 2 + applications/main/nfc/nfc.c | 11 +- applications/main/nfc/nfc_i.h | 2 + .../main/nfc/scenes/nfc_scene_file_select.c | 3 + .../nfc/scenes/nfc_scene_mf_classic_emulate.c | 5 +- .../nfc/scenes/nfc_scene_mf_classic_update.c | 2 +- .../scenes/nfc_scene_mf_ultralight_emulate.c | 5 +- .../main/nfc/scenes/nfc_scene_save_name.c | 2 +- .../main/nfc/scenes/nfc_scene_set_uid.c | 3 +- fbt_options.py | 1 + firmware/targets/f7/api_symbols.csv | 3 +- lib/nfc/nfc_device.c | 44 ++-- lib/nfc/protocols/mifare_classic.c | 2 +- lib/nfc/protocols/mifare_classic.h | 2 + 16 files changed, 256 insertions(+), 35 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 8009f6a17..454c11c0f 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -17,6 +19,7 @@ #define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" #define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" #define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") +#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc") static const char* nfc_test_file_type = "Flipper NFC test"; static const uint32_t nfc_test_file_version = 1; @@ -287,9 +290,203 @@ MU_TEST(mf_classic_dict_load_test) { furi_record_close(RECORD_STORAGE); } +MU_TEST(nfca_file_test) { + NfcDevice* nfc = nfc_device_alloc(); + mu_assert(nfc != NULL, "nfc_device_data != NULL assert failed\r\n"); + nfc->format = NfcDeviceSaveFormatUid; + + // Fill the UID, sak, ATQA and type + uint8_t uid[7] = {0x04, 0x01, 0x23, 0x45, 0x67, 0x89, 0x00}; + memcpy(nfc->dev_data.nfc_data.uid, uid, 7); + nfc->dev_data.nfc_data.uid_len = 7; + + nfc->dev_data.nfc_data.sak = 0x08; + nfc->dev_data.nfc_data.atqa[0] = 0x00; + nfc->dev_data.nfc_data.atqa[1] = 0x04; + nfc->dev_data.nfc_data.type = FuriHalNfcTypeA; + + // Save the NFC device data to the file + mu_assert( + nfc_device_save(nfc, NFC_TEST_NFC_DEV_PATH), "nfc_device_save == true assert failed\r\n"); + nfc_device_free(nfc); + + // Load the NFC device data from the file + NfcDevice* nfc_validate = nfc_device_alloc(); + mu_assert( + nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, true), + "nfc_device_load == true assert failed\r\n"); + + // Check the UID, sak, ATQA and type + mu_assert(memcmp(nfc_validate->dev_data.nfc_data.uid, uid, 7) == 0, "uid assert failed\r\n"); + mu_assert(nfc_validate->dev_data.nfc_data.sak == 0x08, "sak == 0x08 assert failed\r\n"); + mu_assert( + nfc_validate->dev_data.nfc_data.atqa[0] == 0x00, "atqa[0] == 0x00 assert failed\r\n"); + mu_assert( + nfc_validate->dev_data.nfc_data.atqa[1] == 0x04, "atqa[1] == 0x04 assert failed\r\n"); + mu_assert( + nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, + "type == FuriHalNfcTypeA assert failed\r\n"); + nfc_device_free(nfc_validate); +} + +static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { + NfcDevice* nfc_dev = nfc_device_alloc(); + mu_assert(nfc_dev != NULL, "nfc_device_data != NULL assert failed\r\n"); + nfc_dev->format = NfcDeviceSaveFormatMifareClassic; + + // Create a test file + nfc_generate_mf_classic(&nfc_dev->dev_data, uid_len, type); + + // Get the uid from generated MFC + uint8_t uid[7] = {0}; + memcpy(uid, nfc_dev->dev_data.nfc_data.uid, uid_len); + uint8_t sak = nfc_dev->dev_data.nfc_data.sak; + uint8_t atqa[2] = {}; + memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2); + + MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data; + // Check the manufacturer block (should be uid[uid_len] + 0xFF[rest]) + uint8_t manufacturer_block[16] = {0}; + memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16); + mu_assert( + memcmp(manufacturer_block, uid, uid_len) == 0, + "manufacturer_block uid doesn't match the file\r\n"); + for(uint8_t i = uid_len; i < 16; i++) { + mu_assert( + manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n"); + } + + // Reference sector trailers (should be 0xFF[6] + 0xFF + 0x07 + 0x80 + 0x69 + 0xFF[6]) + uint8_t sector_trailer[16] = { + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x07, + 0x80, + 0x69, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF}; + // Reference block data + uint8_t block_data[16] = {}; + memset(block_data, 0xff, sizeof(block_data)); + uint16_t total_blocks = mf_classic_get_total_block_num(type); + for(size_t i = 1; i < total_blocks; i++) { + if(mf_classic_is_sector_trailer(i)) { + mu_assert( + memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, + "Failed sector trailer compare"); + } else { + mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); + } + } + // Save the NFC device data to the file + mu_assert( + nfc_device_save(nfc_dev, NFC_TEST_NFC_DEV_PATH), + "nfc_device_save == true assert failed\r\n"); + // Verify that key cache is saved + FuriString* key_cache_name = furi_string_alloc(); + furi_string_set_str(key_cache_name, "/ext/nfc/cache/"); + for(size_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(key_cache_name, "%02X", uid[i]); + } + furi_string_cat_printf(key_cache_name, ".keys"); + mu_assert( + storage_common_stat(nfc_dev->storage, furi_string_get_cstr(key_cache_name), NULL) == + FSE_OK, + "Key cache file save failed"); + nfc_device_free(nfc_dev); + + // Load the NFC device data from the file + NfcDevice* nfc_validate = nfc_device_alloc(); + mu_assert(nfc_validate, "Nfc device alloc assert"); + mu_assert( + nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, false), + "nfc_device_load == true assert failed\r\n"); + + // Check the UID, sak, ATQA and type + mu_assert( + memcmp(nfc_validate->dev_data.nfc_data.uid, uid, uid_len) == 0, + "uid compare assert failed\r\n"); + mu_assert(nfc_validate->dev_data.nfc_data.sak == sak, "sak compare assert failed\r\n"); + mu_assert( + memcmp(nfc_validate->dev_data.nfc_data.atqa, atqa, 2) == 0, + "atqa compare assert failed\r\n"); + mu_assert( + nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, + "type == FuriHalNfcTypeA assert failed\r\n"); + + // Check the manufacturer block + mu_assert( + memcmp(nfc_validate->dev_data.mf_classic_data.block[0].value, manufacturer_block, 16) == 0, + "manufacturer_block assert failed\r\n"); + // Check other blocks + for(size_t i = 1; i < total_blocks; i++) { + if(mf_classic_is_sector_trailer(i)) { + mu_assert( + memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, + "Failed sector trailer compare"); + } else { + mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); + } + } + nfc_device_free(nfc_validate); + + // Check saved key cache + NfcDevice* nfc_keys = nfc_device_alloc(); + mu_assert(nfc_validate, "Nfc device alloc assert"); + nfc_keys->dev_data.nfc_data.uid_len = uid_len; + memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len); + mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache"); + uint8_t total_sec = mf_classic_get_total_sectors_num(type); + uint8_t default_key[6] = {}; + memset(default_key, 0xff, 6); + for(size_t i = 0; i < total_sec; i++) { + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); + mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare"); + mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare"); + } + + // Delete key cache file + mu_assert( + storage_common_remove(nfc_keys->storage, furi_string_get_cstr(key_cache_name)) == FSE_OK, + "Failed to remove key cache file"); + furi_string_free(key_cache_name); + nfc_device_free(nfc_keys); +} + +MU_TEST(mf_classic_1k_4b_file_test) { + mf_classic_generator_test(4, MfClassicType1k); +} + +MU_TEST(mf_classic_4k_4b_file_test) { + mf_classic_generator_test(4, MfClassicType4k); +} + +MU_TEST(mf_classic_1k_7b_file_test) { + mf_classic_generator_test(7, MfClassicType1k); +} + +MU_TEST(mf_classic_4k_7b_file_test) { + mf_classic_generator_test(7, MfClassicType4k); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); + MU_RUN_TEST(nfca_file_test); + MU_RUN_TEST(mf_classic_1k_4b_file_test); + MU_RUN_TEST(mf_classic_4k_4b_file_test); + MU_RUN_TEST(mf_classic_1k_7b_file_test); + MU_RUN_TEST(mf_classic_4k_7b_file_test); MU_RUN_TEST(nfc_digital_signal_test); MU_RUN_TEST(mf_classic_dict_test); MU_RUN_TEST(mf_classic_dict_load_test); diff --git a/applications/main/nfc/helpers/nfc_generators.c b/applications/main/nfc/helpers/nfc_generators.c index 11083b9f0..5f0527c6a 100644 --- a/applications/main/nfc/helpers/nfc_generators.c +++ b/applications/main/nfc/helpers/nfc_generators.c @@ -314,7 +314,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { mful->version.storage_size = 0x15; } -static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { +void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { nfc_generate_common_start(data); nfc_generate_mf_classic_common(data, uid_len, type); @@ -337,6 +337,9 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas } mf_classic_set_block_read(mfc, i, &mfc->block[i]); } + // Set SAK to 18 + data->nfc_data.sak = 0x18; + } else if(type == MfClassicType1k) { // Set every block to 0xFF for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) { @@ -347,6 +350,8 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas } mf_classic_set_block_read(mfc, i, &mfc->block[i]); } + // Set SAK to 08 + data->nfc_data.sak = 0x08; } mfc->type = type; diff --git a/applications/main/nfc/helpers/nfc_generators.h b/applications/main/nfc/helpers/nfc_generators.h index 10a05591b..362a19b1e 100644 --- a/applications/main/nfc/helpers/nfc_generators.h +++ b/applications/main/nfc/helpers/nfc_generators.h @@ -11,3 +11,5 @@ struct NfcGenerator { }; extern const NfcGenerator* const nfc_generators[]; + +void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type); diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index 55c68a450..0dd071bc4 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -116,7 +116,9 @@ void nfc_free(Nfc* nfc) { // Stop worker nfc_worker_stop(nfc->worker); // Save data in shadow file - nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } } if(nfc->rpc_ctx) { rpc_system_app_send_exited(nfc->rpc_ctx); @@ -218,6 +220,13 @@ void nfc_blink_stop(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_stop); } +bool nfc_save_file(Nfc* nfc) { + furi_string_printf( + nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); + bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + return file_saved; +} + void nfc_show_loading_popup(void* context, bool show) { Nfc* nfc = context; TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); diff --git a/applications/main/nfc/nfc_i.h b/applications/main/nfc/nfc_i.h index e9b36a3e9..57eefbf67 100644 --- a/applications/main/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_i.h @@ -114,4 +114,6 @@ void nfc_blink_detect_start(Nfc* nfc); void nfc_blink_stop(Nfc* nfc); +bool nfc_save_file(Nfc* nfc); + void nfc_show_loading_popup(void* context, bool show); diff --git a/applications/main/nfc/scenes/nfc_scene_file_select.c b/applications/main/nfc/scenes/nfc_scene_file_select.c index 693fdec20..374a933d1 100644 --- a/applications/main/nfc/scenes/nfc_scene_file_select.c +++ b/applications/main/nfc/scenes/nfc_scene_file_select.c @@ -5,6 +5,9 @@ void nfc_scene_file_select_on_enter(void* context) { Nfc* nfc = context; // Process file_select return nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); + if(!furi_string_size(nfc->dev->load_path)) { + furi_string_set_str(nfc->dev->load_path, NFC_APP_FOLDER); + } if(nfc_file_select(nfc->dev)) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c index e514fa728..68eda7040 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -48,7 +48,10 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even NFC_MF_CLASSIC_DATA_CHANGED) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED); - nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); + // Save shadow file + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } } consumed = false; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c index dd3a6f7d5..aacf77f77 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c @@ -57,7 +57,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventSuccess) { nfc_worker_stop(nfc->worker); - if(nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name)) { + if(nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path))) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index e84fb3927..adcadaaf2 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -48,7 +48,10 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e NFC_MF_UL_DATA_CHANGED) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED); - nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); + // Save shadow file + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } } consumed = false; } diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c index 791f8d99b..ca4b1a350 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -62,7 +62,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; } strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); - if(nfc_device_save(nfc->dev, nfc->text_store)) { + if(nfc_save_file(nfc)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { // Nothing, do not count editing as saving diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c index 1d3fb5eb9..5f0f52f6e 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -31,7 +31,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { if(event.event == NfcCustomEventByteInputDone) { if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; - if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) { + if(nfc_save_file(nfc)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); consumed = true; } @@ -41,6 +41,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { } } } + return consumed; } diff --git a/fbt_options.py b/fbt_options.py index 11124b936..a00f7c1b6 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -81,6 +81,7 @@ FIRMWARE_APPS = { "basic_services", "updater_app", "unit_tests", + "nfc", ], } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 0c10258f7..d6e522a2b 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,+,7.3,, +Version,+,7.4,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1844,6 +1844,7 @@ Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" +Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType Function,-,mf_classic_get_type_str,const char*,MfClassicType Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index a5e3fc14f..9f17aed3a 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -1006,12 +1006,7 @@ static void nfc_device_get_shadow_path(FuriString* orig_path, FuriString* shadow furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION); } -static bool nfc_device_save_file( - NfcDevice* dev, - const char* dev_name, - const char* folder, - const char* extension, - bool use_load_path) { +bool nfc_device_save(NfcDevice* dev, const char* dev_name) { furi_assert(dev); bool saved = false; @@ -1021,19 +1016,10 @@ static bool nfc_device_save_file( temp_str = furi_string_alloc(); do { - 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 nfc 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 nfc directory if necessary - if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break; - // First remove nfc device file if it was saved - furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); - } + // Create nfc directory if necessary + if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break; + // First remove nfc device file if it was saved + furi_string_printf(temp_str, "%s", dev_name); // Open file if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break; // Write header @@ -1072,13 +1058,19 @@ static bool nfc_device_save_file( return saved; } -bool nfc_device_save(NfcDevice* dev, const char* dev_name) { - return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_EXTENSION, true); -} - -bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { +bool nfc_device_save_shadow(NfcDevice* dev, const char* path) { dev->shadow_file_exist = true; - return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION, true); + // Replace extension from .nfc to .shd if necessary + FuriString* orig_path = furi_string_alloc(); + furi_string_set_str(orig_path, path); + FuriString* shadow_path = furi_string_alloc(); + nfc_device_get_shadow_path(orig_path, shadow_path); + + bool file_saved = nfc_device_save(dev, furi_string_get_cstr(shadow_path)); + furi_string_free(orig_path); + furi_string_free(shadow_path); + + return file_saved; } static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) { @@ -1195,7 +1187,7 @@ bool nfc_file_select(NfcDevice* dev) { }; bool res = - dialog_file_browser_show(dev->dialogs, dev->load_path, nfc_app_folder, &browser_options); + dialog_file_browser_show(dev->dialogs, dev->load_path, dev->load_path, &browser_options); furi_string_free(nfc_app_folder); if(res) { diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 7b0e17975..b7a52bc01 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -82,7 +82,7 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { } } -static uint16_t mf_classic_get_total_block_num(MfClassicType type) { +uint16_t mf_classic_get_total_block_num(MfClassicType type) { if(type == MfClassicType1k) { return 64; } else if(type == MfClassicType4k) { diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index d5467b100..9a0bb5790 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -98,6 +98,8 @@ MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t S uint8_t mf_classic_get_total_sectors_num(MfClassicType type); +uint16_t mf_classic_get_total_block_num(MfClassicType type); + uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); bool mf_classic_is_sector_trailer(uint8_t block); From e7c4b40dbe14f71275639ac9ba9a712c17a5e566 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 10 Nov 2022 18:29:57 +0200 Subject: [PATCH 5/7] Force card types in extra actions (#1961) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Mifare Classic forced read * Add all the needed card types * nfc: remove unused scene * nfc: remove unused worker state * nfc: fix read card type scene state usage * nfc: move NfcReadMode to NfcDevData struct * nfc: fix bank card reading and scene navigation * nfc magic: fix magic deactifate function Co-authored-by: gornekich Co-authored-by: あく --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_exit_confirm.c | 9 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 13 +++ .../nfc/scenes/nfc_scene_read_card_type.c | 97 +++++++++++++++++++ .../main/nfc/scenes/nfc_scene_start.c | 2 + .../plugins/nfc_magic/lib/magic/magic.c | 2 +- .../plugins/nfc_magic/nfc_magic_worker.c | 1 - lib/nfc/nfc_device.h | 10 ++ lib/nfc/nfc_worker.c | 81 +++++++++++++++- lib/nfc/nfc_worker_i.h | 2 + 10 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_read_card_type.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 9b922add2..49c8412c5 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -60,3 +60,4 @@ ADD_SCENE(nfc, detect_reader, DetectReader) ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) +ADD_SCENE(nfc, read_card_type, ReadCardType) diff --git a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c index b22dd42a1..3ce4f6de8 100644 --- a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c @@ -29,8 +29,13 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { if(event.event == DialogExResultRight) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneReadCardType)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneReadCardType); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } } } else if(event.type == SceneManagerEventTypeBack) { consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index e888e9d35..fc6021d73 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -1,6 +1,7 @@ #include "../nfc_i.h" enum SubmenuIndex { + SubmenuIndexReadCardType, SubmenuIndexMfClassicKeys, SubmenuIndexMfUltralightUnlock, }; @@ -15,6 +16,12 @@ void nfc_scene_extra_actions_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; + submenu_add_item( + submenu, + "Read Specific Card Type", + SubmenuIndexReadCardType, + nfc_scene_extra_actions_submenu_callback, + nfc); submenu_add_item( submenu, "Mifare Classic Keys", @@ -44,9 +51,15 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + consumed = true; + } else if(event.event == SubmenuIndexReadCardType) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); + consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } + return consumed; } diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c new file mode 100644 index 000000000..94262aa1e --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -0,0 +1,97 @@ +#include "../nfc_i.h" +#include "nfc_worker_i.h" + +enum SubmenuIndex { + SubmenuIndexReadMifareClassic, + SubmenuIndexReadMifareDesfire, + SubmenuIndexReadMfUltralight, + SubmenuIndexReadEMV, + SubmenuIndexReadNFCA, +}; + +void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_read_card_type_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, + "Read Mifare Classic", + SubmenuIndexReadMifareClassic, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read Mifare DESFire", + SubmenuIndexReadMifareDesfire, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read NTAG/Ultralight", + SubmenuIndexReadMfUltralight, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read EMV card", + SubmenuIndexReadEMV, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read NFC-A data", + SubmenuIndexReadNFCA, + nfc_scene_read_card_type_submenu_callback, + nfc); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType); + submenu_set_selected_item(submenu, state); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexReadMifareClassic) { + nfc->dev->dev_data.read_mode = NfcReadModeMfClassic; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadMifareDesfire) { + nfc->dev->dev_data.read_mode = NfcReadModeMfDesfire; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadMfUltralight) { + nfc->dev->dev_data.read_mode = NfcReadModeMfUltralight; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadEMV) { + nfc->dev->dev_data.read_mode = NfcReadModeEMV; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadNFCA) { + nfc->dev->dev_data.read_mode = NfcReadModeNFCA; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event); + } + return consumed; +} + +void nfc_scene_read_card_type_on_exit(void* context) { + Nfc* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 028f85ae0..f8b9f52c6 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include "nfc_worker_i.h" #include enum SubmenuIndex { @@ -47,6 +48,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { + nfc->dev->dev_data.read_mode = NfcReadModeAuto; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; diff --git a/applications/plugins/nfc_magic/lib/magic/magic.c b/applications/plugins/nfc_magic/lib/magic/magic.c index 3cfca748b..a922bc7a8 100644 --- a/applications/plugins/nfc_magic/lib/magic/magic.c +++ b/applications/plugins/nfc_magic/lib/magic/magic.c @@ -210,5 +210,5 @@ bool magic_wipe() { void magic_deactivate() { furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); + furi_hal_nfc_sleep(); } diff --git a/applications/plugins/nfc_magic/nfc_magic_worker.c b/applications/plugins/nfc_magic/nfc_magic_worker.c index 0623211e2..0e1f6cea4 100644 --- a/applications/plugins/nfc_magic/nfc_magic_worker.c +++ b/applications/plugins/nfc_magic/nfc_magic_worker.c @@ -167,7 +167,6 @@ void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) { if(!magic_data_access_cmd()) continue; if(!magic_write_blk(0, &block)) continue; nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - magic_deactivate(); break; } magic_deactivate(); diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index c8e8517ae..3d302c18b 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -51,9 +51,19 @@ typedef struct { MfClassicDict* dict; } NfcMfClassicDictAttackData; +typedef enum { + NfcReadModeAuto, + NfcReadModeMfClassic, + NfcReadModeMfUltralight, + NfcReadModeMfDesfire, + NfcReadModeEMV, + NfcReadModeNFCA, +} NfcReadMode; + typedef struct { FuriHalNfcDevData nfc_data; NfcProtocol protocol; + NfcReadMode read_mode; union { NfcReaderRequestData reader_data; NfcMfClassicDictAttackData mf_classic_dict_attack_data; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 5ce543636..5ad37c6e3 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -90,7 +90,11 @@ int32_t nfc_worker_task(void* context) { furi_hal_nfc_exit_sleep(); if(nfc_worker->state == NfcWorkerStateRead) { - nfc_worker_read(nfc_worker); + if(nfc_worker->dev_data->read_mode == NfcReadModeAuto) { + nfc_worker_read(nfc_worker); + } else { + nfc_worker_read_type(nfc_worker); + } } else if(nfc_worker->state == NfcWorkerStateUidEmulate) { nfc_worker_emulate_uid(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { @@ -394,6 +398,81 @@ void nfc_worker_read(NfcWorker* nfc_worker) { } } +void nfc_worker_read_type(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + furi_assert(nfc_worker->callback); + + NfcReadMode read_mode = nfc_worker->dev_data->read_mode; + nfc_device_data_clear(nfc_worker->dev_data); + NfcDeviceData* dev_data = nfc_worker->dev_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + FuriHalNfcTxRxContext tx_rx = {}; + NfcWorkerEvent event = 0; + bool card_not_detected_notified = false; + + while(nfc_worker->state == NfcWorkerStateRead) { + if(furi_hal_nfc_detect(nfc_data, 300)) { + FURI_LOG_D(TAG, "Card detected"); + furi_hal_nfc_sleep(); + // Process first found device + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + card_not_detected_notified = false; + if(nfc_data->type == FuriHalNfcTypeA) { + if(read_mode == NfcReadModeMfClassic) { + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; + nfc_worker->dev_data->mf_classic_data.type = mf_classic_get_classic_type( + nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + if(nfc_worker_read_mf_classic(nfc_worker, &tx_rx)) { + FURI_LOG_D(TAG, "Card read"); + dev_data->protocol = NfcDeviceProtocolMifareClassic; + event = NfcWorkerEventReadMfClassicDone; + break; + } else { + FURI_LOG_D(TAG, "Card read failed"); + dev_data->protocol = NfcDeviceProtocolMifareClassic; + event = NfcWorkerEventReadMfClassicDictAttackRequired; + break; + } + } else if(read_mode == NfcReadModeMfUltralight) { + FURI_LOG_I(TAG, "Mifare Ultralight / NTAG"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl; + if(nfc_worker_read_mf_ultralight(nfc_worker, &tx_rx)) { + event = NfcWorkerEventReadMfUltralight; + break; + } + } else if(read_mode == NfcReadModeMfDesfire) { + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareDesfire; + if(nfc_worker_read_mf_desfire(nfc_worker, &tx_rx)) { + event = NfcWorkerEventReadMfDesfire; + break; + } + } else if(read_mode == NfcReadModeEMV) { + nfc_worker->dev_data->protocol = NfcDeviceProtocolEMV; + if(nfc_worker_read_bank_card(nfc_worker, &tx_rx)) { + event = NfcWorkerEventReadBankCard; + break; + } + } else if(read_mode == NfcReadModeNFCA) { + nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + event = NfcWorkerEventReadUidNfcA; + break; + } + } else { + if(!card_not_detected_notified) { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + card_not_detected_notified = true; + } + } + } + furi_hal_nfc_sleep(); + furi_delay_ms(100); + } + // Notify caller and exit + if(event > NfcWorkerEventReserved) { + nfc_worker->callback(event, nfc_worker->context); + } +} + void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index b9f69e620..9733426ab 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -35,6 +35,8 @@ int32_t nfc_worker_task(void* context); void nfc_worker_read(NfcWorker* nfc_worker); +void nfc_worker_read_type(NfcWorker* nfc_worker); + void nfc_worker_emulate_uid(NfcWorker* nfc_worker); void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker); From aec36e7041a24af68d04d57b024726d909d29c82 Mon Sep 17 00:00:00 2001 From: lauaall <48836917+skelq@users.noreply.github.com> Date: Thu, 10 Nov 2022 18:48:58 +0200 Subject: [PATCH 6/7] Fixed typos (#1999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sergey Gavrilov Co-authored-by: あく --- documentation/KeyCombo.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/documentation/KeyCombo.md b/documentation/KeyCombo.md index 359fd5b9b..e6f55dc52 100644 --- a/documentation/KeyCombo.md +++ b/documentation/KeyCombo.md @@ -1,7 +1,7 @@ # Key Combos -There are times when your flipper feels blue and don't respond to your commands. -In that case you may find this guide useful. +There are times when your flipper feels blue and doesn't respond to your commands. +In that case, you may find this guide useful. ## Basic Combos @@ -9,7 +9,7 @@ In that case you may find this guide useful. ### Hardware Reset -- Press `LEFT` and `BACK` and hold for couple seconds +- Press `LEFT` and `BACK` and hold for a couple of seconds - Release `LEFT` and `BACK` This combo performs hardware reset by pulling MCU reset line down. @@ -29,7 +29,7 @@ There is 1 case when it's not working: - If you have not disconnected USB, then disconnect USB and repeat previous step - Release `BACK` key -This combo performs reset by switching SYS power line off and then on. +This combo performs a reset by switching SYS power line off and then on. Main components involved: Keys -> DD6(bq25896, charger) There is 1 case when it's not working: @@ -60,13 +60,13 @@ There is 1 case when it's not working: ### Hardware Reset + Software DFU -- Press `LEFT` and `BACK` and hold for couple seconds +- Press `LEFT` and `BACK` and hold for a couple of seconds - Release `BACK` - Device will enter DFU with indication (Blue LED + DFU Screen) - Release `LEFT` This combo performs hardware reset by pulling MCU reset line down. -Then `LEFT` key indicates to boot-loader that DFU mode requested. +Then `LEFT` key indicates to boot-loader that DFU mode is requested. There are 2 cases when it's not working: @@ -76,7 +76,7 @@ There are 2 cases when it's not working: ### Hardware Reset + Hardware DFU -- Press `LEFT` and `BACK` and `OK` and hold for couple seconds +- Press `LEFT` and `BACK` and `OK` and hold for a couple of seconds - Release `BACK` and `LEFT` - Device will enter DFU without indication @@ -127,8 +127,8 @@ There are 2 cases when it's not working: If none of the described methods were useful: -- Ensure battery charged -- Disconnect battery and connect again (Requires disassembly) -- Try to Flash device with ST-Link or other programmer that support SWD +- Ensure the battery charged +- Disconnect the battery and connect again (Requires disassembly) +- Try to Flash device with ST-Link or other programmer that supports SWD -If you still here and your device is not working: it's not software issue. +If you still here and your device is not working: it's not a software issue. From 721ab717d784859f7076175d22991b6d950c361e Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 10 Nov 2022 21:14:44 +0400 Subject: [PATCH 7/7] [FL-2961] SubGhz: properly handle storage loss (#1990) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../subghz/scenes/subghz_scene_more_raw.c | 38 +++++++++++++------ .../subghz/scenes/subghz_scene_read_raw.c | 38 ++++++++++++++----- applications/main/subghz/subghz_i.c | 17 +++++++++ applications/main/subghz/subghz_i.h | 1 + 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_more_raw.c b/applications/main/subghz/scenes/subghz_scene_more_raw.c index d75ab13c7..864be1ed1 100644 --- a/applications/main/subghz/scenes/subghz_scene_more_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_more_raw.c @@ -38,18 +38,34 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexDelete) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); - return true; + if(subghz_file_available(subghz)) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); + return true; + } else { + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } + } } else if(event.event == SubmenuIndexEdit) { - furi_string_reset(subghz->file_path_tmp); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); - return true; + if(subghz_file_available(subghz)) { + furi_string_reset(subghz->file_path_tmp); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + return true; + } else { + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } + } } } return false; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index ba9ce803b..2e5ba0966 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -198,20 +198,28 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWMore: - if(subghz_scene_read_raw_update_filename(subghz)) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); - consumed = true; + if(subghz_file_available(subghz)) { + if(subghz_scene_read_raw_update_filename(subghz)) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); + subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); + consumed = true; + } else { + furi_crash("SubGhz: RAW file name update error."); + } } else { - furi_crash("SubGhz: RAW file name update error."); + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } } break; case SubGhzCustomEventViewReadRAWSendStart: - if(subghz_scene_read_raw_update_filename(subghz)) { + if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { @@ -238,6 +246,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->state_notifications = SubGhzNotificationStateTx; } } + } else { + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } } consumed = true; break; @@ -314,11 +328,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWSave: - if(subghz_scene_read_raw_update_filename(subghz)) { + if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW); subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + } else { + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } } consumed = true; break; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index a887b6543..d9070ba8c 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -490,6 +490,23 @@ bool subghz_rename_file(SubGhz* subghz) { return ret; } +bool subghz_file_available(SubGhz* subghz) { + furi_assert(subghz); + bool ret = true; + Storage* storage = furi_record_open(RECORD_STORAGE); + + FS_Error fs_result = + storage_common_stat(storage, furi_string_get_cstr(subghz->file_path), NULL); + + if(fs_result != FSE_OK) { + dialog_message_show_storage_error(subghz->dialogs, "File not available\n file/directory"); + ret = false; + } + + furi_record_close(RECORD_STORAGE); + return ret; +} + bool subghz_delete_file(SubGhz* subghz) { furi_assert(subghz); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 46768cf02..0a40196bb 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -124,6 +124,7 @@ bool subghz_save_protocol_to_file( const char* dev_file_name); bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); +bool subghz_file_available(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(FuriString* path);