From 20fe544b4f53e637667a17d25c3e4190405aefc9 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 8 Jul 2021 23:41:34 +0300 Subject: [PATCH] [FL-1501] NFC: read Mifare Ultralight (#571) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: add scripts menu scene * canvas: add glyph width api * app_scene: add state to Scene template * gui: introduce TextBox view * nfc: add mifare ultralight read scenes * nfc: add mifare ultralight menu scene * nfc: fix scene functions declaration * Gui: use size_t for sizes. Co-authored-by: あく --- applications/gui/canvas.c | 5 + applications/gui/canvas.h | 5 + applications/gui/modules/text_box.c | 212 ++++++++++++++++++ applications/gui/modules/text_box.h | 63 ++++++ applications/nfc/nfc.c | 19 ++ applications/nfc/nfc_device.h | 5 + applications/nfc/nfc_i.h | 16 ++ applications/nfc/nfc_worker.c | 5 +- .../nfc/scenes/nfc_scene_mifare_ul_menu.c | 69 ++++++ .../nfc/scenes/nfc_scene_mifare_ul_menu.h | 7 + .../nfc/scenes/nfc_scene_read_mifare_ul.c | 67 ++++++ .../nfc/scenes/nfc_scene_read_mifare_ul.h | 7 + .../scenes/nfc_scene_read_mifare_ul_success.c | 152 +++++++++++++ .../scenes/nfc_scene_read_mifare_ul_success.h | 7 + .../nfc/scenes/nfc_scene_scripts_menu.c | 75 +++++++ .../nfc/scenes/nfc_scene_scripts_menu.h | 7 + applications/nfc/scenes/nfc_scene_start.c | 2 +- lib/app_scene_template/app_scene.h | 1 + 18 files changed, 722 insertions(+), 2 deletions(-) create mode 100755 applications/gui/modules/text_box.c create mode 100644 applications/gui/modules/text_box.h mode change 100644 => 100755 applications/nfc/nfc_i.h create mode 100755 applications/nfc/scenes/nfc_scene_mifare_ul_menu.c create mode 100644 applications/nfc/scenes/nfc_scene_mifare_ul_menu.h create mode 100755 applications/nfc/scenes/nfc_scene_read_mifare_ul.c create mode 100644 applications/nfc/scenes/nfc_scene_read_mifare_ul.h create mode 100755 applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c create mode 100644 applications/nfc/scenes/nfc_scene_read_mifare_ul_success.h create mode 100755 applications/nfc/scenes/nfc_scene_scripts_menu.c create mode 100644 applications/nfc/scenes/nfc_scene_scripts_menu.h diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index 6d5b5e6a..3e4d0d85 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -176,6 +176,11 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str) { return u8g2_GetStrWidth(&canvas->fb, str); } +uint8_t canvas_glyph_width(Canvas* canvas, char symbol) { + furi_assert(canvas); + return u8g2_GetGlyphWidth(&canvas->fb, symbol); +} + void canvas_draw_icon_animation( Canvas* canvas, uint8_t x, diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h index 2e55c212..db4bec1f 100644 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -91,6 +91,11 @@ void canvas_draw_str_aligned( */ uint16_t canvas_string_width(Canvas* canvas, const char* str); +/** Get glyph width + * @return width in pixels + */ +uint8_t canvas_glyph_width(Canvas* canvas, char symbol); + /** Draw animation at position defined by x,y. * @param canvas - canvas instance * @param x - x coordinate diff --git a/applications/gui/modules/text_box.c b/applications/gui/modules/text_box.c new file mode 100755 index 00000000..67bb042c --- /dev/null +++ b/applications/gui/modules/text_box.c @@ -0,0 +1,212 @@ +#include "text_box.h" +#include "gui/canvas.h" +#include +#include +#include +#include + +struct TextBox { + View* view; + void* context; + TextBoxExitCallback callback; +}; + +typedef struct { + const char* text; + char* text_pos; + string_t text_formatted; + size_t scroll_pos; + size_t scroll_num; + TextBoxFont font; + bool formatted; +} TextBoxModel; + +static void text_box_process_down(TextBox* text_box) { + with_view_model( + text_box->view, (TextBoxModel * model) { + if(model->scroll_pos < model->scroll_num - 1) { + model->scroll_pos++; + // Search next line start + while(*model->text_pos++ != '\n') + ; + } + return true; + }); +} + +static void text_box_process_up(TextBox* text_box) { + with_view_model( + text_box->view, (TextBoxModel * model) { + if(model->scroll_pos > 0) { + model->scroll_pos--; + // Reach last symbol of previous line + model->text_pos--; + // Search prevous line start + while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) + ; + if(*model->text_pos == '\n') { + model->text_pos++; + } + } + return true; + }); +} + +static void text_box_process_back(TextBox* text_box) { + if(text_box->callback) { + text_box->callback(text_box->context); + } +} + +static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { + size_t i = 0; + size_t line_width = 0; + const char* str = model->text; + size_t line_num = 0; + + const size_t text_width = 140; + + while(str[i] != '\0') { + char symb = str[i++]; + if(symb != '\n') { + line_width += canvas_glyph_width(canvas, symb) + 1; + if(line_width > text_width) { + line_num++; + line_width = 0; + string_push_back(model->text_formatted, '\n'); + } + } else { + line_num++; + line_width = 0; + } + string_push_back(model->text_formatted, symb); + } + line_num++; + model->text = string_get_cstr(model->text_formatted); + model->text_pos = (char*)model->text; + model->scroll_num = MAX(line_num - 4, 0); + model->scroll_pos = 0; +} + +static void text_box_view_draw_callback(Canvas* canvas, void* _model) { + TextBoxModel* model = _model; + + if(!model->formatted) { + text_box_insert_endline(canvas, model); + model->formatted = true; + } + + canvas_clear(canvas); + elements_slightly_rounded_frame(canvas, 0, 0, 124, 64); + if(model->font == TextBoxFontText) { + canvas_set_font(canvas, FontSecondary); + } else if(model->font == TextBoxFontHex) { + canvas_set_font(canvas, FontKeyboard); + } + elements_multiline_text(canvas, 3, 11, model->text_pos); + elements_scrollbar(canvas, model->scroll_pos, model->scroll_num); +} + +static bool text_box_view_input_callback(InputEvent* event, void* context) { + furi_assert(context); + + TextBox* text_box = context; + bool consumed = false; + if(event->type == InputTypeShort) { + if(event->key == InputKeyDown) { + text_box_process_down(text_box); + consumed = true; + } else if(event->key == InputKeyUp) { + text_box_process_up(text_box); + consumed = true; + } else if(event->key == InputKeyBack) { + text_box_process_back(text_box); + consumed = true; + } + } + return consumed; +} + +TextBox* text_box_alloc() { + TextBox* text_box = furi_alloc(sizeof(TextBox)); + text_box->view = view_alloc(); + view_set_context(text_box->view, text_box); + view_allocate_model(text_box->view, ViewModelTypeLocking, sizeof(TextBoxModel)); + view_set_draw_callback(text_box->view, text_box_view_draw_callback); + view_set_input_callback(text_box->view, text_box_view_input_callback); + + with_view_model( + text_box->view, (TextBoxModel * model) { + model->text = NULL; + string_init_set_str(model->text_formatted, ""); + model->formatted = false; + model->font = TextBoxFontText; + return true; + }); + + return text_box; +} + +void text_box_free(TextBox* text_box) { + furi_assert(text_box); + + with_view_model( + text_box->view, (TextBoxModel * model) { + string_clear(model->text_formatted); + return true; + }); + view_free(text_box->view); + free(text_box); +} + +View* text_box_get_view(TextBox* text_box) { + furi_assert(text_box); + return text_box->view; +} + +void text_box_clean(TextBox* text_box) { + furi_assert(text_box); + + with_view_model( + text_box->view, (TextBoxModel * model) { + model->text = NULL; + string_set_str(model->text_formatted, ""); + model->font = TextBoxFontText; + return true; + }); + text_box->context = NULL; + text_box->callback = NULL; +} + +void text_box_set_text(TextBox* text_box, const char* text) { + furi_assert(text_box); + furi_assert(text); + + with_view_model( + text_box->view, (TextBoxModel * model) { + model->text = text; + string_reserve(model->text_formatted, strlen(text)); + model->formatted = false; + return true; + }); +} + +void text_box_set_font(TextBox* text_box, TextBoxFont font) { + furi_assert(text_box); + + with_view_model( + text_box->view, (TextBoxModel * model) { + model->font = font; + return true; + }); +} + +void text_box_set_context(TextBox* text_box, void* context) { + furi_assert(text_box); + text_box->context = context; +} + +void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback) { + furi_assert(text_box); + text_box->callback = callback; +} diff --git a/applications/gui/modules/text_box.h b/applications/gui/modules/text_box.h new file mode 100644 index 00000000..e2bfc34f --- /dev/null +++ b/applications/gui/modules/text_box.h @@ -0,0 +1,63 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* TextBox anonymous structure */ +typedef struct TextBox TextBox; +typedef void (*TextBoxExitCallback)(void* context); + +typedef enum { + TextBoxFontText, + TextBoxFontHex, +} TextBoxFont; + +/** Allocate and initialize text_box + */ +TextBox* text_box_alloc(); + +/** Deinitialize and free text_box + * @param text_box text_box instance + */ +void text_box_free(TextBox* text_box); + +/** Get text_box view + * @param text_box TextBox instance + * @return View instance that can be used for embedding + */ +View* text_box_get_view(TextBox* text_box); + +/** Clean text_box + * @param text_box TextBox instance + */ +void text_box_clean(TextBox* text_box); + +/** Set text for text_box + * @param text_box TextBox instance + * @param text text to set + */ +void text_box_set_text(TextBox* text_box, const char* text); + +/** Set TextBox font + * @param text_box TextBox instance + * @param font TextBoxFont instance + */ +void text_box_set_font(TextBox* text_box, TextBoxFont font); + +/** Set text_box context + * @param text_box TextBox instance + * @param context context pointer + */ +void text_box_set_context(TextBox* text_box, void* context); + +/** Set exit callback + * @param text_box TextBox instance + * @param callback TextBoxExitCallback callback pointer + */ +void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback); + +#ifdef __cplusplus +} +#endif diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index f41d6386..6bee68c2 100755 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -43,6 +43,12 @@ Nfc* nfc_alloc() { view_dispatcher_add_view( nfc->nfc_common.view_dispatcher, NfcViewByteInput, byte_input_get_view(nfc->byte_input)); + // TextBox + nfc->text_box = text_box_alloc(); + view_dispatcher_add_view( + nfc->nfc_common.view_dispatcher, NfcViewTextBox, text_box_get_view(nfc->text_box)); + string_init(nfc->text_box_store); + // Detect nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common); view_dispatcher_add_view( @@ -85,6 +91,10 @@ Nfc* nfc_alloc() { nfc->scene_set_sak = nfc_scene_set_sak_alloc(); nfc->scene_set_atqa = nfc_scene_set_atqa_alloc(); nfc->scene_set_uid = nfc_scene_set_uid_alloc(); + nfc->scene_scripts_menu = nfc_scene_scripts_menu_alloc(); + nfc->scene_read_mifare_ul = nfc_scene_read_mifare_ul_alloc(); + nfc->scene_read_mifare_ul_success = nfc_scene_read_mifare_ul_success_alloc(); + nfc->scene_mifare_ul_menu = nfc_scene_mifare_ul_menu_alloc(); view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_start); @@ -114,6 +124,11 @@ void nfc_free(Nfc* nfc) { view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); byte_input_free(nfc->byte_input); + // TextBox + view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewTextBox); + text_box_free(nfc->text_box); + string_clear(nfc->text_box_store); + // Detect view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); nfc_detect_free(nfc->nfc_detect); @@ -154,6 +169,10 @@ void nfc_free(Nfc* nfc) { nfc_scene_set_sak_free(nfc->scene_set_sak); nfc_scene_set_atqa_free(nfc->scene_set_atqa); nfc_scene_set_uid_free(nfc->scene_set_uid); + nfc_scene_scripts_menu_free(nfc->scene_scripts_menu); + nfc_scene_read_mifare_ul_free(nfc->scene_read_mifare_ul); + nfc_scene_read_mifare_ul_success_free(nfc->scene_read_mifare_ul_success); + nfc_scene_mifare_ul_menu_free(nfc->scene_mifare_ul_menu); // View Dispatcher view_dispatcher_free(nfc->nfc_common.view_dispatcher); diff --git a/applications/nfc/nfc_device.h b/applications/nfc/nfc_device.h index 31147259..ac922320 100644 --- a/applications/nfc/nfc_device.h +++ b/applications/nfc/nfc_device.h @@ -6,6 +6,8 @@ #define NFC_DEV_NAME_MAX_LEN 22 #define NFC_FILE_NAME_MAX_LEN 120 +#define NFC_MIFARE_UL_MAX_SIZE 256 + typedef enum { NfcDeviceNfca, NfcDeviceNfcb, @@ -36,6 +38,9 @@ typedef struct { typedef struct { NfcDeviceData nfc_data; + uint8_t full_dump[NFC_MIFARE_UL_MAX_SIZE]; + uint16_t dump_size; + // TODO delete with debug view uint8_t man_block[12]; uint8_t otp[4]; } NfcMifareUlData; diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h old mode 100644 new mode 100755 index 8d3d3e2b..861dde63 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "views/nfc_detect.h" #include "views/nfc_emulate.h" @@ -38,6 +39,10 @@ #include "scenes/nfc_scene_set_sak.h" #include "scenes/nfc_scene_set_atqa.h" #include "scenes/nfc_scene_set_uid.h" +#include "scenes/nfc_scene_scripts_menu.h" +#include "scenes/nfc_scene_read_mifare_ul.h" +#include "scenes/nfc_scene_read_mifare_ul_success.h" +#include "scenes/nfc_scene_mifare_ul_menu.h" // TODO delete debug scenes #include "scenes/nfc_scene_debug_menu.h" @@ -55,6 +60,7 @@ struct Nfc { NfcDevice device; char text_store[NFC_TEXT_STORE_SIZE + 1]; + string_t text_box_store; // Nfc Views NfcDetect* nfc_detect; @@ -68,6 +74,7 @@ struct Nfc { Popup* popup; TextInput* text_input; ByteInput* byte_input; + TextBox* text_box; // Scenes AppScene* scene_start; @@ -84,6 +91,10 @@ struct Nfc { AppScene* scene_set_sak; AppScene* scene_set_atqa; AppScene* scene_set_uid; + AppScene* scene_scripts_menu; + AppScene* scene_read_mifare_ul; + AppScene* scene_read_mifare_ul_success; + AppScene* scene_mifare_ul_menu; // TODO delete debug scenes AppScene* scene_debug_menu; @@ -99,6 +110,7 @@ typedef enum { NfcViewPopup, NfcViewTextInput, NfcViewByteInput, + NfcViewTextBox, NfcViewDetect, NfcViewEmulate, NfcViewEmv, @@ -125,6 +137,10 @@ typedef enum { NfcSceneSetSak, NfcSceneSetAtqa, NfcSceneSetUid, + NfcSceneScriptsMenu, + NfcSceneReadMifareUl, + NfcSceneReadMifareUlSuccess, + NfcSceneReadMifareUlMenu, } NfcScene; Nfc* nfc_alloc(); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 18e0337a..b23caccc 100755 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -383,7 +383,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { mf_ul_set_default_version(&mf_ul_read); // Reinit device api_hal_nfc_deactivate(); - if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { + if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); continue; } @@ -439,6 +439,9 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); memcpy(result->man_block, mf_ul_read.dump, 4 * 3); memcpy(result->otp, &mf_ul_read.dump[4 * 3], 4); + result->dump_size = mf_ul_read.pages_readed * 4; + memcpy(result->full_dump, mf_ul_read.dump, result->dump_size); + for(uint8_t i = 0; i < mf_ul_read.pages_readed * 4; i += 4) { printf("Page %2d: ", i / 4); for(uint8_t j = 0; j < 4; j++) { diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c new file mode 100755 index 00000000..298833ec --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c @@ -0,0 +1,69 @@ +#include "nfc_scene_mifare_ul_menu.h" +#include "../nfc_i.h" + +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulate, +}; + +void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); +} + +const void nfc_scene_mifare_ul_menu_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Name and save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mifare_ul_menu_submenu_callback, nfc); + + view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); +} + +const bool nfc_scene_mifare_ul_menu_on_event(void* context, uint32_t event) { + Nfc* nfc = (Nfc*)context; + + if(event == SubmenuIndexSave) { + view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); + return true; + } else if(event == SubmenuIndexEmulate) { + view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); + return true; + } else if(event == ViewNavigatorEventBack) { + view_dispatcher_send_back_search_scene_event( + nfc->nfc_common.view_dispatcher, NfcSceneStart); + return true; + } + + return false; +} + +const void nfc_scene_mifare_ul_menu_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + submenu_clean(nfc->submenu); +} + +AppScene* nfc_scene_mifare_ul_menu_alloc() { + AppScene* scene = furi_alloc(sizeof(AppScene)); + scene->id = NfcSceneReadMifareUlMenu; + scene->on_enter = nfc_scene_mifare_ul_menu_on_enter; + scene->on_event = nfc_scene_mifare_ul_menu_on_event; + scene->on_exit = nfc_scene_mifare_ul_menu_on_exit; + + return scene; +} + +void nfc_scene_mifare_ul_menu_free(AppScene* scene) { + free(scene); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.h b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.h new file mode 100644 index 00000000..d757eeb8 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.h @@ -0,0 +1,7 @@ +#pragma once + +#include "app_scene.h" + +AppScene* nfc_scene_mifare_ul_menu_alloc(); + +void nfc_scene_mifare_ul_menu_free(AppScene* scene); diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c new file mode 100755 index 00000000..58763114 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c @@ -0,0 +1,67 @@ +#include +#include +#include "../nfc_i.h" + +void nfc_read_mifare_ul_worker_callback(void* context) { + Nfc* nfc = (Nfc*)context; + view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, NfcEventMifareUl); +} + +const void nfc_scene_read_mifare_ul_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_header(popup, "Detecting\nultralight", 70, 34, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + + // Start worker + nfc_worker_start( + nfc->nfc_common.worker, + NfcWorkerStateReadMfUltralight, + &nfc->nfc_common.worker_result, + nfc_read_mifare_ul_worker_callback, + nfc); + view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewPopup); +} + +const bool nfc_scene_read_mifare_ul_on_event(void* context, uint32_t event) { + Nfc* nfc = (Nfc*)context; + + if(event == NfcEventMifareUl) { + nfc->device.data = nfc->nfc_common.worker_result.nfc_detect_data; + view_dispatcher_add_scene( + nfc->nfc_common.view_dispatcher, nfc->scene_read_mifare_ul_success); + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); + return true; + } + return false; +} + +const void nfc_scene_read_mifare_ul_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + // Stop worker + nfc_worker_stop(nfc->nfc_common.worker); + + // 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); +} + +AppScene* nfc_scene_read_mifare_ul_alloc() { + AppScene* scene = furi_alloc(sizeof(AppScene)); + scene->id = NfcSceneReadMifareUl; + scene->on_enter = nfc_scene_read_mifare_ul_on_enter; + scene->on_event = nfc_scene_read_mifare_ul_on_event; + scene->on_exit = nfc_scene_read_mifare_ul_on_exit; + + return scene; +} + +void nfc_scene_read_mifare_ul_free(AppScene* scene) { + free(scene); +} diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul.h b/applications/nfc/scenes/nfc_scene_read_mifare_ul.h new file mode 100644 index 00000000..19b8e6cb --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul.h @@ -0,0 +1,7 @@ +#pragma once + +#include "app_scene.h" + +AppScene* nfc_scene_read_mifare_ul_alloc(); + +void nfc_scene_read_mifare_ul_free(AppScene* scene); diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c new file mode 100755 index 00000000..621a45a4 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -0,0 +1,152 @@ +#include "nfc_scene_read_mifare_ul_success.h" +#include "../nfc_i.h" + +#include +#include +#include + +#define NFC_SCENE_READ_SUCCESS_SHIFT " " +#define NFC_SCENE_READ_MF_UL_CUSTOM_EVENT (0UL) + +enum { + ReadMifareUlStateShowUID, + ReadMifareUlStateShowData, +}; + +void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, result); +} + +void nfc_scene_read_mifare_ul_success_text_box_callback(void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event( + nfc->nfc_common.view_dispatcher, NFC_SCENE_READ_MF_UL_CUSTOM_EVENT); +} + +const void nfc_scene_read_mifare_ul_success_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Clear device name + nfc_device_set_name(&nfc->device, ""); + + // Send notification + notification_message(nfc->notifications, &sequence_success); + + // Setup dialog view + NfcDeviceData* data = + (NfcDeviceData*)&nfc->nfc_common.worker_result.nfc_mifare_ul_data.nfc_data; + DialogEx* dialog_ex = nfc->dialog_ex; + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "More"); + dialog_ex_set_center_button_text(dialog_ex, "Data"); + dialog_ex_set_header(dialog_ex, "Mifare Ultralight", 22, 8, AlignLeft, AlignCenter); + dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); + // Display UID + nfc_set_text_store( + nfc, + NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X\n" NFC_SCENE_READ_SUCCESS_SHIFT + "SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", + data->atqa[0], + data->atqa[1], + data->sak, + data->uid[0], + data->uid[1], + data->uid[2], + data->uid[3], + data->uid[4], + data->uid[5], + data->uid[6]); + dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); + + // Setup TextBox view + NfcMifareUlData* mf_ul_data = + (NfcMifareUlData*)&nfc->nfc_common.worker_result.nfc_mifare_ul_data; + TextBox* text_box = nfc->text_box; + text_box_set_context(text_box, nfc); + text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); + text_box_set_font(text_box, TextBoxFontHex); + for(uint16_t i = 0; i < mf_ul_data->dump_size; i += 2) { + if(!(i % 8) && i) { + string_push_back(nfc->text_box_store, '\n'); + } + string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + mf_ul_data->full_dump[i], + mf_ul_data->full_dump[i + 1]); + } + text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); + + nfc->scene_read_mifare_ul_success->state = ReadMifareUlStateShowUID; + view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); +} + +const bool nfc_scene_read_mifare_ul_success_on_event(void* context, uint32_t event) { + Nfc* nfc = (Nfc*)context; + + if((nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowUID) && + (event == DialogExResultLeft)) { + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventBack); + return true; + } else if( + (nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowUID) && + (event == DialogExResultRight)) { + view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_mifare_ul_menu); + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); + return true; + } else if( + (nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowUID) && + (event == DialogExResultCenter)) { + view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewTextBox); + nfc->scene_read_mifare_ul_success->state = ReadMifareUlStateShowData; + return true; + } else if( + (nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowData) && + (event == NFC_SCENE_READ_MF_UL_CUSTOM_EVENT)) { + view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); + nfc->scene_read_mifare_ul_success->state = ReadMifareUlStateShowUID; + return true; + } + return false; +} + +const void nfc_scene_read_mifare_ul_success_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + // Clean dialog + DialogEx* dialog_ex = nfc->dialog_ex; + dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, NULL); + dialog_ex_set_right_button_text(dialog_ex, NULL); + dialog_ex_set_center_button_text(dialog_ex, NULL); + dialog_ex_set_result_callback(dialog_ex, NULL); + dialog_ex_set_context(dialog_ex, NULL); + + // Clean TextBox + TextBox* text_box = nfc->text_box; + text_box_clean(text_box); + string_clean(nfc->text_box_store); +} + +AppScene* nfc_scene_read_mifare_ul_success_alloc() { + AppScene* scene = furi_alloc(sizeof(AppScene)); + scene->id = NfcSceneReadMifareUlSuccess; + scene->on_enter = nfc_scene_read_mifare_ul_success_on_enter; + scene->on_event = nfc_scene_read_mifare_ul_success_on_event; + scene->on_exit = nfc_scene_read_mifare_ul_success_on_exit; + + return scene; +} + +void nfc_scene_read_mifare_ul_success_free(AppScene* scene) { + free(scene); +} diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.h b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.h new file mode 100644 index 00000000..a8f9e44b --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.h @@ -0,0 +1,7 @@ +#pragma once + +#include "app_scene.h" + +AppScene* nfc_scene_read_mifare_ul_success_alloc(); + +void nfc_scene_read_mifare_ul_success_free(AppScene* scene); diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.c b/applications/nfc/scenes/nfc_scene_scripts_menu.c new file mode 100755 index 00000000..29086f12 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_scripts_menu.c @@ -0,0 +1,75 @@ +#include "nfc_scene_scripts_menu.h" +#include "../nfc_i.h" + +#include +#include +#include + +enum SubmenuIndex { + SubmenuIndexBankCard, + SubmenuIndexMifareUltralight, +}; + +void nfc_scene_scripts_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); +} + +const void nfc_scene_scripts_menu_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, + "Read bank card", + SubmenuIndexBankCard, + nfc_scene_scripts_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read Mifare Ultralight", + SubmenuIndexMifareUltralight, + nfc_scene_scripts_menu_submenu_callback, + nfc); + + view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); +} + +const bool nfc_scene_scripts_menu_on_event(void* context, uint32_t event) { + Nfc* nfc = (Nfc*)context; + + if(event == SubmenuIndexBankCard) { + view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); + return true; + } else if(event == SubmenuIndexMifareUltralight) { + view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_read_mifare_ul); + view_dispatcher_send_navigation_event( + nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); + return true; + } + + return false; +} + +const void nfc_scene_scripts_menu_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + submenu_clean(nfc->submenu); +} + +AppScene* nfc_scene_scripts_menu_alloc() { + AppScene* scene = furi_alloc(sizeof(AppScene)); + scene->id = NfcSceneScriptsMenu; + scene->on_enter = nfc_scene_scripts_menu_on_enter; + scene->on_event = nfc_scene_scripts_menu_on_event; + scene->on_exit = nfc_scene_scripts_menu_on_exit; + + return scene; +} + +void nfc_scene_scripts_menu_free(AppScene* scene) { + free(scene); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.h b/applications/nfc/scenes/nfc_scene_scripts_menu.h new file mode 100644 index 00000000..8002e568 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_scripts_menu.h @@ -0,0 +1,7 @@ +#pragma once + +#include "app_scene.h" + +AppScene* nfc_scene_scripts_menu_alloc(); + +void nfc_scene_scripts_menu_free(AppScene* scene); diff --git a/applications/nfc/scenes/nfc_scene_start.c b/applications/nfc/scenes/nfc_scene_start.c index 15c59266..80f497b8 100644 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/nfc/scenes/nfc_scene_start.c @@ -49,7 +49,7 @@ const bool nfc_scene_start_on_event(void* context, uint32_t event) { nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); return true; } else if(event == SubmenuIndexRunScript) { - view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); + view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_scripts_menu); view_dispatcher_send_navigation_event( nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); return true; diff --git a/lib/app_scene_template/app_scene.h b/lib/app_scene_template/app_scene.h index e820ab04..f20b7935 100644 --- a/lib/app_scene_template/app_scene.h +++ b/lib/app_scene_template/app_scene.h @@ -5,6 +5,7 @@ typedef struct { uint32_t id; + uint32_t state; const void (*on_enter)(void* context); const bool (*on_event)(void* context, uint32_t event); const void (*on_exit)(void* context);