Explorar o código

NFC Magic update to 1.5

Methodius %!s(int64=2) %!d(string=hai) anos
pai
achega
71d601ad4b

+ 3 - 3
application.fam

@@ -1,6 +1,6 @@
 App(
     appid="nfc_magic",
-    name="NFC Magic",
+    name="Nfc Magic",
     apptype=FlipperAppType.EXTERNAL,
     targets=["f7"],
     entry_point="nfc_magic_app",
@@ -10,8 +10,8 @@ App(
     ],
     stack_size=4 * 1024,
     fap_description="Application for writing to NFC tags with modifiable sector 0",
-    fap_version="1.4",
-    fap_icon="assets/Nfc_10px.png",
+    fap_version="1.5",
+    fap_icon="assets/125_10px.png",
     fap_category="NFC",
     fap_private_libs=[
         Lib(

+ 24 - 0
lib/magic/protocols/gen4/gen4_poller.c

@@ -1,5 +1,7 @@
+#include "core/check.h"
 #include "core/log.h"
 #include "gen4_poller_i.h"
+#include "protocols/gen4/gen4_poller.h"
 #include <nfc/protocols/iso14443_3a/iso14443_3a.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 #include <nfc/helpers/nfc_util.h>
@@ -177,6 +179,8 @@ NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) {
         instance->state = Gen4PollerStateGetCurrentConfig;
     } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetRevision) {
         instance->state = Gen4PollerStateGetRevision;
+    } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetShadowMode) {
+        instance->state = Gen4PollerStateSetShadowMode;
     } else {
         instance->state = Gen4PollerStateFail;
     }
@@ -534,6 +538,25 @@ NfcCommand gen4_poller_get_revision_handler(Gen4Poller* instance) {
     return command;
 }
 
+NfcCommand gen4_poller_set_shadow_mode_handler(Gen4Poller* instance) {
+    NfcCommand command = NfcCommandContinue;
+
+    do {
+        Gen4PollerError error =
+            gen4_poller_set_shadow_mode(instance, instance->password, instance->shadow_mode);
+
+        if(error != Gen4PollerErrorNone) {
+            FURI_LOG_E(TAG, "Failed to set shadow mode: %d", error);
+            instance->state = Gen4PollerStateFail;
+            break;
+        }
+
+        instance->state = Gen4PollerStateSuccess;
+    } while(false);
+
+    return command;
+}
+
 NfcCommand gen4_poller_success_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
 
@@ -568,6 +591,7 @@ static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNu
     [Gen4PollerStateSetDefaultConfig] = gen4_poller_set_default_cfg_handler,
     [Gen4PollerStateGetCurrentConfig] = gen4_poller_get_current_cfg_handler,
     [Gen4PollerStateGetRevision] = gen4_poller_get_revision_handler,
+    [Gen4PollerStateSetShadowMode] = gen4_poller_set_shadow_mode_handler,
     [Gen4PollerStateSuccess] = gen4_poller_success_handler,
     [Gen4PollerStateFail] = gen4_poller_fail_handler,
 

+ 1 - 0
lib/magic/protocols/gen4/gen4_poller.h

@@ -41,6 +41,7 @@ typedef enum {
     Gen4PollerModeSetDefaultCFG,
     Gen4PollerModeGetCFG,
     Gen4PollerModeGetRevision,
+    Gen4PollerModeSetShadowMode,
 } Gen4PollerMode;
 
 typedef struct {

+ 39 - 1
lib/magic/protocols/gen4/gen4_poller_i.c

@@ -4,9 +4,11 @@
 #include "core/log.h"
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 #include <nfc/helpers/nfc_util.h>
+#include <stdint.h>
 
 #define GEN4_CMD_PREFIX (0xCF)
 
+#define GEN4_CMD_SET_SHD_MODE (0x32)
 #define GEN4_CMD_GET_CFG (0xC6)
 #define GEN4_CMD_GET_REVISION (0xCC)
 #define GEN4_CMD_WRITE (0xCD)
@@ -17,6 +19,7 @@
 
 #define CONFIG_SIZE (32)
 #define REVISION_SIZE (5)
+#define SHD_MODE_RESPONSE_SIZE (2)
 
 static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
     Gen4PollerError ret = Gen4PollerErrorNone;
@@ -30,6 +33,41 @@ static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
     return ret;
 }
 
+Gen4PollerError
+    gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, uint8_t mode) {
+    Gen4PollerError ret = Gen4PollerErrorNone;
+    bit_buffer_reset(instance->tx_buffer);
+
+    do {
+        uint8_t password_arr[4] = {};
+        nfc_util_num2bytes(password, COUNT_OF(password_arr), password_arr);
+        bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
+        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_SHD_MODE);
+        bit_buffer_append_byte(instance->tx_buffer, mode);
+
+        Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
+            instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
+
+        if(error != Iso14443_3aErrorNone) {
+            ret = gen4_poller_process_error(error);
+            break;
+        }
+
+        size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
+        if(rx_bytes != SHD_MODE_RESPONSE_SIZE) {
+            ret = Gen4PollerErrorProtocol;
+            break;
+        }
+        uint16_t response = bit_buffer_get_size_bytes(instance->rx_buffer);
+
+        FURI_LOG_D(TAG, "Card response: %X, Shadow mode set: %u", response, mode);
+
+    } while(false);
+
+    return ret;
+}
+
 Gen4PollerError
     gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result) {
     Gen4PollerError ret = Gen4PollerErrorNone;
@@ -83,7 +121,7 @@ Gen4PollerError
         }
 
         size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
-        if(rx_bytes != 5) {
+        if(rx_bytes != REVISION_SIZE) {
             ret = Gen4PollerErrorProtocol;
             break;
         }

+ 6 - 0
lib/magic/protocols/gen4/gen4_poller_i.h

@@ -3,6 +3,7 @@
 #include "gen4_poller.h"
 #include <nfc/nfc_poller.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
+#include <stdint.h>
 
 #define TAG "Gen4Poller"
 
@@ -53,6 +54,7 @@ typedef enum {
     Gen4PollerStateSetDefaultConfig,
     Gen4PollerStateGetCurrentConfig,
     Gen4PollerStateGetRevision,
+    Gen4PollerStateSetShadowMode,
 
     Gen4PollerStateSuccess,
     Gen4PollerStateFail,
@@ -78,6 +80,8 @@ struct Gen4Poller {
 
     uint8_t config[GEN4_POLLER_CONFIG_SIZE_MAX];
 
+    uint8_t shadow_mode;
+
     Gen4PollerEvent gen4_event;
     Gen4PollerEventData gen4_event_data;
 
@@ -107,6 +111,8 @@ Gen4PollerError
 Gen4PollerError
     gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result);
 
+Gen4PollerError gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, uint8_t mode);
+
 #ifdef __cplusplus
 }
 #endif

+ 5 - 3
scenes/nfc_magic_scene_config.h

@@ -5,11 +5,13 @@ ADD_SCENE(nfc_magic, magic_info, MagicInfo)
 ADD_SCENE(nfc_magic, gen1_menu, Gen1Menu)
 ADD_SCENE(nfc_magic, gen4_menu, Gen4Menu)
 ADD_SCENE(nfc_magic, gen4_actions_menu, Gen4ActionsMenu)
-ADD_SCENE(nfc_magic, gen4_get_cfg, Gen4GetCFG)
-ADD_SCENE(nfc_magic, gen4_set_cfg, Gen4SetCFG)
+ADD_SCENE(nfc_magic, gen4_get_cfg, Gen4GetCfg)
+ADD_SCENE(nfc_magic, gen4_set_cfg, Gen4SetCfg)
 ADD_SCENE(nfc_magic, gen4_revision, Gen4Revision)
 ADD_SCENE(nfc_magic, gen4_show_rev, Gen4ShowRev)
-ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCFG)
+ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCfg)
+ADD_SCENE(nfc_magic, gen4_select_shd_mode, Gen4SelectShdMode)
+ADD_SCENE(nfc_magic, gen4_set_shd_mode, Gen4SetShdMode)
 ADD_SCENE(nfc_magic, gen4_fail, Gen4Fail)
 ADD_SCENE(nfc_magic, wipe, Wipe)
 ADD_SCENE(nfc_magic, wipe_fail, WipeFail)

+ 2 - 24
scenes/nfc_magic_scene_gen4_actions_menu.c

@@ -1,11 +1,8 @@
 #include "../nfc_magic_app_i.h"
-#include "furi_hal_rtc.h"
 
 enum SubmenuIndex {
     SubmenuIndexAuthenticate,
     SubmenuIndexSetStandartConfig,
-    SubmenuIndexGetConfig,
-    SubmenuIndexGetRevision
 };
 
 void nfc_magic_scene_gen4_actions_menu_submenu_callback(void* context, uint32_t index) {
@@ -24,26 +21,12 @@ void nfc_magic_scene_gen4_actions_menu_on_enter(void* context) {
         SubmenuIndexAuthenticate,
         nfc_magic_scene_gen4_actions_menu_submenu_callback,
         instance);
-    submenu_add_item(
-        submenu,
-        "Get Revision",
-        SubmenuIndexGetRevision,
-        nfc_magic_scene_gen4_actions_menu_submenu_callback,
-        instance);
     submenu_add_item(
         submenu,
         "Set Standart Config",
         SubmenuIndexSetStandartConfig,
         nfc_magic_scene_gen4_actions_menu_submenu_callback,
         instance);
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        submenu_add_item(
-            submenu,
-            "Get Config",
-            SubmenuIndexGetConfig,
-            nfc_magic_scene_gen4_actions_menu_submenu_callback,
-            instance);
-    }
 
     submenu_set_selected_item(
         submenu,
@@ -60,15 +43,10 @@ bool nfc_magic_scene_gen4_actions_menu_on_event(void* context, SceneManagerEvent
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneKeyInput);
             consumed = true;
         } else if(event.event == SubmenuIndexSetStandartConfig) {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetCFG);
-            consumed = true;
-        } else if(event.event == SubmenuIndexGetConfig) {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4GetCFG);
-            consumed = true;
-        } else if(event.event == SubmenuIndexGetRevision) {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Revision);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetCfg);
             consumed = true;
         }
+
         scene_manager_set_scene_state(
             instance->scene_manager, NfcMagicSceneGen4ActionsMenu, event.event);
     } else if(event.type == SceneManagerEventTypeBack) {

+ 6 - 6
scenes/nfc_magic_scene_gen4_get_cfg.c

@@ -39,7 +39,7 @@ static void nfc_magic_scene_gen4_get_cfg_setup_view(NfcMagicApp* instance) {
     Popup* popup = instance->popup;
     popup_reset(popup);
     uint32_t state =
-        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4GetCFG);
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4GetCfg);
 
     if(state == NfcMagicSceneGen4GetCFGStateCardSearch) {
         popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
@@ -57,7 +57,7 @@ void nfc_magic_scene_gen4_get_cfg_on_enter(void* context) {
     NfcMagicApp* instance = context;
 
     scene_manager_set_scene_state(
-        instance->scene_manager, NfcMagicSceneGen4GetCFG, NfcMagicSceneGen4GetCFGStateCardSearch);
+        instance->scene_manager, NfcMagicSceneGen4GetCfg, NfcMagicSceneGen4GetCFGStateCardSearch);
     nfc_magic_scene_gen4_get_cfg_setup_view(instance);
 
     nfc_magic_app_blink_start(instance);
@@ -76,19 +76,19 @@ bool nfc_magic_scene_gen4_get_cfg_on_event(void* context, SceneManagerEvent even
         if(event.event == NfcMagicCustomEventCardDetected) {
             scene_manager_set_scene_state(
                 instance->scene_manager,
-                NfcMagicSceneGen4GetCFG,
+                NfcMagicSceneGen4GetCfg,
                 NfcMagicSceneGen4GetCFGStateCardFound);
             nfc_magic_scene_gen4_get_cfg_setup_view(instance);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventCardLost) {
             scene_manager_set_scene_state(
                 instance->scene_manager,
-                NfcMagicSceneGen4GetCFG,
+                NfcMagicSceneGen4GetCfg,
                 NfcMagicSceneGen4GetCFGStateCardSearch);
             nfc_magic_scene_gen4_get_cfg_setup_view(instance);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventWorkerSuccess) {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowCFG);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowCfg);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventWorkerFail) {
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail);
@@ -105,7 +105,7 @@ void nfc_magic_scene_gen4_get_cfg_on_exit(void* context) {
     gen4_poller_stop(instance->gen4_poller);
     gen4_poller_free(instance->gen4_poller);
     scene_manager_set_scene_state(
-        instance->scene_manager, NfcMagicSceneGen4GetCFG, NfcMagicSceneGen4GetCFGStateCardSearch);
+        instance->scene_manager, NfcMagicSceneGen4GetCfg, NfcMagicSceneGen4GetCFGStateCardSearch);
     // Clear view
     popup_reset(instance->popup);
 

+ 34 - 0
scenes/nfc_magic_scene_gen4_menu.c

@@ -1,8 +1,12 @@
 #include "../nfc_magic_app_i.h"
+#include "furi_hal_rtc.h"
 
 enum SubmenuIndex {
     SubmenuIndexWrite,
     SubmenuIndexChangePassword,
+    SubmenuIndexSetShadowMode,
+    SubmenuIndexGetRevision,
+    SubmenuIndexGetConfig,
     SubmenuIndexWipe,
 };
 
@@ -24,8 +28,28 @@ void nfc_magic_scene_gen4_menu_on_enter(void* context) {
         SubmenuIndexChangePassword,
         nfc_magic_scene_gen4_menu_submenu_callback,
         instance);
+    submenu_add_item(
+        submenu,
+        "Set Shadow Mode",
+        SubmenuIndexSetShadowMode,
+        nfc_magic_scene_gen4_menu_submenu_callback,
+        instance);
+    submenu_add_item(
+        submenu,
+        "Get Revision",
+        SubmenuIndexGetRevision,
+        nfc_magic_scene_gen4_menu_submenu_callback,
+        instance);
     submenu_add_item(
         submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen4_menu_submenu_callback, instance);
+    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
+        submenu_add_item(
+            submenu,
+            "Get Config",
+            SubmenuIndexGetConfig,
+            nfc_magic_scene_gen4_menu_submenu_callback,
+            instance);
+    }
 
     submenu_set_selected_item(
         submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu));
@@ -46,7 +70,17 @@ bool nfc_magic_scene_gen4_menu_on_event(void* context, SceneManagerEvent event)
         } else if(event.event == SubmenuIndexWipe) {
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
             consumed = true;
+        } else if(event.event == SubmenuIndexGetConfig) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4GetCfg);
+            consumed = true;
+        } else if(event.event == SubmenuIndexGetRevision) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Revision);
+            consumed = true;
+        } else if(event.event == SubmenuIndexSetShadowMode) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SelectShdMode);
+            consumed = true;
         }
+
         scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
     } else if(event.type == SceneManagerEventTypeBack) {
         if(instance->gen4_password != 0) {

+ 113 - 0
scenes/nfc_magic_scene_gen4_select_shd_mode.c

@@ -0,0 +1,113 @@
+#include "../nfc_magic_app_i.h"
+
+/* SHADOW MODES DESCRIPTION:
+    00: pre-write, shadow data can be written
+    01: restore mode
+        WARNING: new UMC (06a0) cards return garbage data when using 01
+    02: disabled
+    03: disabled, high speed R/W mode for Ultralight?
+    04: split mode, work with new UMC. With old UMC is untested.
+*/
+enum SubmenuIndex {
+    SubmenuIndexPreWriteMode,
+    SubmenuIndexRestoreMode,
+    SubmenuIndexDisable,
+    SubmenuIndexDisableHighSpeed,
+    SubmenuIndexSplitMode,
+};
+
+void nfc_magic_scene_gen4_select_shd_mode_submenu_callback(void* context, uint32_t index) {
+    NfcMagicApp* instance = context;
+
+    view_dispatcher_send_custom_event(instance->view_dispatcher, index);
+}
+
+void nfc_magic_scene_gen4_select_shd_mode_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+
+    Submenu* submenu = instance->submenu;
+    submenu_add_item(
+        submenu,
+        "Pre-Write",
+        SubmenuIndexPreWriteMode,
+        nfc_magic_scene_gen4_select_shd_mode_submenu_callback,
+        instance);
+    submenu_add_item(
+        submenu,
+        "Restore",
+        SubmenuIndexRestoreMode,
+        nfc_magic_scene_gen4_select_shd_mode_submenu_callback,
+        instance);
+    submenu_add_item(
+        submenu,
+        "Disable",
+        SubmenuIndexDisable,
+        nfc_magic_scene_gen4_select_shd_mode_submenu_callback,
+        instance);
+    submenu_add_item(
+        submenu,
+        "Disable (High-Speed)",
+        SubmenuIndexDisableHighSpeed,
+        nfc_magic_scene_gen4_select_shd_mode_submenu_callback,
+        instance);
+    submenu_add_item(
+        submenu,
+        "Split",
+        SubmenuIndexSplitMode,
+        nfc_magic_scene_gen4_select_shd_mode_submenu_callback,
+        instance);
+
+    submenu_set_selected_item(
+        submenu,
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SelectShdMode));
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
+}
+
+bool nfc_magic_scene_gen4_select_shd_mode_on_event(void* context, SceneManagerEvent event) {
+    NfcMagicApp* instance = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SubmenuIndexPreWriteMode) {
+            scene_manager_set_scene_state(
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, SubmenuIndexPreWriteMode);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+            consumed = true;
+        } else if(event.event == SubmenuIndexRestoreMode) {
+            scene_manager_set_scene_state(
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, SubmenuIndexRestoreMode);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+            consumed = true;
+        } else if(event.event == SubmenuIndexDisable) {
+            scene_manager_set_scene_state(
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, SubmenuIndexDisable);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+            consumed = true;
+        } else if(event.event == SubmenuIndexDisableHighSpeed) {
+            scene_manager_set_scene_state(
+                instance->scene_manager,
+                NfcMagicSceneGen4SetShdMode,
+                SubmenuIndexDisableHighSpeed);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+            consumed = true;
+        } else if(event.event == SubmenuIndexSplitMode) {
+            scene_manager_set_scene_state(
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, SubmenuIndexSplitMode);
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+            consumed = true;
+        }
+        scene_manager_set_scene_state(
+            instance->scene_manager, NfcMagicSceneGen4SelectShdMode, event.event);
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
+    }
+
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_select_shd_mode_on_exit(void* context) {
+    NfcMagicApp* instance = context;
+
+    submenu_reset(instance->submenu);
+}

+ 12 - 12
scenes/nfc_magic_scene_gen4_set_cfg.c

@@ -1,8 +1,8 @@
 #include "../nfc_magic_app_i.h"
 
 enum {
-    NfcMagicSceneGen4SetDefCFGStateCardSearch,
-    NfcMagicSceneGen4SetDefCFGStateCardFound,
+    NfcMagicSceneGen4SetDefCfgStateCardSearch,
+    NfcMagicSceneGen4SetDefCfgStateCardFound,
 };
 
 NfcCommand nfc_mafic_scene_gen4_set_cfg_poller_callback(Gen4PollerEvent event, void* context) {
@@ -33,9 +33,9 @@ static void nfc_magic_scene_gen4_set_cfg_setup_view(NfcMagicApp* instance) {
     Popup* popup = instance->popup;
     popup_reset(popup);
     uint32_t state =
-        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetCFG);
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetCfg);
 
-    if(state == NfcMagicSceneGen4SetDefCFGStateCardSearch) {
+    if(state == NfcMagicSceneGen4SetDefCfgStateCardSearch) {
         popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
         popup_set_text(
             instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter);
@@ -52,8 +52,8 @@ void nfc_magic_scene_gen4_set_cfg_on_enter(void* context) {
 
     scene_manager_set_scene_state(
         instance->scene_manager,
-        NfcMagicSceneGen4SetCFG,
-        NfcMagicSceneGen4SetDefCFGStateCardSearch);
+        NfcMagicSceneGen4SetCfg,
+        NfcMagicSceneGen4SetDefCfgStateCardSearch);
     nfc_magic_scene_gen4_set_cfg_setup_view(instance);
 
     nfc_magic_app_blink_start(instance);
@@ -72,15 +72,15 @@ bool nfc_magic_scene_gen4_set_cfg_on_event(void* context, SceneManagerEvent even
         if(event.event == NfcMagicCustomEventCardDetected) {
             scene_manager_set_scene_state(
                 instance->scene_manager,
-                NfcMagicSceneGen4SetCFG,
-                NfcMagicSceneGen4SetDefCFGStateCardFound);
+                NfcMagicSceneGen4SetCfg,
+                NfcMagicSceneGen4SetDefCfgStateCardFound);
             nfc_magic_scene_gen4_set_cfg_setup_view(instance);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventCardLost) {
             scene_manager_set_scene_state(
                 instance->scene_manager,
-                NfcMagicSceneGen4SetCFG,
-                NfcMagicSceneGen4SetDefCFGStateCardSearch);
+                NfcMagicSceneGen4SetCfg,
+                NfcMagicSceneGen4SetDefCfgStateCardSearch);
             nfc_magic_scene_gen4_set_cfg_setup_view(instance);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventWorkerSuccess) {
@@ -102,8 +102,8 @@ void nfc_magic_scene_gen4_set_cfg_on_exit(void* context) {
     gen4_poller_free(instance->gen4_poller);
     scene_manager_set_scene_state(
         instance->scene_manager,
-        NfcMagicSceneGen4SetCFG,
-        NfcMagicSceneGen4SetDefCFGStateCardSearch);
+        NfcMagicSceneGen4SetCfg,
+        NfcMagicSceneGen4SetDefCfgStateCardSearch);
     // Clear view
     popup_reset(instance->popup);
 

+ 121 - 0
scenes/nfc_magic_scene_gen4_set_shd_mode.c

@@ -0,0 +1,121 @@
+#include "../nfc_magic_app_i.h"
+#include "applications_user/nfc_magic/lib/magic/protocols/gen4/gen4_poller.h"
+#include "applications_user/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h"
+#include "core/log.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+enum {
+    NfcMagicSceneGen4SetShadowModeStateCardSearch,
+    NfcMagicSceneGen4SetShadowModeStateCardFound,
+};
+
+NfcCommand
+    nfc_magic_scene_gen4_set_shd_mode_poller_callback(Gen4PollerEvent event, void* context) {
+    NfcMagicApp* instance = context;
+    furi_assert(event.data);
+
+    NfcCommand command = NfcCommandContinue;
+    if(event.type == Gen4PollerEventTypeCardDetected) {
+        view_dispatcher_send_custom_event(
+            instance->view_dispatcher, NfcMagicCustomEventCardDetected);
+    } else if(event.type == Gen4PollerEventTypeRequestMode) {
+        event.data->request_mode.mode = Gen4PollerModeSetShadowMode;
+    } else if(event.type == Gen4PollerEventTypeSuccess) {
+        view_dispatcher_send_custom_event(
+            instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
+        command = NfcCommandStop;
+    } else if(event.type == Gen4PollerEventTypeFail) {
+        view_dispatcher_send_custom_event(
+            instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
+        command = NfcCommandStop;
+    }
+
+    return command;
+}
+
+static void nfc_magic_scene_gen4_set_shd_mode_setup_view(NfcMagicApp* instance) {
+    Popup* popup = instance->popup;
+    popup_reset(popup);
+    uint32_t state =
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+
+    if(state == NfcMagicSceneGen4SetShadowModeStateCardSearch) {
+        popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
+        popup_set_text(
+            instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter);
+    } else {
+        popup_set_icon(popup, 12, 23, &I_Loading_24);
+        popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
+    }
+
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
+}
+
+void nfc_magic_scene_gen4_set_shd_mode_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+
+    uint8_t shadow_mode =
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
+
+    scene_manager_set_scene_state(
+        instance->scene_manager,
+        NfcMagicSceneGen4SetShdMode,
+        NfcMagicSceneGen4SetShadowModeStateCardSearch);
+    nfc_magic_scene_gen4_set_shd_mode_setup_view(instance);
+
+    nfc_magic_app_blink_start(instance);
+
+    instance->gen4_poller = gen4_poller_alloc(instance->nfc);
+    gen4_poller_set_password(instance->gen4_poller, instance->gen4_password);
+    instance->gen4_poller->shadow_mode = shadow_mode;
+
+    gen4_poller_start(
+        instance->gen4_poller, nfc_magic_scene_gen4_set_shd_mode_poller_callback, instance);
+}
+
+bool nfc_magic_scene_gen4_set_shd_mode_on_event(void* context, SceneManagerEvent event) {
+    NfcMagicApp* instance = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == NfcMagicCustomEventCardDetected) {
+            scene_manager_set_scene_state(
+                instance->scene_manager,
+                NfcMagicSceneGen4SetShdMode,
+                NfcMagicSceneGen4SetShadowModeStateCardFound);
+            nfc_magic_scene_gen4_set_shd_mode_setup_view(instance);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventCardLost) {
+            scene_manager_set_scene_state(
+                instance->scene_manager,
+                NfcMagicSceneGen4SetShdMode,
+                NfcMagicSceneGen4SetShadowModeStateCardSearch);
+            nfc_magic_scene_gen4_set_shd_mode_setup_view(instance);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventWorkerSuccess) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventWorkerFail) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail);
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_set_shd_mode_on_exit(void* context) {
+    NfcMagicApp* instance = context;
+
+    gen4_poller_stop(instance->gen4_poller);
+    gen4_poller_free(instance->gen4_poller);
+    scene_manager_set_scene_state(
+        instance->scene_manager,
+        NfcMagicSceneGen4SetShdMode,
+        NfcMagicSceneGen4SetShadowModeStateCardSearch);
+    // Clear view
+    popup_reset(instance->popup);
+
+    nfc_magic_app_blink_stop(instance);
+}

+ 10 - 3
scenes/nfc_magic_scene_gen4_show_cfg.c

@@ -1,4 +1,5 @@
 #include "../nfc_magic_app_i.h"
+#include "gui/scene_manager.h"
 
 #define CONFIG_SIZE (32)
 
@@ -33,7 +34,11 @@ void nfc_magic_scene_gen4_show_cfg_on_enter(void* context) {
     widget_add_text_scroll_element(widget, 3, 17, 124, 50, furi_string_get_cstr(temp_config));
 
     widget_add_button_element(
-        widget, GuiButtonTypeLeft, "Exit", nfc_magic_scene_gen4_show_cfg_widget_callback, instance);
+        widget,
+        GuiButtonTypeLeft,
+        "Retry",
+        nfc_magic_scene_gen4_show_cfg_widget_callback,
+        instance);
 
     furi_string_free(temp_config);
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
@@ -45,9 +50,11 @@ bool nfc_magic_scene_gen4_show_cfg_on_event(void* context, SceneManagerEvent eve
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == GuiButtonTypeLeft) {
-            consumed = scene_manager_search_and_switch_to_previous_scene(
-                instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
+            consumed = scene_manager_previous_scene(instance->scene_manager);
         }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneGen4Menu);
     }
     return consumed;
 }

+ 9 - 3
scenes/nfc_magic_scene_gen4_show_rev.c

@@ -29,7 +29,11 @@ void nfc_magic_scene_gen4_show_rev_on_enter(void* context) {
     widget_add_string_multiline_element(
         widget, 3, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_revision));
     widget_add_button_element(
-        widget, GuiButtonTypeLeft, "Exit", nfc_magic_scene_gen4_show_rev_widget_callback, instance);
+        widget,
+        GuiButtonTypeLeft,
+        "Retry",
+        nfc_magic_scene_gen4_show_rev_widget_callback,
+        instance);
 
     furi_string_free(temp_revision);
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
@@ -41,9 +45,11 @@ bool nfc_magic_scene_gen4_show_rev_on_event(void* context, SceneManagerEvent eve
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == GuiButtonTypeLeft) {
-            consumed = scene_manager_search_and_switch_to_previous_scene(
-                instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
+            consumed = scene_manager_previous_scene(instance->scene_manager);
         }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneGen4Menu);
     }
     return consumed;
 }

+ 3 - 0
scenes/nfc_magic_scene_magic_info.c

@@ -52,6 +52,9 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event)
                 consumed = true;
             }
         }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneStart);
     }
     return consumed;
 }