Explorar o código

Merge nfc_magic from https://github.com/xMasterX/all-the-plugins

Willy-JL %!s(int64=2) %!d(string=hai) anos
pai
achega
5323be716c

+ 1 - 1
nfc_magic/application.fam

@@ -10,7 +10,7 @@ App(
     ],
     ],
     stack_size=4 * 1024,
     stack_size=4 * 1024,
     fap_description="Application for writing to NFC tags with modifiable sector 0",
     fap_description="Application for writing to NFC tags with modifiable sector 0",
-    fap_version="1.3",
+    fap_version="1.4",
     fap_icon="125_10px.png",
     fap_icon="125_10px.png",
     fap_category="NFC",
     fap_category="NFC",
     fap_private_libs=[
     fap_private_libs=[

+ 74 - 0
nfc_magic/lib/magic/protocols/gen4/gen4_poller.c

@@ -1,3 +1,4 @@
+#include "core/log.h"
 #include "gen4_poller_i.h"
 #include "gen4_poller_i.h"
 #include <nfc/protocols/iso14443_3a/iso14443_3a.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
@@ -170,6 +171,12 @@ NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) {
         instance->state = Gen4PollerStateRequestWriteData;
         instance->state = Gen4PollerStateRequestWriteData;
     } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetPassword) {
     } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetPassword) {
         instance->state = Gen4PollerStateChangePassword;
         instance->state = Gen4PollerStateChangePassword;
+    } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDefaultCFG) {
+        instance->state = Gen4PollerStateSetDefaultConfig;
+    } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetCFG) {
+        instance->state = Gen4PollerStateGetCurrentConfig;
+    } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetRevision) {
+        instance->state = Gen4PollerStateGetRevision;
     } else {
     } else {
         instance->state = Gen4PollerStateFail;
         instance->state = Gen4PollerStateFail;
     }
     }
@@ -463,6 +470,70 @@ NfcCommand gen4_poller_change_password_handler(Gen4Poller* instance) {
     return command;
     return command;
 }
 }
 
 
+NfcCommand gen4_poller_set_default_cfg_handler(Gen4Poller* instance) {
+    NfcCommand command = NfcCommandContinue;
+
+    do {
+        Gen4PollerError error = gen4_poller_set_config(
+            instance,
+            instance->password,
+            gen4_poller_default_config,
+            sizeof(gen4_poller_default_config),
+            false);
+        if(error != Gen4PollerErrorNone) {
+            FURI_LOG_E(TAG, "Failed to set default config: %d", error);
+            instance->state = Gen4PollerStateFail;
+            break;
+        }
+
+        instance->state = Gen4PollerStateSuccess;
+    } while(false);
+
+    return command;
+}
+
+NfcCommand gen4_poller_get_current_cfg_handler(Gen4Poller* instance) {
+    NfcCommand command = NfcCommandContinue;
+
+    do {
+        uint8_t the_config[32] = {};
+
+        Gen4PollerError error = gen4_poller_get_config(instance, instance->password, the_config);
+        if(error != Gen4PollerErrorNone) {
+            FURI_LOG_E(TAG, "Failed to get current config: %d", error);
+            instance->state = Gen4PollerStateFail;
+            break;
+        }
+        // Copy config data to event data buffer
+        memcpy(instance->gen4_event_data.display_config, the_config, sizeof(the_config));
+
+        instance->state = Gen4PollerStateSuccess;
+    } while(false);
+
+    return command;
+}
+
+NfcCommand gen4_poller_get_revision_handler(Gen4Poller* instance) {
+    NfcCommand command = NfcCommandContinue;
+
+    do {
+        uint8_t the_revision[5] = {0};
+        Gen4PollerError error =
+            gen4_poller_get_revision(instance, instance->password, the_revision);
+        if(error != Gen4PollerErrorNone) {
+            FURI_LOG_E(TAG, "Failed to get revision: %d", error);
+            instance->state = Gen4PollerStateFail;
+            break;
+        }
+        // Copy revision data to event data buffer
+        memcpy(instance->gen4_event_data.revision_data, the_revision, sizeof(the_revision));
+
+        instance->state = Gen4PollerStateSuccess;
+    } while(false);
+
+    return command;
+}
+
 NfcCommand gen4_poller_success_handler(Gen4Poller* instance) {
 NfcCommand gen4_poller_success_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
     NfcCommand command = NfcCommandContinue;
 
 
@@ -494,6 +565,9 @@ static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNu
     [Gen4PollerStateWrite] = gen4_poller_write_handler,
     [Gen4PollerStateWrite] = gen4_poller_write_handler,
     [Gen4PollerStateWipe] = gen4_poller_wipe_handler,
     [Gen4PollerStateWipe] = gen4_poller_wipe_handler,
     [Gen4PollerStateChangePassword] = gen4_poller_change_password_handler,
     [Gen4PollerStateChangePassword] = gen4_poller_change_password_handler,
+    [Gen4PollerStateSetDefaultConfig] = gen4_poller_set_default_cfg_handler,
+    [Gen4PollerStateGetCurrentConfig] = gen4_poller_get_current_cfg_handler,
+    [Gen4PollerStateGetRevision] = gen4_poller_get_revision_handler,
     [Gen4PollerStateSuccess] = gen4_poller_success_handler,
     [Gen4PollerStateSuccess] = gen4_poller_success_handler,
     [Gen4PollerStateFail] = gen4_poller_fail_handler,
     [Gen4PollerStateFail] = gen4_poller_fail_handler,
 
 

+ 7 - 0
nfc_magic/lib/magic/protocols/gen4/gen4_poller.h

@@ -37,6 +37,10 @@ typedef enum {
     Gen4PollerModeWipe,
     Gen4PollerModeWipe,
     Gen4PollerModeWrite,
     Gen4PollerModeWrite,
     Gen4PollerModeSetPassword,
     Gen4PollerModeSetPassword,
+
+    Gen4PollerModeSetDefaultCFG,
+    Gen4PollerModeGetCFG,
+    Gen4PollerModeGetRevision,
 } Gen4PollerMode;
 } Gen4PollerMode;
 
 
 typedef struct {
 typedef struct {
@@ -56,6 +60,9 @@ typedef union {
     Gen4PollerEventDataRequestMode request_mode;
     Gen4PollerEventDataRequestMode request_mode;
     Gen4PollerEventDataRequestDataToWrite request_data;
     Gen4PollerEventDataRequestDataToWrite request_data;
     Gen4PollerEventDataRequestNewPassword request_password;
     Gen4PollerEventDataRequestNewPassword request_password;
+
+    uint8_t display_config[32];
+    uint8_t revision_data[5];
 } Gen4PollerEventData;
 } Gen4PollerEventData;
 
 
 typedef struct {
 typedef struct {

+ 69 - 0
nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c

@@ -1,17 +1,23 @@
 #include "gen4_poller_i.h"
 #include "gen4_poller_i.h"
 
 
+#include "bit_buffer.h"
+#include "core/log.h"
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 #include <nfc/helpers/nfc_util.h>
 #include <nfc/helpers/nfc_util.h>
 
 
 #define GEN4_CMD_PREFIX (0xCF)
 #define GEN4_CMD_PREFIX (0xCF)
 
 
 #define GEN4_CMD_GET_CFG (0xC6)
 #define GEN4_CMD_GET_CFG (0xC6)
+#define GEN4_CMD_GET_REVISION (0xCC)
 #define GEN4_CMD_WRITE (0xCD)
 #define GEN4_CMD_WRITE (0xCD)
 #define GEN4_CMD_READ (0xCE)
 #define GEN4_CMD_READ (0xCE)
 #define GEN4_CMD_SET_CFG (0xF0)
 #define GEN4_CMD_SET_CFG (0xF0)
 #define GEN4_CMD_FUSE_CFG (0xF1)
 #define GEN4_CMD_FUSE_CFG (0xF1)
 #define GEN4_CMD_SET_PWD (0xFE)
 #define GEN4_CMD_SET_PWD (0xFE)
 
 
+#define CONFIG_SIZE (32)
+#define REVISION_SIZE (5)
+
 static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
 static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     Gen4PollerError ret = Gen4PollerErrorNone;
 
 
@@ -24,6 +30,69 @@ static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
     return ret;
     return ret;
 }
 }
 
 
+Gen4PollerError
+    gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result) {
+    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_GET_CFG);
+
+        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 != CONFIG_SIZE) {
+            ret = Gen4PollerErrorProtocol;
+            break;
+        }
+        bit_buffer_write_bytes(instance->rx_buffer, config_result, CONFIG_SIZE);
+    } while(false);
+
+    return ret;
+}
+
+Gen4PollerError
+    gen4_poller_get_revision(Gen4Poller* instance, uint32_t password, uint8_t* revision_result) {
+    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_GET_REVISION);
+
+        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 != 5) {
+            ret = Gen4PollerErrorProtocol;
+            break;
+        }
+        bit_buffer_write_bytes(instance->rx_buffer, revision_result, REVISION_SIZE);
+    } while(false);
+
+    return ret;
+}
+
 Gen4PollerError gen4_poller_set_config(
 Gen4PollerError gen4_poller_set_config(
     Gen4Poller* instance,
     Gen4Poller* instance,
     uint32_t password,
     uint32_t password,

+ 11 - 0
nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h

@@ -49,6 +49,11 @@ typedef enum {
     Gen4PollerStateWrite,
     Gen4PollerStateWrite,
     Gen4PollerStateWipe,
     Gen4PollerStateWipe,
     Gen4PollerStateChangePassword,
     Gen4PollerStateChangePassword,
+
+    Gen4PollerStateSetDefaultConfig,
+    Gen4PollerStateGetCurrentConfig,
+    Gen4PollerStateGetRevision,
+
     Gen4PollerStateSuccess,
     Gen4PollerStateSuccess,
     Gen4PollerStateFail,
     Gen4PollerStateFail,
 
 
@@ -96,6 +101,12 @@ Gen4PollerError gen4_poller_write_block(
 Gen4PollerError
 Gen4PollerError
     gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new);
     gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new);
 
 
+Gen4PollerError
+    gen4_poller_get_revision(Gen4Poller* instance, uint32_t password, uint8_t* revision_result);
+
+Gen4PollerError
+    gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 3 - 0
nfc_magic/nfc_magic_app_i.h

@@ -73,6 +73,9 @@ struct NfcMagicApp {
     uint32_t gen4_password;
     uint32_t gen4_password;
     uint32_t gen4_password_new;
     uint32_t gen4_password_new;
 
 
+    uint8_t gen4_config_display[32];
+    uint8_t gen4_revision_display[5];
+
     FuriString* text_box_store;
     FuriString* text_box_store;
     uint8_t byte_input_store[NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE];
     uint8_t byte_input_store[NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE];
 
 

+ 7 - 0
nfc_magic/scenes/nfc_magic_scene_config.h

@@ -4,6 +4,13 @@ ADD_SCENE(nfc_magic, key_input, KeyInput)
 ADD_SCENE(nfc_magic, magic_info, MagicInfo)
 ADD_SCENE(nfc_magic, magic_info, MagicInfo)
 ADD_SCENE(nfc_magic, gen1_menu, Gen1Menu)
 ADD_SCENE(nfc_magic, gen1_menu, Gen1Menu)
 ADD_SCENE(nfc_magic, gen4_menu, Gen4Menu)
 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_revision, Gen4Revision)
+ADD_SCENE(nfc_magic, gen4_show_rev, Gen4ShowRev)
+ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCFG)
+ADD_SCENE(nfc_magic, gen4_fail, Gen4Fail)
 ADD_SCENE(nfc_magic, wipe, Wipe)
 ADD_SCENE(nfc_magic, wipe, Wipe)
 ADD_SCENE(nfc_magic, wipe_fail, WipeFail)
 ADD_SCENE(nfc_magic, wipe_fail, WipeFail)
 ADD_SCENE(nfc_magic, success, Success)
 ADD_SCENE(nfc_magic, success, Success)

+ 2 - 2
nfc_magic/scenes/nfc_magic_scene_gen1_menu.c

@@ -21,7 +21,7 @@ void nfc_magic_scene_gen1_menu_on_enter(void* context) {
         submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen1_menu_submenu_callback, instance);
         submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen1_menu_submenu_callback, instance);
 
 
     submenu_set_selected_item(
     submenu_set_selected_item(
-        submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu));
+        submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen1Menu));
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
 }
 }
 
 
@@ -37,7 +37,7 @@ bool nfc_magic_scene_gen1_menu_on_event(void* context, SceneManagerEvent event)
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
             consumed = true;
             consumed = true;
         }
         }
-        scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
+        scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen1Menu, event.event);
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
         consumed = scene_manager_search_and_switch_to_previous_scene(
         consumed = scene_manager_search_and_switch_to_previous_scene(
             instance->scene_manager, NfcMagicSceneStart);
             instance->scene_manager, NfcMagicSceneStart);

+ 86 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c

@@ -0,0 +1,86 @@
+#include "../nfc_magic_app_i.h"
+#include "furi_hal_rtc.h"
+
+enum SubmenuIndex {
+    SubmenuIndexAuthenticate,
+    SubmenuIndexSetStandartConfig,
+    SubmenuIndexGetRevision,
+    SubmenuIndexGetConfig
+};
+
+void nfc_magic_scene_gen4_actions_menu_submenu_callback(void* context, uint32_t index) {
+    NfcMagicApp* instance = context;
+
+    view_dispatcher_send_custom_event(instance->view_dispatcher, index);
+}
+
+void nfc_magic_scene_gen4_actions_menu_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+
+    Submenu* submenu = instance->submenu;
+    submenu_add_item(
+        submenu,
+        "Auth With Password",
+        SubmenuIndexAuthenticate,
+        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);
+    submenu_add_item(
+        submenu,
+        "Get Revision",
+        SubmenuIndexGetRevision,
+        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,
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4ActionsMenu));
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
+}
+
+bool nfc_magic_scene_gen4_actions_menu_on_event(void* context, SceneManagerEvent event) {
+    NfcMagicApp* instance = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SubmenuIndexAuthenticate) {
+            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 == SubmenuIndexGetRevision) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Revision);
+            consumed = true;
+        } else if(event.event == SubmenuIndexGetConfig) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4GetCFG);
+            consumed = true;
+        }
+        scene_manager_set_scene_state(
+            instance->scene_manager, NfcMagicSceneGen4ActionsMenu, event.event);
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneStart);
+    }
+
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_actions_menu_on_exit(void* context) {
+    NfcMagicApp* instance = context;
+
+    submenu_reset(instance->submenu);
+}

+ 49 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_fail.c

@@ -0,0 +1,49 @@
+#include "../nfc_magic_app_i.h"
+
+void nfc_magic_scene_gen4_fail_widget_callback(GuiButtonType result, InputType type, void* context) {
+    NfcMagicApp* instance = context;
+    if(type == InputTypeShort) {
+        view_dispatcher_send_custom_event(instance->view_dispatcher, result);
+    }
+}
+
+void nfc_magic_scene_gen4_fail_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+    Widget* widget = instance->widget;
+
+    notification_message(instance->notifications, &sequence_error);
+
+    widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
+    widget_add_string_element(
+        widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Something gone wrong!");
+    widget_add_string_multiline_element(
+        widget, 7, 17, AlignLeft, AlignTop, FontSecondary, "No response. Maybe\nnot Gen4 card?");
+
+    widget_add_button_element(
+        widget, GuiButtonTypeLeft, "Back", nfc_magic_scene_gen4_fail_widget_callback, instance);
+
+    // Setup and start worker
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
+}
+
+bool nfc_magic_scene_gen4_fail_on_event(void* context, SceneManagerEvent event) {
+    NfcMagicApp* instance = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == GuiButtonTypeLeft) {
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                instance->scene_manager, NfcMagicSceneStart);
+        }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneStart);
+    }
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_fail_on_exit(void* context) {
+    NfcMagicApp* instance = context;
+
+    widget_reset(instance->widget);
+}

+ 113 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_get_cfg.c

@@ -0,0 +1,113 @@
+#include "../nfc_magic_app_i.h"
+
+enum {
+    NfcMagicSceneGen4GetCFGStateCardSearch,
+    NfcMagicSceneGen4GetCFGStateCardFound,
+};
+
+NfcCommand nfc_mafic_scene_gen4_get_cfg_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 = Gen4PollerModeGetCFG;
+    } else if(event.type == Gen4PollerEventTypeSuccess) {
+        // Copy config from event to main instance to display it on success scene
+        memcpy(
+            instance->gen4_config_display,
+            event.data->display_config,
+            sizeof(event.data->display_config));
+
+        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_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);
+
+    if(state == NfcMagicSceneGen4GetCFGStateCardSearch) {
+        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, "Reading\nDon't move...", 52, 32, AlignLeft, AlignCenter);
+    }
+
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
+}
+
+void nfc_magic_scene_gen4_get_cfg_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+
+    scene_manager_set_scene_state(
+        instance->scene_manager, NfcMagicSceneGen4GetCFG, NfcMagicSceneGen4GetCFGStateCardSearch);
+    nfc_magic_scene_gen4_get_cfg_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);
+    gen4_poller_start(
+        instance->gen4_poller, nfc_mafic_scene_gen4_get_cfg_poller_callback, instance);
+}
+
+bool nfc_magic_scene_gen4_get_cfg_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,
+                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,
+                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);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventWorkerFail) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail);
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_get_cfg_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, NfcMagicSceneGen4GetCFG, NfcMagicSceneGen4GetCFGStateCardSearch);
+    // Clear view
+    popup_reset(instance->popup);
+
+    nfc_magic_app_blink_stop(instance);
+}

+ 7 - 2
nfc_magic/scenes/nfc_magic_scene_gen4_menu.c

@@ -49,8 +49,13 @@ bool nfc_magic_scene_gen4_menu_on_event(void* context, SceneManagerEvent event)
         }
         }
         scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
         scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
-        consumed = scene_manager_search_and_switch_to_previous_scene(
-            instance->scene_manager, NfcMagicSceneStart);
+        if(instance->gen4_password != 0) {
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
+        } else {
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                instance->scene_manager, NfcMagicSceneStart);
+        }
     }
     }
 
 
     return consumed;
     return consumed;

+ 117 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_revision.c

@@ -0,0 +1,117 @@
+#include "../nfc_magic_app_i.h"
+
+enum {
+    NfcMagicSceneGen4RevisionStateCardSearch,
+    NfcMagicSceneGen4RevisionStateCardFound,
+};
+
+NfcCommand nfc_mafic_scene_gen4_revision_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 = Gen4PollerModeGetRevision;
+    } else if(event.type == Gen4PollerEventTypeSuccess) {
+        // Copy revision from event to main instance to display it on success scene
+        memcpy(
+            instance->gen4_revision_display,
+            event.data->revision_data,
+            sizeof(event.data->revision_data));
+
+        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_revision_setup_view(NfcMagicApp* instance) {
+    Popup* popup = instance->popup;
+    popup_reset(popup);
+    uint32_t state =
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Revision);
+
+    if(state == NfcMagicSceneGen4RevisionStateCardSearch) {
+        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, "Reading\nDon't move...", 52, 32, AlignLeft, AlignCenter);
+    }
+
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
+}
+
+void nfc_magic_scene_gen4_revision_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+
+    scene_manager_set_scene_state(
+        instance->scene_manager,
+        NfcMagicSceneGen4Revision,
+        NfcMagicSceneGen4RevisionStateCardSearch);
+    nfc_magic_scene_gen4_revision_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);
+    gen4_poller_start(
+        instance->gen4_poller, nfc_mafic_scene_gen4_revision_poller_callback, instance);
+}
+
+bool nfc_magic_scene_gen4_revision_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,
+                NfcMagicSceneGen4Revision,
+                NfcMagicSceneGen4RevisionStateCardFound);
+            nfc_magic_scene_gen4_revision_setup_view(instance);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventCardLost) {
+            scene_manager_set_scene_state(
+                instance->scene_manager,
+                NfcMagicSceneGen4Revision,
+                NfcMagicSceneGen4RevisionStateCardSearch);
+            nfc_magic_scene_gen4_revision_setup_view(instance);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventWorkerSuccess) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowRev);
+            consumed = true;
+        } else if(event.event == NfcMagicCustomEventWorkerFail) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Fail);
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_revision_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,
+        NfcMagicSceneGen4Revision,
+        NfcMagicSceneGen4RevisionStateCardSearch);
+    // Clear view
+    popup_reset(instance->popup);
+
+    nfc_magic_app_blink_stop(instance);
+}

+ 111 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_set_cfg.c

@@ -0,0 +1,111 @@
+#include "../nfc_magic_app_i.h"
+
+enum {
+    NfcMagicSceneGen4SetDefCFGStateCardSearch,
+    NfcMagicSceneGen4SetDefCFGStateCardFound,
+};
+
+NfcCommand nfc_mafic_scene_gen4_set_cfg_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 = Gen4PollerModeSetDefaultCFG;
+    } 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_cfg_setup_view(NfcMagicApp* instance) {
+    Popup* popup = instance->popup;
+    popup_reset(popup);
+    uint32_t state =
+        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4SetCFG);
+
+    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);
+    } 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_cfg_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+
+    scene_manager_set_scene_state(
+        instance->scene_manager,
+        NfcMagicSceneGen4SetCFG,
+        NfcMagicSceneGen4SetDefCFGStateCardSearch);
+    nfc_magic_scene_gen4_set_cfg_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);
+    gen4_poller_start(
+        instance->gen4_poller, nfc_mafic_scene_gen4_set_cfg_poller_callback, instance);
+}
+
+bool nfc_magic_scene_gen4_set_cfg_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,
+                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);
+            nfc_magic_scene_gen4_set_cfg_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_cfg_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,
+        NfcMagicSceneGen4SetCFG,
+        NfcMagicSceneGen4SetDefCFGStateCardSearch);
+    // Clear view
+    popup_reset(instance->popup);
+
+    nfc_magic_app_blink_stop(instance);
+}

+ 59 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c

@@ -0,0 +1,59 @@
+#include "../nfc_magic_app_i.h"
+
+#define CONFIG_SIZE (32)
+
+void nfc_magic_scene_gen4_show_cfg_widget_callback(
+    GuiButtonType result,
+    InputType type,
+    void* context) {
+    NfcMagicApp* instance = context;
+
+    if(type == InputTypeShort) {
+        view_dispatcher_send_custom_event(instance->view_dispatcher, result);
+    }
+}
+
+void nfc_magic_scene_gen4_show_cfg_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+    Widget* widget = instance->widget;
+
+    notification_message(instance->notifications, &sequence_success);
+
+    FuriString* temp_config = furi_string_alloc();
+    for(size_t i = 0; i < CONFIG_SIZE; i++) {
+        if((i != 0) && (i % 8 == 0)) {
+            furi_string_cat_printf(temp_config, "\n");
+        }
+        furi_string_cat_printf(temp_config, "%02X ", instance->gen4_config_display[i]);
+    }
+    furi_string_cat_printf(temp_config, "\n");
+
+    widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Gen4 Config");
+
+    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);
+
+    furi_string_free(temp_config);
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
+}
+
+bool nfc_magic_scene_gen4_show_cfg_on_event(void* context, SceneManagerEvent event) {
+    NfcMagicApp* instance = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == GuiButtonTypeLeft) {
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
+        }
+    }
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_show_cfg_on_exit(void* context) {
+    NfcMagicApp* instance = context;
+
+    widget_reset(instance->widget);
+}

+ 55 - 0
nfc_magic/scenes/nfc_magic_scene_gen4_show_rev.c

@@ -0,0 +1,55 @@
+#include "../nfc_magic_app_i.h"
+
+#define REVISION_SIZE (5)
+
+void nfc_magic_scene_gen4_show_rev_widget_callback(
+    GuiButtonType result,
+    InputType type,
+    void* context) {
+    NfcMagicApp* instance = context;
+
+    if(type == InputTypeShort) {
+        view_dispatcher_send_custom_event(instance->view_dispatcher, result);
+    }
+}
+
+void nfc_magic_scene_gen4_show_rev_on_enter(void* context) {
+    NfcMagicApp* instance = context;
+    Widget* widget = instance->widget;
+
+    notification_message(instance->notifications, &sequence_success);
+
+    FuriString* temp_revision = furi_string_alloc();
+    for(size_t i = REVISION_SIZE - 2; i < REVISION_SIZE; i++) {
+        furi_string_cat_printf(temp_revision, "%02X ", instance->gen4_revision_display[i]);
+    }
+
+    widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
+    widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Gen4 Revision");
+    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);
+
+    furi_string_free(temp_revision);
+    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
+}
+
+bool nfc_magic_scene_gen4_show_rev_on_event(void* context, SceneManagerEvent event) {
+    NfcMagicApp* instance = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == GuiButtonTypeLeft) {
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
+        }
+    }
+    return consumed;
+}
+
+void nfc_magic_scene_gen4_show_rev_on_exit(void* context) {
+    NfcMagicApp* instance = context;
+
+    widget_reset(instance->widget);
+}

+ 5 - 5
nfc_magic/scenes/nfc_magic_scene_start.c

@@ -2,7 +2,7 @@
 
 
 enum SubmenuIndex {
 enum SubmenuIndex {
     SubmenuIndexCheck,
     SubmenuIndexCheck,
-    SubmenuIndexAuthenticateGen4,
+    SubmenuIndexGen4ActionsMenu,
 };
 };
 
 
 void nfc_magic_scene_start_submenu_callback(void* context, uint32_t index) {
 void nfc_magic_scene_start_submenu_callback(void* context, uint32_t index) {
@@ -22,8 +22,8 @@ void nfc_magic_scene_start_on_enter(void* context) {
         instance);
         instance);
     submenu_add_item(
     submenu_add_item(
         submenu,
         submenu,
-        "Authenticate Gen4",
-        SubmenuIndexAuthenticateGen4,
+        "Gen4 Actions",
+        SubmenuIndexGen4ActionsMenu,
         nfc_magic_scene_start_submenu_callback,
         nfc_magic_scene_start_submenu_callback,
         instance);
         instance);
 
 
@@ -44,8 +44,8 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) {
                 instance->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
                 instance->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck);
             consumed = true;
             consumed = true;
-        } else if(event.event == SubmenuIndexAuthenticateGen4) {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneKeyInput);
+        } else if(event.event == SubmenuIndexGen4ActionsMenu) {
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
         }
         }
     }
     }