diff options
author | gornekich <n.gorbadey@gmail.com> | 2021-08-17 00:45:04 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-17 00:45:04 +0300 |
commit | c1223174681f8fa96caee376f502d49886db0355 (patch) | |
tree | 632c5d6539e2d91562800c0b67a83b5c67cd43eb /applications/nfc | |
parent | e1d80d5402d8b19de7e5a448dc20bc83a50e7bfc (diff) |
[FL-1526] Mifare Ultralight emulation (#645)
* rfal: add discovery parameter for passing listen activation
* nfc: add discovery parameter to furi_hal_nfc_listen
* mifare_ul: add emulation parsing commands
* nfc: add mifare ul emulation
* nfc: switch to mifare ultralight emulation form menu
* furi-hal-nfc: add first frame reception in emulation mode
* nfc: change argument check
* nfc: rework nfc worker and mifare ul lib
* mifare_ul: add write and cnt increment commands
* nfc: add card modification check
* mifare_ul: add data changed flag
* nfc: add shodow files
* nfc: add restore original file
Co-authored-by: あく <alleteam@gmail.com>
Diffstat (limited to 'applications/nfc')
-rwxr-xr-x | applications/nfc/nfc.c | 3 | ||||
-rwxr-xr-x | applications/nfc/nfc_cli.c | 2 | ||||
-rwxr-xr-x | applications/nfc/nfc_device.c | 93 | ||||
-rw-r--r-- | applications/nfc/nfc_device.h | 5 | ||||
-rwxr-xr-x | applications/nfc/nfc_worker.c | 55 | ||||
-rwxr-xr-x | applications/nfc/scenes/nfc_scene_config.h | 1 | ||||
-rwxr-xr-x | applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c | 51 | ||||
-rwxr-xr-x | applications/nfc/scenes/nfc_scene_mifare_ul_menu.c | 2 | ||||
-rw-r--r-- | applications/nfc/scenes/nfc_scene_restore_original.c | 48 | ||||
-rwxr-xr-x | applications/nfc/scenes/nfc_scene_saved_menu.c | 41 |
10 files changed, 237 insertions, 64 deletions
diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index a1f4a19e..5bf788b9 100755 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -151,9 +151,10 @@ void nfc_text_store_clear(Nfc* nfc) { int32_t nfc_app(void* p) { Nfc* nfc = nfc_alloc(); + char* args = p; // Check argument and run corresponding scene - if(p && nfc_device_load(&nfc->dev, p)) { + if((*args != '\0') && nfc_device_load(&nfc->dev, p)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c index 8adf5761..e2ddb5ed 100755 --- a/applications/nfc/nfc_cli.c +++ b/applications/nfc/nfc_cli.c @@ -64,7 +64,7 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) { }; while(!cli_cmd_interrupt_received(cli)) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 100)) { + if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { printf("Reader detected\r\n"); furi_hal_nfc_deactivate(); } diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index bfe0e877..bdb3d547 100755 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -8,6 +8,7 @@ static const char* nfc_app_folder = "/any/nfc"; static const char* nfc_app_extension = ".nfc"; +static const char* nfc_app_shadow_extension = ".shd"; static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) { string_strim(str); @@ -259,7 +260,11 @@ void nfc_device_set_name(NfcDevice* dev, const char* name) { strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN); } -bool nfc_device_save(NfcDevice* dev, const char* dev_name) { +static bool nfc_device_save_file( + NfcDevice* dev, + const char* dev_name, + const char* folder, + const char* extension) { furi_assert(dev); FileWorker* file_worker = file_worker_alloc(false); @@ -275,7 +280,7 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { break; }; // First remove nfc device file if it was saved - string_printf(dev_file_name, "%s/%s%s", nfc_app_folder, dev_name, nfc_app_extension); + string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension); if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { break; }; @@ -316,16 +321,42 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { return true; } +bool nfc_device_save(NfcDevice* dev, const char* dev_name) { + return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_extension); +} + +bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { + dev->shadow_file_exist = true; + return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension); +} + static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) { string_t temp_string; string_init(temp_string); bool parsed = false; do { - // Open key file - if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + // Check existance of shadow file + size_t ext_start = string_search_str(path, nfc_app_extension); + string_set_n(temp_string, path, 0, ext_start); + string_cat_printf(temp_string, "%s", nfc_app_shadow_extension); + if(!file_worker_is_file_exist( + file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) { break; } + // Open shadow file if it exists. If not - open original + if(dev->shadow_file_exist) { + if(!file_worker_open( + file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + } else { + if(!file_worker_open( + file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + } + // Read and parse format from 1st line if(!file_worker_read_until(file_worker, temp_string, '\n')) { break; @@ -427,13 +458,61 @@ void nfc_device_clear(NfcDevice* dev) { bool nfc_device_delete(NfcDevice* dev) { furi_assert(dev); - bool result = false; + bool result = true; FileWorker* file_worker = file_worker_alloc(false); string_t file_path; - string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); - result = file_worker_remove(file_worker, string_get_cstr(file_path)); + + do { + // Delete original file + string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); + if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { + result = false; + break; + } + // Delete shadow file if it exists + if(dev->shadow_file_exist) { + string_clean(file_path); + string_printf( + file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); + if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { + result = false; + break; + } + } + } while(0); + string_clear(file_path); file_worker_close(file_worker); file_worker_free(file_worker); return result; } + +bool nfc_device_restore(NfcDevice* dev) { + furi_assert(dev); + furi_assert(dev->shadow_file_exist); + + bool result = true; + FileWorker* file_worker = file_worker_alloc(false); + string_t path; + + do { + string_init_printf( + path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); + if(!file_worker_remove(file_worker, string_get_cstr(path))) { + result = false; + break; + } + dev->shadow_file_exist = false; + string_clean(path); + string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); + if(!nfc_device_load_data(file_worker, path, dev)) { + result = false; + break; + } + } while(0); + + string_clear(path); + file_worker_close(file_worker); + file_worker_free(file_worker); + return result; +} diff --git a/applications/nfc/nfc_device.h b/applications/nfc/nfc_device.h index c2de3120..25f0e42f 100644 --- a/applications/nfc/nfc_device.h +++ b/applications/nfc/nfc_device.h @@ -59,12 +59,15 @@ typedef struct { char dev_name[NFC_DEV_NAME_MAX_LEN]; char file_name[NFC_FILE_NAME_MAX_LEN]; NfcDeviceSaveFormat format; + bool shadow_file_exist; } NfcDevice; void nfc_device_set_name(NfcDevice* dev, const char* name); bool nfc_device_save(NfcDevice* dev, const char* dev_name); +bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name); + bool nfc_device_load(NfcDevice* dev, const char* file_path); bool nfc_file_select(NfcDevice* dev); @@ -72,3 +75,5 @@ bool nfc_file_select(NfcDevice* dev); void nfc_device_clear(NfcDevice* dev); bool nfc_device_delete(NfcDevice* dev); + +bool nfc_device_restore(NfcDevice* dev); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 334e6d7b..9fd6dc64 100755 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -143,7 +143,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { void nfc_worker_emulate(NfcWorker* nfc_worker) { NfcDeviceCommomData* data = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateEmulate) { - if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, 100)) { + if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); } osDelay(10); @@ -406,7 +406,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { 0x00, 0x00}; while(nfc_worker->state == NfcWorkerStateEmulateApdu) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 300)) { + if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected"); // Read data from POS terminal err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); @@ -608,33 +608,52 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { uint8_t* rx_buff; uint16_t* rx_len; NfcDeviceData* data = nfc_worker->dev_data; - + MifareUlDevice mf_ul_emulate; + // Setup emulation parameters from mifare ultralight data structure + mf_ul_prepare_emulation(&mf_ul_emulate, &data->mf_ul_data); while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { if(furi_hal_nfc_listen( data->nfc_data.uid, data->nfc_data.uid_len, data->nfc_data.atqa, data->nfc_data.sak, - 1000)) { - FURI_LOG_I(NFC_WORKER_TAG, "Hello my dudes"); - // Prepare version answer - tx_len = sizeof(data->mf_ul_data.version); - memcpy(tx_buff, &data->mf_ul_data.version, tx_len); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_I(NFC_WORKER_TAG, "Received 1st message:"); - for(uint16_t i = 0; i < *rx_len; i++) { - printf("%02X ", rx_buff[i]); + true, + 200)) { + FURI_LOG_D(NFC_WORKER_TAG, "Anticollision passed"); + if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) { + // Data exchange loop + while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + tx_len = mf_ul_prepare_emulation_response( + rx_buff, *rx_len, tx_buff, &mf_ul_emulate); + if(tx_len > 0) { + err = + furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); + if(err == ERR_NONE) { + continue; + } else { + FURI_LOG_E(NFC_WORKER_TAG, "Communication error: %d", err); + break; + } + } else { + FURI_LOG_W(NFC_WORKER_TAG, "Not valid command: %02X", rx_buff[0]); + furi_hal_nfc_deactivate(); + break; + } } - printf("\r\n"); } else { - FURI_LOG_E(NFC_WORKER_TAG, "Error in 1st data exchange: select PPSE"); + FURI_LOG_W(NFC_WORKER_TAG, "Error in 1st data exchange"); furi_hal_nfc_deactivate(); - continue; } } - FURI_LOG_W(NFC_WORKER_TAG, "Hello my dudes"); - osDelay(10); + // Check if data was modified + if(mf_ul_emulate.data_changed) { + nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; + if(nfc_worker->callback) { + nfc_worker->callback(nfc_worker->context); + } + } + FURI_LOG_W(NFC_WORKER_TAG, "Can't find reader"); + osThreadYield(); } } diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 149b4d7f..97072ead 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -26,3 +26,4 @@ ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm) ADD_SCENE(nfc, read_emv_data, ReadEmvData) ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) +ADD_SCENE(nfc, restore_original, RestoreOriginal) diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c index 7286b7ac..d1d52bef 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c @@ -1,38 +1,33 @@ #include "../nfc_i.h" +#define NFC_MF_UL_DATA_NOT_CHANGED (0UL) +#define NFC_MF_UL_DATA_CHANGED (1UL) + +void nfc_emulate_mifare_ul_worker_callback(void* context) { + Nfc* nfc = (Nfc*)context; + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); +} + const void nfc_scene_emulate_mifare_ul_on_enter(void* context) { Nfc* nfc = (Nfc*)context; // Setup view Popup* popup = nfc->popup; - NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; - if(strcmp(nfc->dev.dev_name, "")) { nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); - } else if(data->uid_len == 4) { - nfc_text_store_set( - nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]); - } else if(data->uid_len == 7) { - nfc_text_store_set( - nfc, - "%02X %02X %02X %02X\n%02X %02X %02X", - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3], - data->uid[4], - data->uid[5], - data->uid[6]); } - popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); - popup_set_header(popup, "Emulating Mf Ul", 56, 31, AlignLeft, AlignTop); - popup_set_text(popup, nfc->text_store, 56, 43, AlignLeft, AlignTop); + popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop); // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc_worker_start(nfc->worker, NfcWorkerStateEmulateMifareUl, &nfc->dev.dev_data, NULL, nfc); + nfc_worker_start( + nfc->worker, + NfcWorkerStateEmulateMifareUl, + &nfc->dev.dev_data, + nfc_emulate_mifare_ul_worker_callback, + nfc); } const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { @@ -42,6 +37,17 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); consumed = true; + } else if(event.type == SceneManagerEventTypeBack) { + // Stop worker + nfc_worker_stop(nfc->worker); + // Check if data changed and save in shadow file + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) == + NFC_MF_UL_DATA_CHANGED) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED); + nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name); + } + consumed = false; } return consumed; } @@ -49,9 +55,6 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent const void nfc_scene_emulate_mifare_ul_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view Popup* popup = nfc->popup; popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c index 396c393b..70716618 100755 --- a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c @@ -38,7 +38,7 @@ const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent ev } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); return true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/nfc/scenes/nfc_scene_restore_original.c b/applications/nfc/scenes/nfc_scene_restore_original.c new file mode 100644 index 00000000..3229d023 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_restore_original.c @@ -0,0 +1,48 @@ +#include "../nfc_i.h" + +#define SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT (0UL) + +void nfc_scene_restore_original_popup_callback(void* context) { + Nfc* nfc = (Nfc*)context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT); +} + +const void nfc_scene_restore_original_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_restore_original_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +const bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + return consumed; +} + +const void nfc_scene_restore_original_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + // Clear view + Popup* popup = nfc->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); +} diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index 24d03fbc..cd682783 100755 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -5,6 +5,7 @@ enum SubmenuIndex { SubmenuIndexEdit, SubmenuIndexDelete, SubmenuIndexInfo, + SubmenuIndexRestoreOriginal, }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { @@ -29,36 +30,52 @@ const void nfc_scene_saved_menu_on_enter(void* context) { submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); + if(nfc->dev.shadow_file_exist) { + submenu_add_item( + submenu, + "Restore original", + SubmenuIndexRestoreOriginal, + nfc_scene_saved_menu_submenu_callback, + nfc); + } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = (Nfc*)context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); if(event.event == SubmenuIndexEmulate) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - return true; + if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + } + consumed = true; } else if(event.event == SubmenuIndexEdit) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEdit); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); - return true; + consumed = true; } else if(event.event == SubmenuIndexDelete) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexDelete); scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); - return true; + consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexInfo); scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); - return true; + consumed = true; + } else if(event.event == SubmenuIndexRestoreOriginal) { + if(!nfc_device_restore(&nfc->dev)) { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal); + } + consumed = true; } } - return false; + return consumed; } const void nfc_scene_saved_menu_on_exit(void* context) { |