diff --git a/base_pack/nfc_magic/application.fam b/base_pack/nfc_magic/application.fam index b13f0ed3d45..81bd0ae8fce 100644 --- a/base_pack/nfc_magic/application.fam +++ b/base_pack/nfc_magic/application.fam @@ -10,7 +10,7 @@ App( ], stack_size=4 * 1024, fap_description="Application for writing to NFC tags with modifiable sector 0", - fap_version="1.3", + fap_version="1.4", fap_icon="assets/Nfc_10px.png", fap_category="NFC", fap_private_libs=[ diff --git a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.c b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.c index dbb7b5ce730..6181936be35 100644 --- a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.c +++ b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.c @@ -1,3 +1,4 @@ +#include "core/log.h" #include "gen4_poller_i.h" #include #include @@ -170,6 +171,12 @@ NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) { instance->state = Gen4PollerStateRequestWriteData; } else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetPassword) { 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 { instance->state = Gen4PollerStateFail; } @@ -463,6 +470,70 @@ NfcCommand gen4_poller_change_password_handler(Gen4Poller* instance) { 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 command = NfcCommandContinue; @@ -494,6 +565,9 @@ static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNu [Gen4PollerStateWrite] = gen4_poller_write_handler, [Gen4PollerStateWipe] = gen4_poller_wipe_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, [Gen4PollerStateFail] = gen4_poller_fail_handler, diff --git a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.h b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.h index 3c087313aa0..a1966164304 100644 --- a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.h +++ b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.h @@ -37,6 +37,10 @@ typedef enum { Gen4PollerModeWipe, Gen4PollerModeWrite, Gen4PollerModeSetPassword, + + Gen4PollerModeSetDefaultCFG, + Gen4PollerModeGetCFG, + Gen4PollerModeGetRevision, } Gen4PollerMode; typedef struct { @@ -56,6 +60,9 @@ typedef union { Gen4PollerEventDataRequestMode request_mode; Gen4PollerEventDataRequestDataToWrite request_data; Gen4PollerEventDataRequestNewPassword request_password; + + uint8_t display_config[32]; + uint8_t revision_data[5]; } Gen4PollerEventData; typedef struct { diff --git a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c index 162199d85d5..52c764d4ce7 100644 --- a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c +++ b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c @@ -1,17 +1,23 @@ #include "gen4_poller_i.h" +#include "bit_buffer.h" +#include "core/log.h" #include #include #define GEN4_CMD_PREFIX (0xCF) #define GEN4_CMD_GET_CFG (0xC6) +#define GEN4_CMD_GET_REVISION (0xCC) #define GEN4_CMD_WRITE (0xCD) #define GEN4_CMD_READ (0xCE) #define GEN4_CMD_SET_CFG (0xF0) #define GEN4_CMD_FUSE_CFG (0xF1) #define GEN4_CMD_SET_PWD (0xFE) +#define CONFIG_SIZE (32) +#define REVISION_SIZE (5) + static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) { Gen4PollerError ret = Gen4PollerErrorNone; @@ -24,6 +30,69 @@ static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) { 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( Gen4Poller* instance, uint32_t password, diff --git a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h index be2f6304eb2..abbbbb7c8a5 100644 --- a/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h +++ b/base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h @@ -49,6 +49,11 @@ typedef enum { Gen4PollerStateWrite, Gen4PollerStateWipe, Gen4PollerStateChangePassword, + + Gen4PollerStateSetDefaultConfig, + Gen4PollerStateGetCurrentConfig, + Gen4PollerStateGetRevision, + Gen4PollerStateSuccess, Gen4PollerStateFail, @@ -96,6 +101,12 @@ Gen4PollerError gen4_poller_write_block( Gen4PollerError 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 } #endif diff --git a/base_pack/nfc_magic/nfc_magic_app_i.h b/base_pack/nfc_magic/nfc_magic_app_i.h index 7e710e9afaf..85d7ac4f537 100644 --- a/base_pack/nfc_magic/nfc_magic_app_i.h +++ b/base_pack/nfc_magic/nfc_magic_app_i.h @@ -71,6 +71,9 @@ struct NfcMagicApp { uint32_t gen4_password; uint32_t gen4_password_new; + uint8_t gen4_config_display[32]; + uint8_t gen4_revision_display[5]; + FuriString* text_box_store; uint8_t byte_input_store[NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE]; diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_config.h b/base_pack/nfc_magic/scenes/nfc_magic_scene_config.h index 190ec876f84..301d67f55ae 100644 --- a/base_pack/nfc_magic/scenes/nfc_magic_scene_config.h +++ b/base_pack/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, 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_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_fail, WipeFail) ADD_SCENE(nfc_magic, success, Success) diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen1_menu.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen1_menu.c index eae84afa868..5900ac737ff 100644 --- a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen1_menu.c +++ b/base_pack/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_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); } @@ -37,7 +37,7 @@ bool nfc_magic_scene_gen1_menu_on_event(void* context, SceneManagerEvent event) scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe); 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) { consumed = scene_manager_search_and_switch_to_previous_scene( instance->scene_manager, NfcMagicSceneStart); diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_actions_menu.c new file mode 100644 index 00000000000..04ac85e9fc1 --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_fail.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_fail.c new file mode 100644 index 00000000000..c1e0f988d18 --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_get_cfg.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_get_cfg.c new file mode 100644 index 00000000000..9d69803550b --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c index 7551883b49c..69fb78af5b0 100644 --- a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_menu.c +++ b/base_pack/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); } 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; diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_revision.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_revision.c new file mode 100644 index 00000000000..c3d863e063b --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_set_cfg.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_set_cfg.c new file mode 100644 index 00000000000..d9910dec42c --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c new file mode 100644 index 00000000000..0aed4588484 --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_show_rev.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_gen4_show_rev.c new file mode 100644 index 00000000000..74b525ff89e --- /dev/null +++ b/base_pack/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); +} diff --git a/base_pack/nfc_magic/scenes/nfc_magic_scene_start.c b/base_pack/nfc_magic/scenes/nfc_magic_scene_start.c index 3d4c57b4283..922129897d8 100644 --- a/base_pack/nfc_magic/scenes/nfc_magic_scene_start.c +++ b/base_pack/nfc_magic/scenes/nfc_magic_scene_start.c @@ -2,7 +2,7 @@ enum SubmenuIndex { SubmenuIndexCheck, - SubmenuIndexAuthenticateGen4, + SubmenuIndexGen4ActionsMenu, }; 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); submenu_add_item( submenu, - "Authenticate Gen4", - SubmenuIndexAuthenticateGen4, + "Gen4 Actions", + SubmenuIndexGen4ActionsMenu, nfc_magic_scene_start_submenu_callback, instance); @@ -44,8 +44,8 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) { instance->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck); scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck); 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); } }