From 49af516ec720d9378fb294ec792f6bd8f489678d Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 22 Jul 2021 09:05:07 +0300 Subject: [PATCH] [FL-1547], [FL-1500] NFC app v1 (#593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: remove mifare read debug view and scene * nfc: change mifare ultralight data structure * mifare_ultralight: add more commands * nfc: add emulate mifare ul scene * nfc: rework data structures, remove debug scenes and views * nfc: add read emv scenes * nfc: mifare emulation wip * nfc cli: increase detecting time * nfc: save nfc files with new format * nfc: store Mifare Ultralight * nfc: start loading mifare ultralight * nfc: add delete scenes * nfc: add edit UID and name * nfc: finish parsing uid and mifare ul data * nfc: delete success fix * gui_widget: introduce GuiWidget * gui_widget: add string element * gui_widget: add button element * gui_widget: move free elements into gui_widget * nfc: rework info scene with GuiWidget * nfc: rework device info scene * nfc: rework delete scene gui * nfc: add compatible script support * nfc: rework emv reading scenes * nfc: rework bank card save * nfc: add bank card custom view * gui_widget: add icon element * nfc: add icon to bank card * nfc: start worker after switching view Co-authored-by: あく --- .../nfc/gui_widget/gui_element_button.c | 84 ++++ .../nfc/gui_widget/gui_element_button.h | 24 ++ applications/nfc/gui_widget/gui_element_i.h | 21 + .../nfc/gui_widget/gui_element_icon.c | 51 +++ .../nfc/gui_widget/gui_element_icon.h | 13 + .../nfc/gui_widget/gui_element_string.c | 72 ++++ .../nfc/gui_widget/gui_element_string.h | 21 + applications/nfc/gui_widget/gui_widget.c | 141 ++++++ applications/nfc/gui_widget/gui_widget.h | 76 ++++ applications/nfc/nfc.c | 99 ++--- applications/nfc/nfc_cli.c | 6 +- applications/nfc/nfc_device.c | 400 +++++++++++++++--- applications/nfc/nfc_device.h | 40 +- applications/nfc/nfc_device_i.h | 16 + applications/nfc/nfc_i.h | 30 +- applications/nfc/nfc_types.h | 21 +- applications/nfc/nfc_worker.c | 250 ++++++++--- applications/nfc/nfc_worker.h | 16 +- applications/nfc/nfc_worker_i.h | 10 +- applications/nfc/scenes/nfc_scene_card_menu.c | 27 +- applications/nfc/scenes/nfc_scene_config.h | 14 +- .../nfc/scenes/nfc_scene_debug_detect.c | 14 - .../nfc/scenes/nfc_scene_debug_emulate.c | 14 - .../nfc/scenes/nfc_scene_debug_menu.c | 72 ---- .../nfc/scenes/nfc_scene_debug_read_emv.c | 14 - .../scenes/nfc_scene_debug_read_mifare_ul.c | 14 - applications/nfc/scenes/nfc_scene_delete.c | 95 +++++ .../nfc/scenes/nfc_scene_delete_success.c | 47 ++ .../nfc/scenes/nfc_scene_device_info.c | 185 ++++++++ .../nfc/scenes/nfc_scene_emulate_mifare_ul.c | 60 +++ .../nfc/scenes/nfc_scene_emulate_uid.c | 14 +- .../nfc/scenes/nfc_scene_file_select.c | 2 +- .../nfc/scenes/nfc_scene_mifare_ul_menu.c | 7 +- .../nfc/scenes/nfc_scene_not_implemented.c | 4 +- applications/nfc/scenes/nfc_scene_read_card.c | 17 +- .../nfc/scenes/nfc_scene_read_card_success.c | 10 +- .../nfc/scenes/nfc_scene_read_emv_app.c | 54 +++ .../scenes/nfc_scene_read_emv_app_success.c | 69 +++ .../nfc/scenes/nfc_scene_read_emv_data.c | 57 +++ .../scenes/nfc_scene_read_emv_data_success.c | 89 ++++ .../nfc/scenes/nfc_scene_read_mifare_ul.c | 17 +- .../scenes/nfc_scene_read_mifare_ul_success.c | 26 +- .../scenes/nfc_scene_run_emv_app_confirm.c | 56 +++ applications/nfc/scenes/nfc_scene_save_name.c | 14 +- .../nfc/scenes/nfc_scene_save_success.c | 5 +- .../nfc/scenes/nfc_scene_saved_menu.c | 16 +- .../nfc/scenes/nfc_scene_scripts_menu.c | 6 +- applications/nfc/scenes/nfc_scene_set_atqa.c | 12 +- applications/nfc/scenes/nfc_scene_set_sak.c | 11 +- applications/nfc/scenes/nfc_scene_set_type.c | 10 +- applications/nfc/scenes/nfc_scene_set_uid.c | 8 +- applications/nfc/scenes/nfc_scene_start.c | 11 +- applications/nfc/views/bank_card.c | 65 +++ applications/nfc/views/bank_card.h | 23 + applications/nfc/views/nfc_detect.c | 142 ------- applications/nfc/views/nfc_detect.h | 12 - applications/nfc/views/nfc_emulate.c | 79 ---- applications/nfc/views/nfc_emulate.h | 12 - applications/nfc/views/nfc_emv.c | 133 ------ applications/nfc/views/nfc_emv.h | 12 - applications/nfc/views/nfc_mifare_ul.c | 162 ------- applications/nfc/views/nfc_mifare_ul.h | 12 - lib/nfc_protocols/mifare_ultralight.c | 86 +++- lib/nfc_protocols/mifare_ultralight.h | 47 +- 64 files changed, 2188 insertions(+), 1059 deletions(-) create mode 100644 applications/nfc/gui_widget/gui_element_button.c create mode 100644 applications/nfc/gui_widget/gui_element_button.h create mode 100644 applications/nfc/gui_widget/gui_element_i.h create mode 100644 applications/nfc/gui_widget/gui_element_icon.c create mode 100644 applications/nfc/gui_widget/gui_element_icon.h create mode 100755 applications/nfc/gui_widget/gui_element_string.c create mode 100755 applications/nfc/gui_widget/gui_element_string.h create mode 100755 applications/nfc/gui_widget/gui_widget.c create mode 100755 applications/nfc/gui_widget/gui_widget.h create mode 100644 applications/nfc/nfc_device_i.h mode change 100644 => 100755 applications/nfc/nfc_worker_i.h delete mode 100755 applications/nfc/scenes/nfc_scene_debug_detect.c delete mode 100755 applications/nfc/scenes/nfc_scene_debug_emulate.c delete mode 100755 applications/nfc/scenes/nfc_scene_debug_menu.c delete mode 100755 applications/nfc/scenes/nfc_scene_debug_read_emv.c delete mode 100755 applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.c create mode 100644 applications/nfc/scenes/nfc_scene_delete.c create mode 100644 applications/nfc/scenes/nfc_scene_delete_success.c create mode 100755 applications/nfc/scenes/nfc_scene_device_info.c create mode 100755 applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c mode change 100644 => 100755 applications/nfc/scenes/nfc_scene_emulate_uid.c create mode 100755 applications/nfc/scenes/nfc_scene_read_emv_app.c create mode 100755 applications/nfc/scenes/nfc_scene_read_emv_app_success.c create mode 100644 applications/nfc/scenes/nfc_scene_read_emv_data.c create mode 100755 applications/nfc/scenes/nfc_scene_read_emv_data_success.c create mode 100755 applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c create mode 100755 applications/nfc/views/bank_card.c create mode 100644 applications/nfc/views/bank_card.h delete mode 100755 applications/nfc/views/nfc_detect.c delete mode 100644 applications/nfc/views/nfc_detect.h delete mode 100755 applications/nfc/views/nfc_emulate.c delete mode 100644 applications/nfc/views/nfc_emulate.h delete mode 100755 applications/nfc/views/nfc_emv.c delete mode 100644 applications/nfc/views/nfc_emv.h delete mode 100755 applications/nfc/views/nfc_mifare_ul.c delete mode 100644 applications/nfc/views/nfc_mifare_ul.h diff --git a/applications/nfc/gui_widget/gui_element_button.c b/applications/nfc/gui_widget/gui_element_button.c new file mode 100644 index 00000000..e671d7dd --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_button.c @@ -0,0 +1,84 @@ +#include "gui_element_i.h" +#include "gui_element_button.h" +#include "gui_widget.h" +#include +#include + +typedef struct { + GuiButtonType button_type; + string_t text; + ButtonCallback callback; + void* context; +} GuiButtonModel; + +static void gui_button_draw(Canvas* canvas, GuiElement* element) { + furi_assert(canvas); + furi_assert(element); + GuiButtonModel* model = element->model; + + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + + if(model->button_type == GuiButtonTypeLeft) { + elements_button_left(canvas, string_get_cstr(model->text)); + } else if(model->button_type == GuiButtonTypeRight) { + elements_button_right(canvas, string_get_cstr(model->text)); + } else if(model->button_type == GuiButtonTypeCenter) { + elements_button_center(canvas, string_get_cstr(model->text)); + } +} + +static bool gui_button_input(InputEvent* event, GuiElement* element) { + GuiButtonModel* model = element->model; + bool consumed = false; + + if((event->type == InputTypeShort) && model->callback) { + if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) { + model->callback(model->button_type, model->context); + consumed = true; + } else if((model->button_type == GuiButtonTypeRight) && (event->key == InputKeyRight)) { + model->callback(model->button_type, model->context); + consumed = true; + } else if((model->button_type == GuiButtonTypeCenter) && (event->key == InputKeyOk)) { + model->callback(model->button_type, model->context); + consumed = true; + } + } + + return consumed; +} + +static void gui_button_free(GuiElement* gui_button) { + furi_assert(gui_button); + + GuiButtonModel* model = gui_button->model; + if(gui_button->parent != NULL) { + // TODO deattach element + } + string_clear(model->text); + free(gui_button->model); + free(gui_button); +} + +GuiElement* gui_button_create( + GuiButtonType button_type, + const char* text, + ButtonCallback callback, + void* context) { + // Allocate and init model + GuiButtonModel* model = furi_alloc(sizeof(GuiButtonModel)); + model->button_type = button_type; + model->callback = callback; + model->context = context; + string_init_set_str(model->text, text); + + // Allocate and init Element + GuiElement* gui_button = furi_alloc(sizeof(GuiElement)); + gui_button->parent = NULL; + gui_button->input = gui_button_input; + gui_button->draw = gui_button_draw; + gui_button->free = gui_button_free; + gui_button->model = model; + + return gui_button; +} diff --git a/applications/nfc/gui_widget/gui_element_button.h b/applications/nfc/gui_widget/gui_element_button.h new file mode 100644 index 00000000..804c0a4e --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_button.h @@ -0,0 +1,24 @@ +#pragma once +#include + +typedef struct GuiElement GuiElement; + +typedef enum { + GuiButtonTypeLeft, + GuiButtonTypeCenter, + GuiButtonTypeRight, +} GuiButtonType; + +typedef void (*ButtonCallback)(GuiButtonType button, void* context); + +/** Allocate Button Element + * @param button_type GuiButtonType instance + * @param text text on allocated button + * @param callback ButtonCallback instance + * @param context pointer to context + */ +GuiElement* gui_button_create( + GuiButtonType button_type, + const char* text, + ButtonCallback callback, + void* context); diff --git a/applications/nfc/gui_widget/gui_element_i.h b/applications/nfc/gui_widget/gui_element_i.h new file mode 100644 index 00000000..ee06e1c7 --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_i.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +typedef struct GuiElement GuiElement; +typedef struct GuiWidget GuiWidget; + +struct GuiElement { + // generic draw and input callbacks + void (*draw)(Canvas* canvas, GuiElement* element); + bool (*input)(InputEvent* event, GuiElement* element); + + // free callback + void (*free)(GuiElement* element); + + // generic model holder + void* model; + + // pointer to widget that hold our element + GuiWidget* parent; +}; \ No newline at end of file diff --git a/applications/nfc/gui_widget/gui_element_icon.c b/applications/nfc/gui_widget/gui_element_icon.c new file mode 100644 index 00000000..f9ca4b60 --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_icon.c @@ -0,0 +1,51 @@ +#include "gui_element_i.h" +#include "gui_element_icon.h" +#include "gui_widget.h" + +#include + +typedef struct { + uint8_t x; + uint8_t y; + const Icon* icon; +} GuiIconModel; + +static void gui_icon_draw(Canvas* canvas, GuiElement* element) { + furi_assert(canvas); + furi_assert(element); + GuiIconModel* model = element->model; + + if(model->icon) { + canvas_draw_icon(canvas, model->x, model->y, model->icon); + } +} + +static void gui_icon_free(GuiElement* gui_icon) { + furi_assert(gui_icon); + + if(gui_icon->parent != NULL) { + // TODO deattach element + } + free(gui_icon->model); + free(gui_icon); +} + +GuiElement* gui_icon_create(uint8_t x, uint8_t y, const Icon* icon) { + furi_assert(icon); + + // Allocate and init model + GuiIconModel* model = furi_alloc(sizeof(GuiIconModel)); + model->x = x; + model->y = y; + model->icon = icon; + + // Allocate and init Element + GuiElement* gui_icon = furi_alloc(sizeof(GuiElement)); + gui_icon->parent = NULL; + gui_icon->input = NULL; + gui_icon->draw = gui_icon_draw; + gui_icon->free = gui_icon_free; + gui_icon->model = model; + + return gui_icon; +} diff --git a/applications/nfc/gui_widget/gui_element_icon.h b/applications/nfc/gui_widget/gui_element_icon.h new file mode 100644 index 00000000..2c983858 --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_icon.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +typedef struct GuiElement GuiElement; + +/** Allocate GuiElement element + * @param x - x coordinate + * @param y - y coordinate + * @param icon Icon instance + * @return GuiElement instance + */ +GuiElement* gui_icon_create(uint8_t x, uint8_t y, const Icon* icon); diff --git a/applications/nfc/gui_widget/gui_element_string.c b/applications/nfc/gui_widget/gui_element_string.c new file mode 100755 index 00000000..dc9e271c --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_string.c @@ -0,0 +1,72 @@ +#include "gui_element_i.h" +#include "gui_element_string.h" +#include "gui_widget.h" + +#include + +typedef struct { + uint8_t x; + uint8_t y; + Align horizontal; + Align vertical; + Font font; + string_t text; +} GuiStringModel; + +static void gui_string_draw(Canvas* canvas, GuiElement* element) { + furi_assert(canvas); + furi_assert(element); + GuiStringModel* model = element->model; + + if(string_size(model->text)) { + canvas_set_font(canvas, model->font); + canvas_draw_str_aligned( + canvas, + model->x, + model->y, + model->horizontal, + model->vertical, + string_get_cstr(model->text)); + } +} + +static void gui_string_free(GuiElement* gui_string) { + furi_assert(gui_string); + + GuiStringModel* model = gui_string->model; + if(gui_string->parent != NULL) { + // TODO deattach element + } + string_clear(model->text); + free(gui_string->model); + free(gui_string); +} + +GuiElement* gui_string_create( + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text) { + furi_assert(text); + + // Allocate and init model + GuiStringModel* model = furi_alloc(sizeof(GuiStringModel)); + model->x = x; + model->y = y; + model->horizontal = horizontal; + model->vertical = vertical; + model->font = font; + string_init_set_str(model->text, text); + + // Allocate and init Element + GuiElement* gui_string = furi_alloc(sizeof(GuiElement)); + gui_string->parent = NULL; + gui_string->input = NULL; + gui_string->draw = gui_string_draw; + gui_string->free = gui_string_free; + gui_string->model = model; + + return gui_string; +} diff --git a/applications/nfc/gui_widget/gui_element_string.h b/applications/nfc/gui_widget/gui_element_string.h new file mode 100755 index 00000000..5be2ae40 --- /dev/null +++ b/applications/nfc/gui_widget/gui_element_string.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +typedef struct GuiElement GuiElement; + +/** Allocate GuiElement element + * @param x - x coordinate + * @param y - y coordinate + * @param horizontal - Align instance + * @param vertical - Align instance + * @param font Font instance + * @return GuiElement instance + */ +GuiElement* gui_string_create( + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text); diff --git a/applications/nfc/gui_widget/gui_widget.c b/applications/nfc/gui_widget/gui_widget.c new file mode 100755 index 00000000..c5b21d95 --- /dev/null +++ b/applications/nfc/gui_widget/gui_widget.c @@ -0,0 +1,141 @@ +#include +#include "gui_element_i.h" +#include "gui_widget.h" + +#define MAX_GUI_ELEMENTS 8 + +struct GuiWidget { + View* view; + void* context; +}; + +// TODO rework with M-LIB container +typedef struct { + GuiElement* element[MAX_GUI_ELEMENTS]; +} GuiWidgetModel; + +static void gui_widget_view_draw_callback(Canvas* canvas, void* _model) { + GuiWidgetModel* model = _model; + canvas_clear(canvas); + + for(uint8_t i = 0; i < MAX_GUI_ELEMENTS; i++) { + if(model->element[i] != NULL) { + if(model->element[i]->draw != NULL) { + model->element[i]->draw(canvas, model->element[i]); + } + } + }; +} + +static bool gui_widget_view_input_callback(InputEvent* event, void* context) { + GuiWidget* gui_widget = context; + bool consumed = false; + + with_view_model( + gui_widget->view, (GuiWidgetModel * model) { + for(uint8_t i = 0; i < MAX_GUI_ELEMENTS; i++) { + if(model->element[i] != NULL) { + if(model->element[i]->input != NULL) { + consumed = model->element[i]->input(event, model->element[i]); + } + } + }; + return true; + }); + + return consumed; +} + +GuiWidget* gui_widget_alloc() { + GuiWidget* gui_widget = furi_alloc(sizeof(GuiWidget)); + gui_widget->view = view_alloc(); + view_set_context(gui_widget->view, gui_widget); + view_allocate_model(gui_widget->view, ViewModelTypeLocking, sizeof(GuiWidgetModel)); + view_set_draw_callback(gui_widget->view, gui_widget_view_draw_callback); + view_set_input_callback(gui_widget->view, gui_widget_view_input_callback); + + with_view_model( + gui_widget->view, (GuiWidgetModel * model) { + for(uint8_t i = 0; i < MAX_GUI_ELEMENTS; i++) { + model->element[i] = NULL; + }; + return true; + }); + + return gui_widget; +} + +void gui_widget_free(GuiWidget* gui_widget) { + furi_assert(gui_widget); + gui_widget_clear(gui_widget); + view_free(gui_widget->view); + free(gui_widget); +} + +void gui_widget_clear(GuiWidget* gui_widget) { + furi_assert(gui_widget); + + with_view_model( + gui_widget->view, (GuiWidgetModel * model) { + for(uint8_t i = 0; i < MAX_GUI_ELEMENTS; i++) { + if(model->element[i]) { + furi_assert(model->element[i]->free); + model->element[i]->free(model->element[i]); + model->element[i] = NULL; + } + }; + return true; + }); +} + +View* gui_widget_get_view(GuiWidget* gui_widget) { + furi_assert(gui_widget); + return gui_widget->view; +} + +void gui_widget_add_element(GuiWidget* gui_widget, GuiElement* element) { + furi_assert(gui_widget); + with_view_model( + gui_widget->view, (GuiWidgetModel * model) { + // add element to first null position + for(uint8_t i = 0; i < MAX_GUI_ELEMENTS; i++) { + if(model->element[i] == NULL) { + model->element[i] = element; + element->parent = gui_widget; + break; + } + }; + return true; + }); +} + +void gui_widget_add_string_element( + GuiWidget* gui_widget, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text) { + furi_assert(gui_widget); + GuiElement* string_element = gui_string_create(x, y, horizontal, vertical, font, text); + gui_widget_add_element(gui_widget, string_element); +} + +void gui_widget_add_button_element( + GuiWidget* gui_widget, + GuiButtonType button_type, + const char* text, + ButtonCallback callback, + void* context) { + furi_assert(gui_widget); + GuiElement* button_element = gui_button_create(button_type, text, callback, context); + gui_widget_add_element(gui_widget, button_element); +} + +void gui_widget_add_icon_element(GuiWidget* gui_widget, uint8_t x, uint8_t y, const Icon* icon) { + furi_assert(gui_widget); + furi_assert(icon); + GuiElement* icon_element = gui_icon_create(x, y, icon); + gui_widget_add_element(gui_widget, icon_element); +} diff --git a/applications/nfc/gui_widget/gui_widget.h b/applications/nfc/gui_widget/gui_widget.h new file mode 100755 index 00000000..6b34b1f9 --- /dev/null +++ b/applications/nfc/gui_widget/gui_widget.h @@ -0,0 +1,76 @@ +#pragma once +#include +#include "gui_element_string.h" +#include "gui_element_button.h" +#include "gui_element_icon.h" + +typedef struct GuiWidget GuiWidget; +typedef struct GuiElement GuiElement; + +/** Allocate Gui Widget that holds Gui Elements + * @return GuiWidget instance + */ +GuiWidget* gui_widget_alloc(); + +/** Free Gui Widget + * @note this function free Gui Elements + * @param gui_widget GuiWidget instance + */ +void gui_widget_free(GuiWidget* gui_widget); + +/** Clear Gui Widget + * @param gui_widget GuiWidget instance + */ +void gui_widget_clear(GuiWidget* gui_widget); + +/** Get Gui Widget view + * @param gui_widget GuiWidget instance + * @return View instance + */ +View* gui_widget_get_view(GuiWidget* gui_widget); + +/** Add generic Gui Elements to Gui Widget + * @param gui_widget GuiWidget instance + * @param element GuiElement element + */ +void gui_widget_add_element(GuiWidget* gui_widget, GuiElement* element); + +/** Add String Element + * @param gui_widget GuiWidget instance + * @param x - x coordinate + * @param y - y coordinate + * @param horizontal - Align instance + * @param vertical - Align instance + * @param font Font instance + * @return GuiElement instance + */ +void gui_widget_add_string_element( + GuiWidget* gui_widget, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text); + +/** Add Button Element + * @param gui_widget GuiWidget instance + * @param button_type GuiButtonType instance + * @param text text on allocated button + * @param callback ButtonCallback instance + * @param context pointer to context + */ +void gui_widget_add_button_element( + GuiWidget* gui_widget, + GuiButtonType button_type, + const char* text, + ButtonCallback callback, + void* context); + +/** Add Icon Element + * @param gui_widget GuiWidget instance + * @param x - x coordinate + * @param y - y coordinate + * @param icon Icon instance + */ +void gui_widget_add_icon_element(GuiWidget* gui_widget, uint8_t x, uint8_t y, const Icon* icon); diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index d970eb33..68fcf358 100755 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -22,78 +22,61 @@ void nfc_tick_event_callback(void* context) { Nfc* nfc_alloc() { Nfc* nfc = furi_alloc(sizeof(Nfc)); - nfc->nfc_common.worker = nfc_worker_alloc(); - nfc->nfc_common.view_dispatcher = view_dispatcher_alloc(); + nfc->worker = nfc_worker_alloc(); + nfc->view_dispatcher = view_dispatcher_alloc(); nfc->scene_manager = scene_manager_alloc(&nfc_scene_handlers, nfc); - view_dispatcher_enable_queue(nfc->nfc_common.view_dispatcher); - view_dispatcher_set_event_callback_context(nfc->nfc_common.view_dispatcher, nfc); - view_dispatcher_set_custom_event_callback( - nfc->nfc_common.view_dispatcher, nfc_custom_event_callback); + view_dispatcher_enable_queue(nfc->view_dispatcher); + view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc); + view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback); view_dispatcher_set_navigation_event_callback( - nfc->nfc_common.view_dispatcher, nfc_navigation_event_callback); - view_dispatcher_set_tick_event_callback( - nfc->nfc_common.view_dispatcher, nfc_tick_event_callback, 300); + nfc->view_dispatcher, nfc_navigation_event_callback); + view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100); // Open GUI record nfc->gui = furi_record_open("gui"); - view_dispatcher_attach_to_gui( - nfc->nfc_common.view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); // Open Notification record nfc->notifications = furi_record_open("notification"); // Submenu nfc->submenu = submenu_alloc(); - view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewMenu, submenu_get_view(nfc->submenu)); + view_dispatcher_add_view(nfc->view_dispatcher, NfcViewMenu, submenu_get_view(nfc->submenu)); // Dialog nfc->dialog_ex = dialog_ex_alloc(); view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewDialogEx, dialog_ex_get_view(nfc->dialog_ex)); + nfc->view_dispatcher, NfcViewDialogEx, dialog_ex_get_view(nfc->dialog_ex)); // Popup nfc->popup = popup_alloc(); - view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewPopup, popup_get_view(nfc->popup)); + view_dispatcher_add_view(nfc->view_dispatcher, NfcViewPopup, popup_get_view(nfc->popup)); // Text Input nfc->text_input = text_input_alloc(); view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewTextInput, text_input_get_view(nfc->text_input)); + nfc->view_dispatcher, NfcViewTextInput, text_input_get_view(nfc->text_input)); // Byte Input nfc->byte_input = byte_input_alloc(); view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewByteInput, byte_input_get_view(nfc->byte_input)); + nfc->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)); + nfc->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); + // Custom Widget + nfc->widget = gui_widget_alloc(); view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewDetect, nfc_detect_get_view(nfc->nfc_detect)); + nfc->view_dispatcher, NfcViewWidget, gui_widget_get_view(nfc->widget)); - // Emulate - nfc->nfc_emulate = nfc_emulate_alloc(&nfc->nfc_common); + // Bank Card + nfc->bank_card = bank_card_alloc(); view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewEmulate, nfc_emulate_get_view(nfc->nfc_emulate)); - - // EMV - nfc->nfc_emv = nfc_emv_alloc(&nfc->nfc_common); - view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, NfcViewEmv, nfc_emv_get_view(nfc->nfc_emv)); - - // Mifare Ultralight - nfc->nfc_mifare_ul = nfc_mifare_ul_alloc(&nfc->nfc_common); - view_dispatcher_add_view( - nfc->nfc_common.view_dispatcher, - NfcViewMifareUl, - nfc_mifare_ul_get_view(nfc->nfc_mifare_ul)); + nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card)); return nfc; } @@ -102,52 +85,44 @@ void nfc_free(Nfc* nfc) { furi_assert(nfc); // Submenu - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); submenu_free(nfc->submenu); // DialogEx - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDialogEx); dialog_ex_free(nfc->dialog_ex); // Popup - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewPopup); + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewPopup); popup_free(nfc->popup); // TextInput - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewTextInput); + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewTextInput); text_input_free(nfc->text_input); // ByteInput - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewByteInput); byte_input_free(nfc->byte_input); // TextBox - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewTextBox); + view_dispatcher_remove_view(nfc->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); + // Custom Widget + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); + gui_widget_free(nfc->widget); - // Emulate - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmulate); - nfc_emulate_free(nfc->nfc_emulate); - - // EMV - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmv); - nfc_emv_free(nfc->nfc_emv); - - // Mifare Ultralight - view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl); - nfc_mifare_ul_free(nfc->nfc_mifare_ul); + // Bank Card + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard); + bank_card_free(nfc->bank_card); // Worker - nfc_worker_stop(nfc->nfc_common.worker); - nfc_worker_free(nfc->nfc_common.worker); + nfc_worker_stop(nfc->worker); + nfc_worker_free(nfc->worker); // View Dispatcher - view_dispatcher_free(nfc->nfc_common.view_dispatcher); + view_dispatcher_free(nfc->view_dispatcher); // Scene Manager scene_manager_free(nfc->scene_manager); @@ -167,13 +142,13 @@ int32_t nfc_task(void* p) { Nfc* nfc = nfc_alloc(); // Check argument and run corresponding scene - if(p && nfc_device_load(&nfc->device, p)) { + if(p && nfc_device_load(&nfc->dev, p)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); } - view_dispatcher_run(nfc->nfc_common.view_dispatcher); + view_dispatcher_run(nfc->view_dispatcher); nfc_free(nfc); diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c index 6f420541..7656bd31 100755 --- a/applications/nfc/nfc_cli.c +++ b/applications/nfc/nfc_cli.c @@ -24,7 +24,7 @@ void nfc_cli_detect(Cli* cli, string_t args, void* context) { printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); while(!cmd_exit) { cmd_exit |= cli_cmd_interrupt_received(cli); - cmd_exit |= api_hal_nfc_detect(&dev_list, &dev_cnt, 200, true); + cmd_exit |= api_hal_nfc_detect(&dev_list, &dev_cnt, 400, true); if(dev_cnt > 0) { printf("Found %d devices\r\n", dev_cnt); for(uint8_t i = 0; i < dev_cnt; i++) { @@ -56,13 +56,13 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) { printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n"); printf("Press Ctrl+C to abort\r\n"); - NfcDeviceData params = { + NfcDeviceCommomData params = { .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, .uid_len = 7, .atqa = {0x44, 0x00}, .sak = 0x00, .device = NfcDeviceNfca, - .protocol = NfcDeviceProtocolMfUltralight, + .protocol = NfcDeviceProtocolMifareUl, }; while(!cli_cmd_interrupt_received(cli)) { diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index d92d0c3d..7037044a 100755 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -1,13 +1,246 @@ -#include "nfc_device.h" +#include "nfc_device_i.h" #include #include +#include #define NFC_DEVICE_MAX_DATA_LEN 14 static const char* nfc_app_folder = "nfc"; static const char* nfc_app_extension = ".nfc"; +static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) { + string_strim(str); + uint8_t nibble_high = 0; + uint8_t nibble_low = 0; + bool parsed = true; + + for(uint16_t i = 0; i < len; i++) { + if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) && + hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) { + buff[i] = (nibble_high << 4) | nibble_low; + string_right(str, 3); + } else { + parsed = false; + break; + } + } + return parsed; +} + +uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { + if(dev->format == NfcDeviceSaveFormatUid) { + string_set_str(format_string, "UID\n"); + } else if(dev->format == NfcDeviceSaveFormatBankCard) { + string_set_str(format_string, "Bank card\n"); + } else if(dev->format == NfcDeviceSaveFormatMifareUl) { + string_set_str(format_string, "Mifare Ultralight\n"); + } else { + string_set_str(format_string, "Unknown\n"); + } + return string_size(format_string); +} + +bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { + if(string_start_with_str_p(format_string, "UID")) { + dev->format = NfcDeviceSaveFormatUid; + dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; + return true; + } else if(string_start_with_str_p(format_string, "Bank card")) { + dev->format = NfcDeviceSaveFormatBankCard; + dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; + return true; + } else if(string_start_with_str_p(format_string, "Mifare Ultralight")) { + dev->format = NfcDeviceSaveFormatMifareUl; + dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; + return true; + } + return false; +} + +uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) { + NfcDeviceCommomData* uid_data = &dev->dev_data.nfc_data; + string_printf(uid_string, "UID len: %02X UID: ", dev->dev_data.nfc_data.uid_len); + for(uint8_t i = 0; i < uid_data->uid_len; i++) { + string_cat_printf(uid_string, "%02X ", uid_data->uid[i]); + } + string_cat_printf( + uid_string, + "ATQA: %02X %02X SAK: %02X\n", + uid_data->atqa[0], + uid_data->atqa[1], + uid_data->sak); + return string_size(uid_string); +} + +bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) { + NfcDeviceCommomData* uid_data = &dev->dev_data.nfc_data; + bool parsed = false; + + do { + // strlen("UID len: ") = 9 + string_right(uid_string, 9); + if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1)) { + break; + } + // strlen("UID: ") = 5 + string_right(uid_string, 5); + if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len)) { + break; + } + // strlen("ATQA: ") = 6 + string_right(uid_string, 6); + if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2)) { + break; + } + // strlen("SAK: ") = 5 + string_right(uid_string, 5); + if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1)) { + break; + } + parsed = true; + } while(0); + + return parsed; +} + +uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) { + MifareUlData* data = &dev->dev_data.mf_ul_data; + string_printf(mifare_ul_string, "Signature:"); + for(uint8_t i = 0; i < sizeof(data->signature); i++) { + string_cat_printf(mifare_ul_string, " %02X", data->signature[i]); + } + string_cat_printf(mifare_ul_string, "\nVersion:"); + uint8_t* version = (uint8_t*)&data->version; + for(uint8_t i = 0; i < sizeof(data->version); i++) { + string_cat_printf(mifare_ul_string, " %02X", version[i]); + } + for(uint8_t i = 0; i < 3; i++) { + string_cat_printf( + mifare_ul_string, + "\nCounter %d: %lu Tearing flag %d: %02X", + i, + data->counter[i], + i, + data->tearing[i]); + } + string_cat_printf(mifare_ul_string, "\nData size: %d\n", data->data_size); + for(uint16_t i = 0; i < data->data_size; i += 4) { + string_cat_printf( + mifare_ul_string, + "%02X %02X %02X %02X\n", + data->data[i], + data->data[i + 1], + data->data[i + 2], + data->data[i + 3]); + } + return string_size(mifare_ul_string); +} + +bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) { + MifareUlData* data = &dev->dev_data.mf_ul_data; + uint16_t tearing_tmp = 0; + uint16_t cnt_num = 0; + size_t ws = 0; + int res = 0; + bool parsed = false; + + do { + // strlen("Signature: ") = 11 + string_right(mifare_ul_string, 11); + if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature))) { + break; + } + // strlen("Version: ") = 9 + string_right(mifare_ul_string, 9); + if(!nfc_device_read_hex( + mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version))) { + break; + } + string_strim(mifare_ul_string); + // Read counters and tearing flags + for(uint8_t i = 0; i < 3; i++) { + res = sscanf( + string_get_cstr(mifare_ul_string), + "Counter %hX: %lu Tearing flag %hX: %02hX", + &cnt_num, + &data->counter[i], + &cnt_num, + &tearing_tmp); + if(res != 4) { + break; + } + data->tearing[i] = tearing_tmp; + ws = string_search_char(mifare_ul_string, '\n'); + string_right(mifare_ul_string, ws + 1); + } + // Read data size + res = sscanf(string_get_cstr(mifare_ul_string), "Data size: %hu", &data->data_size); + if(res != 1) { + break; + } + ws = string_search_char(mifare_ul_string, '\n'); + string_right(mifare_ul_string, ws + 1); + // Read data + for(uint16_t i = 0; i < data->data_size; i += 4) { + if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4)) { + break; + } + } + parsed = true; + } while(0); + + return parsed; +} + +uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string) { + NfcEmvData* data = &dev->dev_data.emv_data; + string_printf(bank_card_string, "AID len: %d, AID:", data->aid_len); + for(uint8_t i = 0; i < data->aid_len; i++) { + string_cat_printf(bank_card_string, " %02X", data->aid[i]); + } + string_cat_printf(bank_card_string, "\nName: %s\nNumber:", data->name); + for(uint8_t i = 0; i < sizeof(data->number); i++) { + string_cat_printf(bank_card_string, " %02X", data->number[i]); + } + return string_size(bank_card_string); +} + +bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string) { + NfcEmvData* data = &dev->dev_data.emv_data; + bool parsed = false; + int res = 0; + memset(data, 0, sizeof(NfcEmvData)); + + do { + res = sscanf(string_get_cstr(bank_card_string), "AID len: %hu", &data->aid_len); + if(res != 1) { + break; + } + // strlen("AID len: ") = 9 + string_right(bank_card_string, 9); + size_t ws = string_search_char(bank_card_string, ':'); + string_right(bank_card_string, ws + 1); + if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len)) { + break; + } + res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name); + if(res != 1) { + break; + } + ws = string_search_char(bank_card_string, '\n'); + string_right(bank_card_string, ws + 1); + // strlen("Number: ") = 8 + string_right(bank_card_string, 8); + if(!nfc_device_read_hex(bank_card_string, data->number, sizeof(data->number))) { + break; + } + parsed = true; + } while(0); + + return parsed; +} + void nfc_device_set_name(NfcDevice* dev, const char* name) { furi_assert(dev); @@ -19,37 +252,52 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { FileWorker* file_worker = file_worker_alloc(false); string_t dev_file_name; + string_init(dev_file_name); + string_t temp_str; + string_init(temp_str); + uint16_t string_len = 0; - // Create nfc directory if necessary - if(!file_worker_mkdir(file_worker, nfc_app_folder)) { - return false; - }; - - // First remove nfc device file if it was saved - string_init_printf(dev_file_name, "%s/%s%s", nfc_app_folder, dev_name, nfc_app_extension); - if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { - string_clear(dev_file_name); - return false; - }; - - // Prepare buffer to write - uint8_t buff[NFC_DEVICE_MAX_DATA_LEN]; - buff[0] = dev->data.uid_len; - memcpy(&buff[1], dev->data.uid, dev->data.uid_len); - memcpy(&buff[dev->data.uid_len + 1], dev->data.atqa, 2); - buff[dev->data.uid_len + 3] = dev->data.sak; - - // Save nfc device - bool res = file_worker_open( - file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS); - string_clear(dev_file_name); - if(res) { - // Write UID length - if(!file_worker_write_hex(file_worker, buff, dev->data.uid_len + 4)) { - file_worker_close(file_worker); - return false; + do { + // Create nfc directory if necessary + if(!file_worker_mkdir(file_worker, nfc_app_folder)) { + 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); + if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { + break; + }; + // Open file + if(!file_worker_open( + file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + break; } - } + // Prepare and write format name on 1st line + string_len = nfc_device_prepare_format_string(dev, temp_str); + if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { + break; + } + // Prepare and write UID data on 2nd line + string_len = nfc_device_prepare_uid_string(dev, temp_str); + if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { + break; + } + // Save more data if necessary + if(dev->format == NfcDeviceSaveFormatMifareUl) { + string_len = nfc_device_prepare_mifare_ul_string(dev, temp_str); + if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { + break; + } + } else if(dev->format == NfcDeviceSaveFormatBankCard) { + string_len = nfc_device_prepare_bank_card_string(dev, temp_str); + if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { + break; + } + } + } while(0); + + string_clear(temp_str); + string_clear(dev_file_name); file_worker_close(file_worker); file_worker_free(file_worker); @@ -57,34 +305,52 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { } static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) { - // Open key file - if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { - return false; - } + string_t temp_string; + string_init(temp_string); + bool parsed = false; - uint8_t buff[NFC_DEVICE_MAX_DATA_LEN] = {}; + do { + // Open key file + 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; + } + if(!nfc_device_parse_format_string(dev, temp_string)) { + break; + } + // Read and parse UID data from 2nd line + if(!file_worker_read_until(file_worker, temp_string, '\n')) { + break; + } + if(!nfc_device_parse_uid_string(dev, temp_string)) { + break; + } + // Parse other data + if(dev->format == NfcDeviceSaveFormatMifareUl) { + // Read until EOF + if(!file_worker_read_until(file_worker, temp_string, 0x05)) { + break; + } + if(!nfc_device_parse_mifare_ul_string(dev, temp_string)) { + break; + } + } else if(dev->format == NfcDeviceSaveFormatBankCard) { + // Read until EOF + if(!file_worker_read_until(file_worker, temp_string, 0x05)) { + break; + } + if(!nfc_device_parse_bank_card_string(dev, temp_string)) { + break; + } + } + parsed = true; + } while(0); - // Load first byte - UID length - if(!file_worker_read_hex(file_worker, buff, 1)) { - return false; - } - // Read space - uint8_t space = 0; - if(!file_worker_read(file_worker, &space, 1)) { - return false; - } - - // Load other data - if(!file_worker_read_hex(file_worker, &buff[1], buff[0] + 3)) { - return false; - } - - // Set loaded data - dev->data.uid_len = buff[0]; - memcpy(dev->data.uid, &buff[1], dev->data.uid_len); - memcpy(dev->data.atqa, &buff[dev->data.uid_len + 1], 2); - dev->data.sak = buff[dev->data.uid_len + 3]; - return true; + string_clear(temp_string); + return parsed; } bool nfc_device_load(NfcDevice* dev, const char* file_path) { @@ -137,3 +403,25 @@ bool nfc_file_select(NfcDevice* dev) { return res; } + +void nfc_device_clear(NfcDevice* dev) { + furi_assert(dev); + + memset(&dev->dev_data, 0, sizeof(dev->dev_data)); + nfc_device_set_name(dev, ""); + dev->format = NfcDeviceSaveFormatUid; +} + +bool nfc_device_delete(NfcDevice* dev) { + furi_assert(dev); + + bool result = false; + 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)); + string_clear(file_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 6d6486c6..ab644615 100644 --- a/applications/nfc/nfc_device.h +++ b/applications/nfc/nfc_device.h @@ -3,11 +3,11 @@ #include #include +#include "mifare_ultralight.h" + #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, @@ -18,9 +18,15 @@ typedef enum { typedef enum { NfcDeviceProtocolUnknown, NfcDeviceProtocolEMV, - NfcDeviceProtocolMfUltralight, + NfcDeviceProtocolMifareUl, } NfcProtocol; +typedef enum { + NfcDeviceSaveFormatUid, + NfcDeviceSaveFormatBankCard, + NfcDeviceSaveFormatMifareUl, +} NfcDeviceSaveFormat; + typedef struct { uint8_t uid_len; uint8_t uid[10]; @@ -28,27 +34,31 @@ typedef struct { uint8_t sak; NfcDeviceType device; NfcProtocol protocol; -} NfcDeviceData; +} NfcDeviceCommomData; typedef struct { - NfcDeviceData nfc_data; char name[32]; + uint8_t aid[16]; + uint16_t aid_len; uint8_t number[8]; + uint8_t exp_mon; + uint16_t exp_year; + char cardholder[32]; } NfcEmvData; 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; + NfcDeviceCommomData nfc_data; + union { + NfcEmvData emv_data; + MifareUlData mf_ul_data; + }; +} NfcDeviceData; typedef struct { - NfcDeviceData data; + NfcDeviceData dev_data; char dev_name[NFC_DEV_NAME_MAX_LEN]; char file_name[NFC_FILE_NAME_MAX_LEN]; + NfcDeviceSaveFormat format; } NfcDevice; void nfc_device_set_name(NfcDevice* dev, const char* name); @@ -58,3 +68,7 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name); bool nfc_device_load(NfcDevice* dev, const char* file_path); bool nfc_file_select(NfcDevice* dev); + +void nfc_device_clear(NfcDevice* dev); + +bool nfc_device_delete(NfcDevice* dev); diff --git a/applications/nfc/nfc_device_i.h b/applications/nfc/nfc_device_i.h new file mode 100644 index 00000000..01309eb5 --- /dev/null +++ b/applications/nfc/nfc_device_i.h @@ -0,0 +1,16 @@ +#pragma once + +#include "nfc_device.h" +#include + +uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string); +bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string); + +uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string); +bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string); + +uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string); +bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string); + +uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string); +bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string); \ No newline at end of file diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 94b361d9..5c89e782 100755 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -21,31 +21,27 @@ #include #include -#include +#include "views/bank_card.h" -#include "views/nfc_detect.h" -#include "views/nfc_emulate.h" -#include "views/nfc_emv.h" -#include "views/nfc_mifare_ul.h" +#include "gui_widget/gui_widget.h" +#include "gui_widget/gui_element_string.h" +#include "gui_widget/gui_element_button.h" + +#include #define NFC_TEXT_STORE_SIZE 128 struct Nfc { - NfcCommon nfc_common; + NfcWorker* worker; + ViewDispatcher* view_dispatcher; Gui* gui; NotificationApp* notifications; SceneManager* scene_manager; - NfcDevice device; + NfcDevice dev; char text_store[NFC_TEXT_STORE_SIZE + 1]; string_t text_box_store; - // Nfc Views - NfcDetect* nfc_detect; - NfcEmulate* nfc_emulate; - NfcEmv* nfc_emv; - NfcMifareUl* nfc_mifare_ul; - // Common Views Submenu* submenu; DialogEx* dialog_ex; @@ -53,6 +49,8 @@ struct Nfc { TextInput* text_input; ByteInput* byte_input; TextBox* text_box; + GuiWidget* widget; + BankCard* bank_card; }; typedef enum { @@ -62,10 +60,8 @@ typedef enum { NfcViewTextInput, NfcViewByteInput, NfcViewTextBox, - NfcViewDetect, - NfcViewEmulate, - NfcViewEmv, - NfcViewMifareUl, + NfcViewWidget, + NfcViewBankCard, } NfcView; Nfc* nfc_alloc(); diff --git a/applications/nfc/nfc_types.h b/applications/nfc/nfc_types.h index 5bf29599..46899b6d 100644 --- a/applications/nfc/nfc_types.h +++ b/applications/nfc/nfc_types.h @@ -6,25 +6,6 @@ #include #include "nfc_worker.h" -typedef struct { - NfcWorker* worker; - ViewDispatcher* view_dispatcher; - NfcWorkerResult worker_result; -} NfcCommon; - -typedef enum { - NfcEventDetect, - NfcEventEmv, - NfcEventMifareUl, -} NfcEvent; - -typedef enum { - NfcSubmenuDetect, - NfcSubmenuEmulate, - NfcSubmenuEMV, - NfcSubmenuMifareUl, -} NfcSubmenu; - static inline const char* nfc_get_dev_type(rfalNfcDevType type) { if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { return "NFC-A may be:"; @@ -62,7 +43,7 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { static inline const char* nfc_get_protocol(NfcProtocol protocol) { if(protocol == NfcDeviceProtocolEMV) { return "EMV bank card"; - } else if(protocol == NfcDeviceProtocolMfUltralight) { + } else if(protocol == NfcDeviceProtocolMifareUl) { return "Mifare Ultralight"; } else { return "Unrecognized"; diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index b23caccc..0e0003d6 100755 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -39,26 +39,21 @@ ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker) { return nfc_worker->error; } -void nfc_worker_set_emulation_params(NfcWorker* nfc_worker, NfcDeviceData* data) { - furi_assert(nfc_worker); - furi_assert(data); - - nfc_worker->emulate_params = *data; -} - void nfc_worker_start( NfcWorker* nfc_worker, NfcWorkerState state, - NfcWorkerResult* result_dest, + NfcDeviceData* dev_data, NfcWorkerCallback callback, void* context) { furi_assert(nfc_worker); - furi_assert(nfc_worker->state == NfcWorkerStateReady); - furi_assert(result_dest); + furi_assert(dev_data); + while(nfc_worker->state != NfcWorkerStateReady) { + osDelay(10); + } nfc_worker->callback = callback; nfc_worker->context = context; - nfc_worker->last_result = result_dest; + nfc_worker->dev_data = dev_data; nfc_worker_change_state(nfc_worker, state); nfc_worker->thread = osThreadNew(nfc_worker_task, nfc_worker, &nfc_worker->thread_attr); } @@ -88,12 +83,16 @@ void nfc_worker_task(void* context) { nfc_worker_detect(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateEmulate) { nfc_worker_emulate(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) { + nfc_worker_read_emv_app(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadEMV) { nfc_worker_read_emv(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateEmulateEMV) { nfc_worker_emulate_emv(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadMfUltralight) { - nfc_worker_read_mf_ultralight(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateReadMifareUl) { + nfc_worker_read_mifare_ul(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + nfc_worker_emulate_mifare_ul(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateField) { nfc_worker_field(nfc_worker); } @@ -107,7 +106,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { rfalNfcDevice* dev_list; rfalNfcDevice* dev; uint8_t dev_cnt; - NfcDeviceData* result = &nfc_worker->last_result->nfc_detect_data; + NfcDeviceCommomData* result = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateDetect) { if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { @@ -124,11 +123,12 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { dev->dev.nfca.sensRes.anticollisionInfo, dev->dev.nfca.sensRes.platformInfo, dev->dev.nfca.selRes.sak)) { - result->protocol = NfcDeviceProtocolMfUltralight; + result->protocol = NfcDeviceProtocolMifareUl; + } else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) { + result->protocol = NfcDeviceProtocolEMV; } else { result->protocol = NfcDeviceProtocolUnknown; } - } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) { result->device = NfcDeviceNfcb; } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) { @@ -147,15 +147,77 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { } void nfc_worker_emulate(NfcWorker* nfc_worker) { - NfcDeviceData* param = &nfc_worker->emulate_params; + NfcDeviceCommomData* data = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateEmulate) { - if(api_hal_nfc_listen(param->uid, param->uid_len, param->atqa, param->sak, 100)) { + if(api_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, 100)) { FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); } osDelay(10); } } +void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { + ReturnCode err; + rfalNfcDevice* dev_list; + EmvApplication emv_app = {}; + uint8_t dev_cnt = 0; + uint8_t tx_buff[255] = {}; + uint16_t tx_len = 0; + uint8_t* rx_buff; + uint16_t* rx_len; + NfcDeviceData* result = nfc_worker->dev_data; + + while(nfc_worker->state == NfcWorkerStateReadEMVApp) { + memset(&emv_app, 0, sizeof(emv_app)); + if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { + // Card was found. Check that it supports EMV + if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { + result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; + result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; + result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; + result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; + memcpy( + result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); + result->nfc_data.protocol = NfcDeviceProtocolEMV; + + FURI_LOG_I(NFC_WORKER_TAG, "Send select PPSE command"); + tx_len = emv_prepare_select_ppse(tx_buff); + err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); + if(err != ERR_NONE) { + FURI_LOG_E(NFC_WORKER_TAG, "Error during selection PPSE request: %d", err); + api_hal_nfc_deactivate(); + continue; + } + FURI_LOG_I( + NFC_WORKER_TAG, "Select PPSE response received. Start parsing response"); + if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { + FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced"); + // Notify caller and exit + result->emv_data.aid_len = emv_app.aid_len; + memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); + if(nfc_worker->callback) { + nfc_worker->callback(nfc_worker->context); + } + break; + } else { + FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); + api_hal_nfc_deactivate(); + continue; + } + } else { + // Can't find EMV card + FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV"); + api_hal_nfc_deactivate(); + } + } else { + // Can't find EMV card + FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards"); + api_hal_nfc_deactivate(); + } + osDelay(20); + } +} + void nfc_worker_read_emv(NfcWorker* nfc_worker) { ReturnCode err; rfalNfcDevice* dev_list; @@ -165,13 +227,21 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { uint16_t tx_len = 0; uint8_t* rx_buff; uint16_t* rx_len; - NfcEmvData* result = &nfc_worker->last_result->nfc_emv_data; + NfcDeviceData* result = nfc_worker->dev_data; while(nfc_worker->state == NfcWorkerStateReadEMV) { memset(&emv_app, 0, sizeof(emv_app)); if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { // Card was found. Check that it supports EMV if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { + result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; + result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; + result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; + result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; + memcpy( + result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); + result->nfc_data.protocol = NfcDeviceProtocolEMV; + FURI_LOG_I(NFC_WORKER_TAG, "Send select PPSE command"); tx_len = emv_prepare_select_ppse(tx_buff); err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); @@ -203,7 +273,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { "Select application response received. Start parsing response"); if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { FURI_LOG_I(NFC_WORKER_TAG, "Card name: %s", emv_app.name); - memcpy(result->name, emv_app.name, sizeof(emv_app.name)); + memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); } else { FURI_LOG_E(NFC_WORKER_TAG, "Can't read card name"); api_hal_nfc_deactivate(); @@ -220,7 +290,8 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { } if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed"); - memcpy(result->number, emv_app.card_number, sizeof(emv_app.card_number)); + memcpy( + result->emv_data.number, emv_app.card_number, sizeof(emv_app.card_number)); // Notify caller and exit if(nfc_worker->callback) { nfc_worker->callback(nfc_worker->context); @@ -255,7 +326,10 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { } if(pan_found) { FURI_LOG_I(NFC_WORKER_TAG, "Card PAN found"); - memcpy(result->number, emv_app.card_number, sizeof(emv_app.card_number)); + memcpy( + result->emv_data.number, + emv_app.card_number, + sizeof(emv_app.card_number)); // Notify caller and exit if(nfc_worker->callback) { nfc_worker->callback(nfc_worker->context); @@ -286,7 +360,7 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) { uint16_t tx_len = 0; uint8_t* rx_buff; uint16_t* rx_len; - NfcDeviceData params = { + NfcDeviceCommomData params = { .uid = {0xCF, 0x72, 0xd4, 0x40}, .uid_len = 4, .atqa = {0x00, 0x04}, @@ -343,7 +417,7 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) { } } -void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { +void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { ReturnCode err; rfalNfcDevice* dev_list; uint8_t dev_cnt = 0; @@ -351,21 +425,20 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { uint16_t tx_len = 0; uint8_t* rx_buff; uint16_t* rx_len; - MfUltralightRead mf_ul_read; - NfcMifareUlData* result = &nfc_worker->last_result->nfc_mifare_ul_data; + MifareUlDevice mf_ul_read; + NfcDeviceData* result = nfc_worker->dev_data; - while(nfc_worker->state == NfcWorkerStateReadMfUltralight) { + while(nfc_worker->state == NfcWorkerStateReadMifareUl) { api_hal_nfc_deactivate(); memset(&mf_ul_read, 0, sizeof(mf_ul_read)); - if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { + if(api_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA && mf_ul_check_card_type( dev_list[0].dev.nfca.sensRes.anticollisionInfo, dev_list[0].dev.nfca.sensRes.platformInfo, dev_list[0].dev.nfca.selRes.sak)) { // Get Mifare Ultralight version - FURI_LOG_I( - NFC_WORKER_TAG, "Found Mifare Ultralight tag. Trying to get tag version"); + FURI_LOG_I(NFC_WORKER_TAG, "Found Mifare Ultralight tag. Reading tag version"); tx_len = mf_ul_prepare_get_version(tx_buff); err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); if(err == ERR_NONE) { @@ -378,7 +451,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { } else if(err == ERR_TIMEOUT) { FURI_LOG_W( NFC_WORKER_TAG, - "Card doesn't respond to GET VERSION command. Reinit card and set default read parameters"); + "Card doesn't respond to GET VERSION command. Setting default read parameters"); err = ERR_NONE; mf_ul_set_default_version(&mf_ul_read); // Reinit device @@ -395,37 +468,58 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { continue; } - // Dump Mifare Ultralight card - FURI_LOG_I(NFC_WORKER_TAG, "Trying to read pages"); if(mf_ul_read.support_fast_read) { - // Read card with FAST_READ command + FURI_LOG_I(NFC_WORKER_TAG, "Reading pages ..."); tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1); - err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_I( - NFC_WORKER_TAG, - "Fast read pages %d - %d succeed", - 0, - mf_ul_read.pages_to_read - 1); - memcpy(mf_ul_read.dump, rx_buff, mf_ul_read.pages_to_read * 4); - mf_ul_read.pages_readed = mf_ul_read.pages_to_read; - } else { - FURI_LOG_E(NFC_WORKER_TAG, "Fast read failed"); + if(api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { + FURI_LOG_E(NFC_WORKER_TAG, "Failed reading pages"); continue; + } else { + mf_ul_parse_fast_read_response( + rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read); + } + + FURI_LOG_I(NFC_WORKER_TAG, "Reading signature ..."); + tx_len = mf_ul_prepare_read_signature(tx_buff); + if(api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { + FURI_LOG_W(NFC_WORKER_TAG, "Failed reading signature"); + memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature)); + } else { + mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read); + } + + FURI_LOG_I(NFC_WORKER_TAG, "Reading 3 counters ..."); + for(uint8_t i = 0; i < 3; i++) { + tx_len = mf_ul_prepare_read_cnt(tx_buff, i); + if(api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { + FURI_LOG_W(NFC_WORKER_TAG, "Failed reading Counter %d", i); + mf_ul_read.data.counter[i] = 0; + } else { + mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read); + } + } + + FURI_LOG_I(NFC_WORKER_TAG, "Checking tearing flags ..."); + for(uint8_t i = 0; i < 3; i++) { + tx_len = mf_ul_prepare_check_tearing(tx_buff, i); + if(api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { + FURI_LOG_E(NFC_WORKER_TAG, "Error checking tearing flag %d", i); + mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT; + } else { + mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read); + } } } else { // READ card with READ command (4 pages at a time) for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) { + FURI_LOG_I(NFC_WORKER_TAG, "Reading pages %d - %d ...", page, page + 3); tx_len = mf_ul_prepare_read(tx_buff, page); - err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_I( - NFC_WORKER_TAG, "Read pages %d - %d succeed", page, page + 3); - memcpy(&mf_ul_read.dump[page * 4], rx_buff, 4 * 4); - mf_ul_read.pages_readed += 4; - } else { - FURI_LOG_W( + if(api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { + FURI_LOG_E( NFC_WORKER_TAG, "Read pages %d - %d failed", page, page + 3); + continue; + } else { + mf_ul_parse_read_response(rx_buff, page, &mf_ul_read); } } } @@ -435,20 +529,11 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; + result->nfc_data.protocol = NfcDeviceProtocolMifareUl; memcpy( 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); + result->mf_ul_data = mf_ul_read.data; - 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++) { - printf("%02X ", mf_ul_read.dump[i + j]); - } - printf("\r\n"); - } // Notify caller and exit if(nfc_worker->callback) { nfc_worker->callback(nfc_worker->context); @@ -464,6 +549,43 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { } } +void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { + ReturnCode err; + uint8_t tx_buff[255] = {}; + uint16_t tx_len = 0; + uint8_t* rx_buff; + uint16_t* rx_len; + NfcDeviceData* data = nfc_worker->dev_data; + + while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + if(api_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 = api_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]); + } + printf("\r\n"); + } else { + FURI_LOG_E(NFC_WORKER_TAG, "Error in 1st data exchange: select PPSE"); + api_hal_nfc_deactivate(); + continue; + } + } + FURI_LOG_W(NFC_WORKER_TAG, "Hello my dudes"); + osDelay(10); + } +} + void nfc_worker_field(NfcWorker* nfc_worker) { api_hal_nfc_field_on(); while(nfc_worker->state == NfcWorkerStateField) { diff --git a/applications/nfc/nfc_worker.h b/applications/nfc/nfc_worker.h index d77bfd8d..7109e5f8 100755 --- a/applications/nfc/nfc_worker.h +++ b/applications/nfc/nfc_worker.h @@ -2,14 +2,6 @@ #include "nfc_device.h" -typedef struct { - union { - NfcDeviceData nfc_detect_data; - NfcEmvData nfc_emv_data; - NfcMifareUlData nfc_mifare_ul_data; - }; -} NfcWorkerResult; - typedef struct NfcWorker NfcWorker; typedef enum { @@ -20,10 +12,12 @@ typedef enum { // Main worker states NfcWorkerStateDetect, NfcWorkerStateEmulate, + NfcWorkerStateReadEMVApp, NfcWorkerStateReadEMV, NfcWorkerStateEmulateEMV, NfcWorkerStateField, - NfcWorkerStateReadMfUltralight, + NfcWorkerStateReadMifareUl, + NfcWorkerStateEmulateMifareUl, // Transition NfcWorkerStateStop, } NfcWorkerState; @@ -36,14 +30,12 @@ NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker); ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker); -void nfc_worker_set_emulation_params(NfcWorker* nfc_worker, NfcDeviceData* data); - void nfc_worker_free(NfcWorker* nfc_worker); void nfc_worker_start( NfcWorker* nfc_worker, NfcWorkerState state, - NfcWorkerResult* result_dest, + NfcDeviceData* dev_data, NfcWorkerCallback callback, void* context); diff --git a/applications/nfc/nfc_worker_i.h b/applications/nfc/nfc_worker_i.h old mode 100644 new mode 100755 index 7bb10155..00d5e454 --- a/applications/nfc/nfc_worker_i.h +++ b/applications/nfc/nfc_worker_i.h @@ -20,10 +20,10 @@ struct NfcWorker { osThreadAttr_t thread_attr; osThreadId_t thread; - NfcWorkerResult* last_result; + NfcDeviceData* dev_data; + NfcWorkerCallback callback; void* context; - NfcDeviceData emulate_params; NfcWorkerState state; ReturnCode error; @@ -33,6 +33,8 @@ void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state); void nfc_worker_task(void* context); +void nfc_worker_read_emv_app(NfcWorker* nfc_worker); + void nfc_worker_read_emv(NfcWorker* nfc_worker); void nfc_worker_emulate_emv(NfcWorker* nfc_worker); @@ -43,4 +45,6 @@ void nfc_worker_emulate(NfcWorker* nfc_worker); void nfc_worker_field(NfcWorker* nfc_worker); -void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker); +void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker); + +void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker); diff --git a/applications/nfc/scenes/nfc_scene_card_menu.c b/applications/nfc/scenes/nfc_scene_card_menu.c index 76e36de6..f69e0838 100755 --- a/applications/nfc/scenes/nfc_scene_card_menu.c +++ b/applications/nfc/scenes/nfc_scene_card_menu.c @@ -10,19 +10,21 @@ enum SubmenuIndex { void nfc_scene_card_menu_submenu_callback(void* context, uint32_t index) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } const void nfc_scene_card_menu_on_enter(void* context) { Nfc* nfc = (Nfc*)context; Submenu* submenu = nfc->submenu; - submenu_add_item( - submenu, - "Run compatible app", - SubmenuIndexRunApp, - nfc_scene_card_menu_submenu_callback, - nfc); + if(nfc->dev.dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) { + submenu_add_item( + submenu, + "Run compatible app", + SubmenuIndexRunApp, + nfc_scene_card_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Additional reading scripts", @@ -36,7 +38,7 @@ const void nfc_scene_card_menu_on_enter(void* context) { submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneCardMenu)); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { @@ -46,12 +48,16 @@ const bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) if(event.event == SubmenuIndexRunApp) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); + } else if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); + } return true; } else if(event.event == SubmenuIndexChooseScript) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexChooseScript); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu); return true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( @@ -60,6 +66,7 @@ const bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) return true; } else if(event.event == SubmenuIndexSave) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave); + nfc->dev.format = NfcDeviceSaveFormatUid; scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); return true; } diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 4ad3637f..385b84a3 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -16,8 +16,12 @@ ADD_SCENE(nfc, scripts_menu, ScriptsMenu) ADD_SCENE(nfc, read_mifare_ul, ReadMifareUl) ADD_SCENE(nfc, read_mifare_ul_success, ReadMifareUlSuccess) ADD_SCENE(nfc, mifare_ul_menu, MifareUlMenu) -ADD_SCENE(nfc, debug_menu, DebugMenu) -ADD_SCENE(nfc, debug_detect, DebugDetect) -ADD_SCENE(nfc, debug_emulate, DebugEmulate) -ADD_SCENE(nfc, debug_read_emv, DebugReadEmv) -ADD_SCENE(nfc, debug_read_mifare_ul, DebugReadMifareUl) +ADD_SCENE(nfc, emulate_mifare_ul, EmulateMifareUl) +ADD_SCENE(nfc, read_emv_app, ReadEmvApp) +ADD_SCENE(nfc, read_emv_app_success, ReadEmvAppSuccess) +ADD_SCENE(nfc, device_info, DeviceInfo) +ADD_SCENE(nfc, delete, Delete) +ADD_SCENE(nfc, delete_success, DeleteSuccess) +ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm) +ADD_SCENE(nfc, read_emv_data, ReadEmvData) +ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess) diff --git a/applications/nfc/scenes/nfc_scene_debug_detect.c b/applications/nfc/scenes/nfc_scene_debug_detect.c deleted file mode 100755 index 650ffec5..00000000 --- a/applications/nfc/scenes/nfc_scene_debug_detect.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "../nfc_i.h" - -const void nfc_scene_debug_detect_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); -} - -const bool nfc_scene_debug_detect_on_event(void* context, SceneManagerEvent event) { - return false; -} - -const void nfc_scene_debug_detect_on_exit(void* context) { -} diff --git a/applications/nfc/scenes/nfc_scene_debug_emulate.c b/applications/nfc/scenes/nfc_scene_debug_emulate.c deleted file mode 100755 index ab15ed68..00000000 --- a/applications/nfc/scenes/nfc_scene_debug_emulate.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "../nfc_i.h" - -const void nfc_scene_debug_emulate_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewEmulate); -} - -const bool nfc_scene_debug_emulate_on_event(void* context, SceneManagerEvent event) { - return false; -} - -const void nfc_scene_debug_emulate_on_exit(void* context) { -} diff --git a/applications/nfc/scenes/nfc_scene_debug_menu.c b/applications/nfc/scenes/nfc_scene_debug_menu.c deleted file mode 100755 index ec8737d6..00000000 --- a/applications/nfc/scenes/nfc_scene_debug_menu.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "../nfc_i.h" - -enum SubmenuIndex { - SubmenuIndexDetect, - SubmenuIndexEmulate, - SubmenuIndexReadEmv, - SubmenuIndexReadMifareUl, -}; - -void nfc_scene_debug_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_debug_menu_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Detect", SubmenuIndexDetect, nfc_scene_debug_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_debug_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Read EMV", SubmenuIndexReadEmv, nfc_scene_debug_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Read Mifare Ultralight", - SubmenuIndexReadMifareUl, - nfc_scene_debug_menu_submenu_callback, - nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDebugMenu)); - - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); -} - -const bool nfc_scene_debug_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexDetect) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDebugMenu, SubmenuIndexDetect); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDebugDetect); - return true; - } else if(event.event == SubmenuIndexEmulate) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDebugMenu, SubmenuIndexEmulate); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDebugEmulate); - return true; - } else if(event.event == SubmenuIndexReadEmv) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDebugMenu, SubmenuIndexReadEmv); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDebugReadEmv); - return true; - } else if(event.event == SubmenuIndexReadMifareUl) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDebugMenu, SubmenuIndexReadMifareUl); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDebugReadMifareUl); - return true; - } - } - - return false; -} - -const void nfc_scene_debug_menu_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; - - submenu_clean(nfc->submenu); -} diff --git a/applications/nfc/scenes/nfc_scene_debug_read_emv.c b/applications/nfc/scenes/nfc_scene_debug_read_emv.c deleted file mode 100755 index 5d6fba8b..00000000 --- a/applications/nfc/scenes/nfc_scene_debug_read_emv.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "../nfc_i.h" - -const void nfc_scene_debug_read_emv_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewEmv); -} - -const bool nfc_scene_debug_read_emv_on_event(void* context, SceneManagerEvent event) { - return false; -} - -const void nfc_scene_debug_read_emv_on_exit(void* context) { -} diff --git a/applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.c b/applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.c deleted file mode 100755 index e08c843e..00000000 --- a/applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "../nfc_i.h" - -const void nfc_scene_debug_read_mifare_ul_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl); -} - -const bool nfc_scene_debug_read_mifare_ul_on_event(void* context, SceneManagerEvent event) { - return false; -} - -const void nfc_scene_debug_read_mifare_ul_on_exit(void* context) { -} diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c new file mode 100644 index 00000000..0517a8fa --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_delete.c @@ -0,0 +1,95 @@ +#include "../nfc_i.h" + +void nfc_scene_delete_widget_callback(GuiButtonType result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_delete_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup Custom Widget view + char delete_str[64]; + snprintf(delete_str, sizeof(delete_str), "Delete %s", nfc->dev.dev_name); + gui_widget_add_string_element( + nfc->widget, 64, 6, AlignCenter, AlignTop, FontPrimary, delete_str); + gui_widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); + gui_widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); + char uid_str[32]; + NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; + if(data->uid_len == 4) { + snprintf( + uid_str, + sizeof(uid_str), + "UID: %02X %02X %02X %02X", + data->uid[0], + data->uid[1], + data->uid[2], + data->uid[3]); + } else if(data->uid_len == 7) { + snprintf( + uid_str, + sizeof(uid_str), + "UID: %02X %02X %02X %02X %02X %02X %02X", + data->uid[0], + data->uid[1], + data->uid[2], + data->uid[3], + data->uid[4], + data->uid[5], + data->uid[6]); + } + gui_widget_add_string_element( + nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); + + if(data->protocol > NfcDeviceProtocolUnknown) { + gui_widget_add_string_element( + nfc->widget, + 10, + 32, + AlignLeft, + AlignTop, + FontSecondary, + nfc_get_protocol(data->protocol)); + } + // TODO change dinamically + gui_widget_add_string_element( + nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); + char sak_str[16]; + snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); + gui_widget_add_string_element( + nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str); + char atqa_str[16]; + snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); + gui_widget_add_string_element( + nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +const bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + return scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + if(nfc_device_delete(&nfc->dev)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart); + } + return true; + } + } + return false; +} + +const void nfc_scene_delete_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + gui_widget_clear(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_delete_success.c b/applications/nfc/scenes/nfc_scene_delete_success.c new file mode 100644 index 00000000..592a16c6 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_delete_success.c @@ -0,0 +1,47 @@ +#include "../nfc_i.h" + +#define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL) + +void nfc_scene_delete_success_popup_callback(void* context) { + Nfc* nfc = (Nfc*)context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SAVE_SUCCESS_CUSTOM_EVENT); +} + +const void nfc_scene_delete_success_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_delete_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +const bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) { + return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart); + } + } + return false; +} + +const void nfc_scene_delete_success_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_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c new file mode 100755 index 00000000..afb65ea1 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -0,0 +1,185 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT (0UL) + +enum { + NfcSceneDeviceInfoUid, + NfcSceneDeviceInfoData, +}; + +void nfc_scene_device_info_widget_callback(GuiButtonType result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_device_info_text_box_callback(void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event( + nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT); +} + +void nfc_scene_device_info_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup Custom Widget view + gui_widget_add_string_element( + nfc->widget, 64, 6, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_name); + gui_widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); + gui_widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); + char uid_str[32]; + NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; + if(data->uid_len == 4) { + snprintf( + uid_str, + sizeof(uid_str), + "UID: %02X %02X %02X %02X", + data->uid[0], + data->uid[1], + data->uid[2], + data->uid[3]); + } else if(data->uid_len == 7) { + snprintf( + uid_str, + sizeof(uid_str), + "UID: %02X %02X %02X %02X %02X %02X %02X", + data->uid[0], + data->uid[1], + data->uid[2], + data->uid[3], + data->uid[4], + data->uid[5], + data->uid[6]); + } + gui_widget_add_string_element( + nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); + + if(data->protocol > NfcDeviceProtocolUnknown) { + gui_widget_add_string_element( + nfc->widget, + 10, + 32, + AlignLeft, + AlignTop, + FontSecondary, + nfc_get_protocol(data->protocol)); + } + // TODO change dinamically + gui_widget_add_string_element( + nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); + char sak_str[16]; + snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); + gui_widget_add_string_element( + nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str); + char atqa_str[16]; + snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); + gui_widget_add_string_element( + nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str); + + // Setup Data View + if(nfc->dev.format == NfcDeviceSaveFormatUid) { + DialogEx* dialog_ex = nfc->dialog_ex; + dialog_ex_set_left_button_text(dialog_ex, "Back"); + dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); + } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { + MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data; + TextBox* text_box = nfc->text_box; + text_box_set_context(text_box, nfc); + text_box_set_exit_callback(text_box, nfc_scene_device_info_text_box_callback); + text_box_set_font(text_box, TextBoxFontHex); + for(uint16_t i = 0; i < mf_ul_data->data_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->data[i], mf_ul_data->data[i + 1]); + } + text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); + } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { + NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; + BankCard* bank_card = nfc->bank_card; + bank_card_set_name(bank_card, emv_data->name); + bank_card_set_number(bank_card, emv_data->number); + if(!strcmp(emv_data->name, "")) { + bank_card_set_cardholder_name(bank_card, emv_data->cardholder); + } + if(emv_data->exp_mon) { + bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); + } + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +const bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + bool consumed = false; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo); + + if(event.type == SceneManagerEventTypeCustom) { + if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) { + if(nfc->dev.format == NfcDeviceSaveFormatUid) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); + consumed = true; + } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + consumed = true; + } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); + consumed = true; + } + } else if(state == NfcSceneDeviceInfoData) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + consumed = true; + } + } + return consumed; +} + +const void nfc_scene_device_info_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + // Clear Custom Widget + gui_widget_clear(nfc->widget); + + if(nfc->dev.format == NfcDeviceSaveFormatUid) { + // Clear 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); + } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { + // Clear TextBox + text_box_clean(nfc->text_box); + string_clean(nfc->text_box_store); + } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { + // Clear Bank Card + bank_card_clear(nfc->bank_card); + } +} diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c new file mode 100755 index 00000000..7286b7ac --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c @@ -0,0 +1,60 @@ +#include "../nfc_i.h" + +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); + + // 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); +} + +const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + notification_message(nfc->notifications, &sequence_blink_blue_10); + consumed = true; + } + return consumed; +} + +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); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); +} diff --git a/applications/nfc/scenes/nfc_scene_emulate_uid.c b/applications/nfc/scenes/nfc_scene_emulate_uid.c old mode 100644 new mode 100755 index 8c1ed018..faaf9c7e --- a/applications/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/nfc/scenes/nfc_scene_emulate_uid.c @@ -5,10 +5,10 @@ const void nfc_scene_emulate_uid_on_enter(void* context) { // Setup view Popup* popup = nfc->popup; - NfcDeviceData* data = &nfc->device.data; + NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; - if(strcmp(nfc->device.dev_name, "")) { - nfc_text_store_set(nfc, "%s", nfc->device.dev_name); + 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]); @@ -31,10 +31,8 @@ const void nfc_scene_emulate_uid_on_enter(void* context) { // Setup and start worker - nfc_worker_set_emulation_params(nfc->nfc_common.worker, data); - nfc_worker_start( - nfc->nfc_common.worker, NfcWorkerStateEmulate, &nfc->nfc_common.worker_result, NULL, nfc); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewPopup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev.dev_data, NULL, nfc); } const bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { @@ -51,7 +49,7 @@ const void nfc_scene_emulate_uid_on_exit(void* context) { Nfc* nfc = (Nfc*)context; // Stop worker - nfc_worker_stop(nfc->nfc_common.worker); + nfc_worker_stop(nfc->worker); // Clear view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_file_select.c b/applications/nfc/scenes/nfc_scene_file_select.c index a74c18ed..f8af371f 100755 --- a/applications/nfc/scenes/nfc_scene_file_select.c +++ b/applications/nfc/scenes/nfc_scene_file_select.c @@ -3,7 +3,7 @@ const void nfc_scene_file_select_on_enter(void* context) { Nfc* nfc = (Nfc*)context; // Process file_select return - if(nfc_file_select(&nfc->device)) { + if(nfc_file_select(&nfc->dev)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); } else { scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c index a2121cad..bc639db9 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c @@ -8,7 +8,7 @@ enum SubmenuIndex { 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); + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } const void nfc_scene_mifare_ul_menu_on_enter(void* context) { @@ -22,7 +22,7 @@ const void nfc_scene_mifare_ul_menu_on_enter(void* context) { submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu)); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { @@ -32,7 +32,8 @@ const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent ev if(event.event == SubmenuIndexSave) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + nfc->dev.format = NfcDeviceSaveFormatMifareUl; + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); return true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( diff --git a/applications/nfc/scenes/nfc_scene_not_implemented.c b/applications/nfc/scenes/nfc_scene_not_implemented.c index ece75c97..f23bbe4a 100644 --- a/applications/nfc/scenes/nfc_scene_not_implemented.c +++ b/applications/nfc/scenes/nfc_scene_not_implemented.c @@ -3,7 +3,7 @@ void nfc_scene_not_implemented_dialog_callback(DialogExResult result, void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, result); + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } const void nfc_scene_not_implemented_on_enter(void* context) { @@ -16,7 +16,7 @@ const void nfc_scene_not_implemented_on_enter(void* context) { dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_not_implemented_dialog_callback); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } const bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_read_card.c b/applications/nfc/scenes/nfc_scene_read_card.c index aaf9e5b8..4b32c36d 100755 --- a/applications/nfc/scenes/nfc_scene_read_card.c +++ b/applications/nfc/scenes/nfc_scene_read_card.c @@ -1,8 +1,10 @@ #include "../nfc_i.h" +#define NFC_READ_CARD_CUSTOM_EVENT (0UL) + void nfc_read_card_worker_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, NfcEventDetect); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_CARD_CUSTOM_EVENT); } const void nfc_scene_read_card_on_enter(void* context) { @@ -14,21 +16,16 @@ const void nfc_scene_read_card_on_enter(void* context) { popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); // Start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start( - nfc->nfc_common.worker, - NfcWorkerStateDetect, - &nfc->nfc_common.worker_result, - nfc_read_card_worker_callback, - nfc); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewPopup); + nfc->worker, NfcWorkerStateDetect, &nfc->dev.dev_data, nfc_read_card_worker_callback, nfc); } const bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = (Nfc*)context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcEventDetect) { - nfc->device.data = nfc->nfc_common.worker_result.nfc_detect_data; + if(event.event == NFC_READ_CARD_CUSTOM_EVENT) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); return true; } @@ -43,7 +40,7 @@ const void nfc_scene_read_card_on_exit(void* context) { Nfc* nfc = (Nfc*)context; // Stop worker - nfc_worker_stop(nfc->nfc_common.worker); + nfc_worker_stop(nfc->worker); // Clear view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index 3e841df3..42d5cbee 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -5,20 +5,20 @@ void nfc_scene_read_card_success_dialog_callback(DialogExResult result, void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, result); + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } -const void nfc_scene_read_card_success_on_enter(void* context) { +void nfc_scene_read_card_success_on_enter(void* context) { Nfc* nfc = (Nfc*)context; // Clear device name - nfc_device_set_name(&nfc->device, ""); + nfc_device_set_name(&nfc->dev, ""); // Send notification notification_message(nfc->notifications, &sequence_success); // Setup view - NfcDeviceData* data = (NfcDeviceData*)&nfc->nfc_common.worker_result; + NfcDeviceCommomData* data = (NfcDeviceCommomData*)&nfc->dev.dev_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"); @@ -60,7 +60,7 @@ const void nfc_scene_read_card_success_on_enter(void* context) { dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_card_success_dialog_callback); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } const bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app.c b/applications/nfc/scenes/nfc_scene_read_emv_app.c new file mode 100755 index 00000000..ae00431b --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_emv_app.c @@ -0,0 +1,54 @@ +#include "../nfc_i.h" + +#define NFC_READ_EMV_APP_CUSTOM_EVENT (0UL) + +void nfc_read_emv_app_worker_callback(void* context) { + Nfc* nfc = (Nfc*)context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_EMV_APP_CUSTOM_EVENT); +} + +const void nfc_scene_read_emv_app_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateReadEMVApp, + &nfc->dev.dev_data, + nfc_read_emv_app_worker_callback, + nfc); +} + +const bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NFC_READ_EMV_APP_CUSTOM_EVENT) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); + return true; + } + } else if(event.type == SceneManagerEventTypeTick) { + notification_message(nfc->notifications, &sequence_blink_blue_10); + return true; + } + return false; +} + +const void nfc_scene_read_emv_app_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); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); +} diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c new file mode 100755 index 00000000..631b0456 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c @@ -0,0 +1,69 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_READ_SUCCESS_SHIFT " " + +void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_read_emv_app_success_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + NfcDeviceCommomData* nfc_data = &nfc->dev.dev_data.nfc_data; + NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; + DialogEx* dialog_ex = nfc->dialog_ex; + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "Run app"); + dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter); + dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); + // Display UID and AID + string_t aid; + string_init_printf(aid, "AID:"); + for(uint8_t i = 0; i < emv_data->aid_len; i++) { + string_cat_printf(aid, " %02X", emv_data->aid[i]); + } + nfc_text_store_set( + nfc, + NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n\n%s", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + string_get_cstr(aid)); + string_clear(aid); + 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_emv_app_success_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +const bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + return scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm); + return true; + } + } + return false; +} + +const void nfc_scene_read_emv_app_success_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + 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_result_callback(dialog_ex, NULL); + dialog_ex_set_context(dialog_ex, NULL); +} diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data.c b/applications/nfc/scenes/nfc_scene_read_emv_data.c new file mode 100644 index 00000000..38c5008e --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_emv_data.c @@ -0,0 +1,57 @@ +#include "../nfc_i.h" + +#define NFC_READ_EMV_DATA_CUSTOM_EVENT (0UL) + +void nfc_read_emv_data_worker_callback(void* context) { + Nfc* nfc = (Nfc*)context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_EMV_DATA_CUSTOM_EVENT); +} + +const void nfc_scene_read_emv_data_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateReadEMV, + &nfc->dev.dev_data, + nfc_read_emv_data_worker_callback, + nfc); +} + +const bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NFC_READ_EMV_DATA_CUSTOM_EVENT) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); + return true; + } + } else if(event.type == SceneManagerEventTypeTick) { + notification_message(nfc->notifications, &sequence_blink_blue_10); + return true; + } + return false; +} + +const void nfc_scene_read_emv_data_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Send notification + notification_message(nfc->notifications, &sequence_success); + + // 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); +} diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c new file mode 100755 index 00000000..f8f37f7a --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c @@ -0,0 +1,89 @@ +#include "../nfc_i.h" + +void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_read_emv_data_success_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; + NfcDeviceCommomData* nfc_data = &nfc->dev.dev_data.nfc_data; + + // Clear device name + nfc_device_set_name(&nfc->dev, ""); + + // Setup Custom Widget view + gui_widget_add_button_element( + nfc->widget, + GuiButtonTypeLeft, + "Back", + nfc_scene_read_emv_data_success_widget_callback, + nfc); + gui_widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "Save", + nfc_scene_read_emv_data_success_widget_callback, + nfc); + gui_widget_add_string_element( + nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name); + char pan_str[32]; + snprintf( + pan_str, + sizeof(pan_str), + "%02X%02X %02X%02X %02X%02X %02X%02X", + emv_data->number[0], + emv_data->number[1], + emv_data->number[2], + emv_data->number[3], + emv_data->number[4], + emv_data->number[5], + emv_data->number[6], + emv_data->number[7]); + gui_widget_add_string_element( + nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, pan_str); + char atqa_str[16]; + snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); + gui_widget_add_string_element( + nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str); + char uid_str[32]; + snprintf( + uid_str, + sizeof(uid_str), + "UID: %02X %02X %02X %02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3]); + gui_widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str); + char sak_str[16]; + snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak); + gui_widget_add_string_element( + nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +const bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + return scene_manager_search_previous_scene( + nfc->scene_manager, NfcSceneReadEmvAppSuccess); + } else if(event.event == GuiButtonTypeRight) { + nfc->dev.format = NfcDeviceSaveFormatBankCard; + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + return true; + } + } + return false; +} + +const void nfc_scene_read_emv_data_success_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + gui_widget_clear(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c index 90367a77..d1997d51 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c @@ -1,8 +1,10 @@ #include "../nfc_i.h" +#define NFC_READ_MIFARE_UL_CUSTOM_EVENT (0UL) + void nfc_read_mifare_ul_worker_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, NfcEventMifareUl); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_MIFARE_UL_CUSTOM_EVENT); } const void nfc_scene_read_mifare_ul_on_enter(void* context) { @@ -13,22 +15,21 @@ const void nfc_scene_read_mifare_ul_on_enter(void* context) { popup_set_header(popup, "Detecting\nultralight", 70, 34, AlignLeft, AlignTop); popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); // Start worker nfc_worker_start( - nfc->nfc_common.worker, - NfcWorkerStateReadMfUltralight, - &nfc->nfc_common.worker_result, + nfc->worker, + NfcWorkerStateReadMifareUl, + &nfc->dev.dev_data, 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, SceneManagerEvent event) { Nfc* nfc = (Nfc*)context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcEventMifareUl) { - nfc->device.data = nfc->nfc_common.worker_result.nfc_detect_data; + if(event.event == NFC_READ_MIFARE_UL_CUSTOM_EVENT) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess); return true; } @@ -43,7 +44,7 @@ const void nfc_scene_read_mifare_ul_on_exit(void* context) { Nfc* nfc = (Nfc*)context; // Stop worker - nfc_worker_stop(nfc->nfc_common.worker); + nfc_worker_stop(nfc->worker); // Clear view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index 7303fd09..caf9f5b5 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -11,28 +11,26 @@ enum { 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); + view_dispatcher_send_custom_event(nfc->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); + view_dispatcher_send_custom_event(nfc->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, ""); + nfc_device_set_name(&nfc->dev, ""); // 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; + NfcDeviceCommomData* data = (NfcDeviceCommomData*)&nfc->dev.dev_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"); @@ -59,27 +57,23 @@ const void nfc_scene_read_mifare_ul_success_on_enter(void* context) { 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; + MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_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) { + for(uint16_t i = 0; i < mf_ul_data->data_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]); + nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); } text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } const bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) { @@ -101,7 +95,7 @@ const bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManager (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) == ReadMifareUlStateShowUID) && (event.event == DialogExResultCenter)) { - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewTextBox); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData); return true; @@ -109,7 +103,7 @@ const bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManager (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) == ReadMifareUlStateShowData) && (event.event == NFC_SCENE_READ_MF_UL_CUSTOM_EVENT)) { - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID); return true; diff --git a/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c b/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c new file mode 100755 index 00000000..609ccfc5 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c @@ -0,0 +1,56 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_READ_SUCCESS_SHIFT " " + +void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = (Nfc*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_run_emv_app_confirm_on_enter(void* context) { + Nfc* nfc = (Nfc*)context; + + DialogEx* dialog_ex = nfc->dialog_ex; + dialog_ex_set_left_button_text(dialog_ex, "Back"); + dialog_ex_set_right_button_text(dialog_ex, "Run"); + dialog_ex_set_header(dialog_ex, "Run EMV app?", 64, 8, AlignCenter, AlignCenter); + dialog_ex_set_text( + dialog_ex, + "It will try to run card's app\nand detect unencrypred\ndata", + 64, + 18, + AlignCenter, + AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_run_emv_app_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +const bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = (Nfc*)context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + return scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData); + return true; + } + } + return false; +} + +const void nfc_scene_run_emv_app_confirm_on_exit(void* context) { + Nfc* nfc = (Nfc*)context; + + 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_result_callback(dialog_ex, NULL); + dialog_ex_set_context(dialog_ex, NULL); +} diff --git a/applications/nfc/scenes/nfc_scene_save_name.c b/applications/nfc/scenes/nfc_scene_save_name.c index 956fe8ae..af448ef1 100755 --- a/applications/nfc/scenes/nfc_scene_save_name.c +++ b/applications/nfc/scenes/nfc_scene_save_name.c @@ -5,8 +5,7 @@ void nfc_scene_save_name_text_input_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event( - nfc->nfc_common.view_dispatcher, SCENE_SAVE_NAME_CUSTOM_EVENT); + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SAVE_NAME_CUSTOM_EVENT); } const void nfc_scene_save_name_on_enter(void* context) { @@ -14,7 +13,10 @@ const void nfc_scene_save_name_on_enter(void* context) { // Setup view TextInput* text_input = nfc->text_input; - nfc_text_store_clear(nfc); + if(nfc->dev.dev_name) { + nfc_device_delete(&nfc->dev); + } + nfc_text_store_set(nfc, nfc->dev.dev_name); text_input_set_header_text(text_input, "Name the card"); text_input_set_result_callback( text_input, @@ -22,7 +24,7 @@ const void nfc_scene_save_name_on_enter(void* context) { nfc, nfc->text_store, sizeof(nfc->text_store)); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewTextInput); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); } const bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { @@ -30,8 +32,8 @@ const bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { - memcpy(&nfc->device.dev_name, nfc->text_store, strlen(nfc->text_store)); - if(nfc_device_save(&nfc->device, nfc->text_store)) { + memcpy(&nfc->dev.dev_name, nfc->text_store, strlen(nfc->text_store)); + if(nfc_device_save(&nfc->dev, nfc->text_store)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); return true; } else { diff --git a/applications/nfc/scenes/nfc_scene_save_success.c b/applications/nfc/scenes/nfc_scene_save_success.c index 20a1cd7e..cd36871a 100755 --- a/applications/nfc/scenes/nfc_scene_save_success.c +++ b/applications/nfc/scenes/nfc_scene_save_success.c @@ -4,8 +4,7 @@ void nfc_scene_save_success_popup_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event( - nfc->nfc_common.view_dispatcher, SCENE_SAVE_SUCCESS_CUSTOM_EVENT); + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SAVE_SUCCESS_CUSTOM_EVENT); } const void nfc_scene_save_success_on_enter(void* context) { @@ -19,7 +18,7 @@ const void nfc_scene_save_success_on_enter(void* context) { popup_set_context(popup, nfc); popup_set_callback(popup, nfc_scene_save_success_popup_callback); popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewPopup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); } const bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index 46e64691..24d03fbc 100755 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -10,15 +10,17 @@ enum SubmenuIndex { void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } const void nfc_scene_saved_menu_on_enter(void* context) { Nfc* nfc = (Nfc*)context; Submenu* submenu = nfc->submenu; - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); + if(nfc->dev.format != NfcDeviceSaveFormatBankCard) { + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); + } submenu_add_item( submenu, "Edit UID and name", SubmenuIndexEdit, nfc_scene_saved_menu_submenu_callback, nfc); submenu_add_item( @@ -28,7 +30,7 @@ const void nfc_scene_saved_menu_on_enter(void* context) { submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { @@ -42,16 +44,16 @@ const bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) return true; } else if(event.event == SubmenuIndexEdit) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEdit); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); return true; } else if(event.event == SubmenuIndexDelete) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexDelete); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); return true; } else if(event.event == SubmenuIndexInfo) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexInfo); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); return true; } } diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.c b/applications/nfc/scenes/nfc_scene_scripts_menu.c index b8e43528..327d32c6 100755 --- a/applications/nfc/scenes/nfc_scene_scripts_menu.c +++ b/applications/nfc/scenes/nfc_scene_scripts_menu.c @@ -8,7 +8,7 @@ enum SubmenuIndex { 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); + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } const void nfc_scene_scripts_menu_on_enter(void* context) { @@ -29,7 +29,7 @@ const void nfc_scene_scripts_menu_on_enter(void* context) { nfc); submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneScriptsMenu)); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) { @@ -39,7 +39,7 @@ const bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent even if(event.event == SubmenuIndexBankCard) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexBankCard); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); return true; } else if(event.event == SubmenuIndexMifareUltralight) { scene_manager_set_scene_state( diff --git a/applications/nfc/scenes/nfc_scene_set_atqa.c b/applications/nfc/scenes/nfc_scene_set_atqa.c index ebb0bb8f..80ceea17 100755 --- a/applications/nfc/scenes/nfc_scene_set_atqa.c +++ b/applications/nfc/scenes/nfc_scene_set_atqa.c @@ -5,8 +5,7 @@ void nfc_scene_set_atqa_byte_input_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event( - nfc->nfc_common.view_dispatcher, SCENE_SET_ATQA_CUSTOM_EVENT); + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SET_ATQA_CUSTOM_EVENT); } const void nfc_scene_set_atqa_on_enter(void* context) { @@ -16,8 +15,13 @@ const void nfc_scene_set_atqa_on_enter(void* context) { ByteInput* byte_input = nfc->byte_input; byte_input_set_header_text(byte_input, "Enter atqa in hex"); byte_input_set_result_callback( - byte_input, nfc_scene_set_atqa_byte_input_callback, NULL, nfc, nfc->device.data.atqa, 2); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); + byte_input, + nfc_scene_set_atqa_byte_input_callback, + NULL, + nfc, + nfc->dev.dev_data.nfc_data.atqa, + 2); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } const bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_set_sak.c b/applications/nfc/scenes/nfc_scene_set_sak.c index 1b20afbc..27646cc6 100755 --- a/applications/nfc/scenes/nfc_scene_set_sak.c +++ b/applications/nfc/scenes/nfc_scene_set_sak.c @@ -5,7 +5,7 @@ void nfc_scene_set_sak_byte_input_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, SCENE_SET_SAK_CUSTOM_EVENT); + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SET_SAK_CUSTOM_EVENT); } const void nfc_scene_set_sak_on_enter(void* context) { @@ -15,8 +15,13 @@ const void nfc_scene_set_sak_on_enter(void* context) { ByteInput* byte_input = nfc->byte_input; byte_input_set_header_text(byte_input, "Enter SAK in hex"); byte_input_set_result_callback( - byte_input, nfc_scene_set_sak_byte_input_callback, NULL, nfc, &nfc->device.data.sak, 1); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); + byte_input, + nfc_scene_set_sak_byte_input_callback, + NULL, + nfc, + &nfc->dev.dev_data.nfc_data.sak, + 1); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } const bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_set_type.c b/applications/nfc/scenes/nfc_scene_set_type.c index 951464e0..9798b8f7 100755 --- a/applications/nfc/scenes/nfc_scene_set_type.c +++ b/applications/nfc/scenes/nfc_scene_set_type.c @@ -8,7 +8,7 @@ enum SubmenuIndex { void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } const void nfc_scene_set_type_on_enter(void* context) { @@ -19,7 +19,7 @@ const void nfc_scene_set_type_on_enter(void* context) { submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); submenu_add_item( submenu, "NFC-A 4-bytes UID", SubmenuIndexNFCA4, nfc_scene_set_type_submenu_callback, nfc); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { @@ -27,11 +27,13 @@ const bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexNFCA7) { - nfc->device.data.uid_len = 7; + nfc->dev.dev_data.nfc_data.uid_len = 7; + nfc->dev.format = NfcDeviceSaveFormatUid; scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); return true; } else if(event.event == SubmenuIndexNFCA4) { - nfc->device.data.uid_len = 4; + nfc->dev.dev_data.nfc_data.uid_len = 4; + nfc->dev.format = NfcDeviceSaveFormatUid; scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); return true; } diff --git a/applications/nfc/scenes/nfc_scene_set_uid.c b/applications/nfc/scenes/nfc_scene_set_uid.c index 1c48c8df..6e1a8d7c 100755 --- a/applications/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/nfc/scenes/nfc_scene_set_uid.c @@ -5,7 +5,7 @@ void nfc_scene_set_uid_byte_input_callback(void* context) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, SCENE_SET_UID_CUSTOM_EVENT); + view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SET_UID_CUSTOM_EVENT); } const void nfc_scene_set_uid_on_enter(void* context) { @@ -19,9 +19,9 @@ const void nfc_scene_set_uid_on_enter(void* context) { nfc_scene_set_uid_byte_input_callback, NULL, nfc, - nfc->device.data.uid, - nfc->device.data.uid_len); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); + nfc->dev.dev_data.nfc_data.uid, + nfc->dev.dev_data.nfc_data.uid_len); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } const bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/nfc/scenes/nfc_scene_start.c b/applications/nfc/scenes/nfc_scene_start.c index d171b0c3..78a4d923 100755 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/nfc/scenes/nfc_scene_start.c @@ -5,13 +5,12 @@ enum SubmenuIndex { SubmenuIndexRunScript, SubmenuIndexSaved, SubmenuIndexAddManualy, - SubmenuIndexDebug, }; void nfc_scene_start_submenu_callback(void* context, uint32_t index) { Nfc* nfc = (Nfc*)context; - view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } const void nfc_scene_start_on_enter(void* context) { @@ -30,11 +29,11 @@ const void nfc_scene_start_on_enter(void* context) { submenu, "Saved cards", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc); submenu_add_item( submenu, "Add manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc); - submenu_add_item(submenu, "Debug", SubmenuIndexDebug, nfc_scene_start_submenu_callback, nfc); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart)); - view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); + nfc_device_clear(&nfc->dev); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } const bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { @@ -59,10 +58,6 @@ const bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManualy); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); return true; - } else if(event.event == SubmenuIndexDebug) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDebugMenu); - return true; } } return false; diff --git a/applications/nfc/views/bank_card.c b/applications/nfc/views/bank_card.c new file mode 100755 index 00000000..3d78da26 --- /dev/null +++ b/applications/nfc/views/bank_card.c @@ -0,0 +1,65 @@ +#include "bank_card.h" +#include "../gui_widget/gui_widget.h" +#include + +struct BankCard { + GuiWidget* widget; +}; + +BankCard* bank_card_alloc() { + BankCard* bank_card = furi_alloc(sizeof(BankCard)); + bank_card->widget = gui_widget_alloc(); + return bank_card; +} + +void bank_card_free(BankCard* bank_card) { + furi_assert(bank_card); + gui_widget_free(bank_card->widget); + free(bank_card); +} + +View* bank_card_get_view(BankCard* bank_card) { + furi_assert(bank_card); + return gui_widget_get_view(bank_card->widget); +} + +void bank_card_clear(BankCard* bank_card) { + furi_assert(bank_card); + gui_widget_clear(bank_card->widget); +} + +void bank_card_set_name(BankCard* bank_card, char* name) { + furi_assert(bank_card); + furi_assert(name); + gui_widget_add_string_element( + bank_card->widget, 64, 6, AlignCenter, AlignTop, FontSecondary, name); +} + +void bank_card_set_number(BankCard* bank_card, uint8_t* number) { + furi_assert(bank_card); + furi_assert(number); + string_t num_str; + string_init(num_str); + for(uint8_t i = 0; i < 8; i += 2) { + string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]); + } + gui_widget_add_string_element( + bank_card->widget, 25, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(num_str)); + gui_widget_add_icon_element(bank_card->widget, 6, 20, &I_EMV_Chip_14x11); + string_clear(num_str); +} + +void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint16_t year) { + furi_assert(bank_card); + char exp_date_str[16]; + snprintf(exp_date_str, sizeof(exp_date_str), "Exp: %02d/%02d", mon, year % 100); + gui_widget_add_string_element( + bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); +} + +void bank_card_set_cardholder_name(BankCard* bank_card, char* name) { + furi_assert(bank_card); + furi_assert(name); + gui_widget_add_string_element( + bank_card->widget, 6, 37, AlignLeft, AlignTop, FontSecondary, name); +} diff --git a/applications/nfc/views/bank_card.h b/applications/nfc/views/bank_card.h new file mode 100644 index 00000000..40472c87 --- /dev/null +++ b/applications/nfc/views/bank_card.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include + +typedef struct BankCard BankCard; + +typedef void (*BankCardBackCallback)(void); + +BankCard* bank_card_alloc(); + +void bank_card_free(BankCard* bank_card); + +void bank_card_clear(BankCard* bank_card); + +View* bank_card_get_view(BankCard* bank_card); + +void bank_card_set_name(BankCard* bank_card, char* name); + +void bank_card_set_number(BankCard* bank_card, uint8_t* number); + +void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint16_t year); + +void bank_card_set_cardholder_name(BankCard* bank_card, char* name); diff --git a/applications/nfc/views/nfc_detect.c b/applications/nfc/views/nfc_detect.c deleted file mode 100755 index 8069ce77..00000000 --- a/applications/nfc/views/nfc_detect.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "nfc_detect.h" - -#include -#include -#include - -#include "../nfc_i.h" - -struct NfcDetect { - NfcCommon* nfc_common; - View* view; -}; - -typedef struct { - bool found; - NfcDeviceData data; -} NfcDetectModel; - -void nfc_detect_draw(Canvas* canvas, NfcDetectModel* model) { - char buffer[32]; - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - if(model->found) { - canvas_draw_str(canvas, 0, 12, "Found"); - canvas_draw_str(canvas, 32, 12, nfc_get_dev_type(model->data.device)); - canvas_set_font(canvas, FontSecondary); - if(model->data.protocol != NfcDeviceProtocolUnknown) { - canvas_draw_str(canvas, 0, 22, nfc_get_protocol(model->data.protocol)); - } - // Display UID - for(uint8_t i = 0; i < model->data.uid_len; i++) { - snprintf(buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->data.uid[i]); - buffer[model->data.uid_len * 2] = 0; - } - canvas_draw_str(canvas, 0, 32, "UID: "); - canvas_draw_str(canvas, 22, 32, buffer); - // Display ATQA and SAK - snprintf( - buffer, - sizeof(buffer), - "ATQA: %02X %02X SAK: %02X", - model->data.atqa[1], - model->data.atqa[0], - model->data.sak); - canvas_draw_str(canvas, 0, 42, buffer); - } else { - canvas_draw_str(canvas, 0, 12, "Searching"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 22, "Place card to the back"); - } -} - -bool nfc_detect_input(InputEvent* event, void* context) { - if(event->key == InputKeyBack) { - return false; - } - return true; -} - -void nfc_detect_worker_callback(void* context) { - furi_assert(context); - - NfcDetect* nfc_detect = (NfcDetect*)context; - view_dispatcher_send_custom_event(nfc_detect->nfc_common->view_dispatcher, NfcEventDetect); -} - -bool nfc_detect_view_custom(uint32_t event, void* context) { - furi_assert(context); - - NfcDetect* nfc_detect = (NfcDetect*)context; - if(event == NfcEventDetect) { - NfcDeviceData* data = (NfcDeviceData*)&nfc_detect->nfc_common->worker_result; - - with_view_model( - nfc_detect->view, (NfcDetectModel * model) { - model->found = true; - model->data = *data; - return true; - }); - // TODO add and configure next view model - return false; - } - - return false; -} - -void nfc_detect_enter(void* context) { - furi_assert(context); - - NfcDetect* nfc_detect = (NfcDetect*)context; - with_view_model( - nfc_detect->view, (NfcDetectModel * model) { - model->found = false; - model->data.protocol = NfcDeviceProtocolUnknown; - return true; - }); - nfc_worker_start( - nfc_detect->nfc_common->worker, - NfcWorkerStateDetect, - &nfc_detect->nfc_common->worker_result, - nfc_detect_worker_callback, - nfc_detect); -} - -void nfc_detect_exit(void* context) { - furi_assert(context); - - NfcDetect* nfc_detect = (NfcDetect*)context; - nfc_worker_stop(nfc_detect->nfc_common->worker); -} - -NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common) { - furi_assert(nfc_common); - - NfcDetect* nfc_detect = furi_alloc(sizeof(NfcDetect)); - nfc_detect->nfc_common = nfc_common; - - // View allocation and configuration - nfc_detect->view = view_alloc(); - view_allocate_model(nfc_detect->view, ViewModelTypeLockFree, sizeof(NfcDetectModel)); - view_set_context(nfc_detect->view, nfc_detect); - view_set_draw_callback(nfc_detect->view, (ViewDrawCallback)nfc_detect_draw); - view_set_input_callback(nfc_detect->view, nfc_detect_input); - view_set_custom_callback(nfc_detect->view, nfc_detect_view_custom); - view_set_enter_callback(nfc_detect->view, nfc_detect_enter); - view_set_exit_callback(nfc_detect->view, nfc_detect_exit); - - return nfc_detect; -} - -void nfc_detect_free(NfcDetect* nfc_detect) { - furi_assert(nfc_detect); - - view_free(nfc_detect->view); - free(nfc_detect); -} - -View* nfc_detect_get_view(NfcDetect* nfc_detect) { - furi_assert(nfc_detect); - - return nfc_detect->view; -} \ No newline at end of file diff --git a/applications/nfc/views/nfc_detect.h b/applications/nfc/views/nfc_detect.h deleted file mode 100644 index 5ae6660f..00000000 --- a/applications/nfc/views/nfc_detect.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include "../nfc_types.h" - -typedef struct NfcDetect NfcDetect; - -NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common); - -void nfc_detect_free(NfcDetect* nfc_detect); - -View* nfc_detect_get_view(NfcDetect* nfc_detect); diff --git a/applications/nfc/views/nfc_emulate.c b/applications/nfc/views/nfc_emulate.c deleted file mode 100755 index 7dcac2da..00000000 --- a/applications/nfc/views/nfc_emulate.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "nfc_emulate.h" - -#include -#include -#include - -#include "../nfc_i.h" - -struct NfcEmulate { - NfcCommon* nfc_common; - View* view; -}; - -void nfc_emulate_draw(Canvas* canvas, void* model) { - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 0, 12, "Emulating NFC-A"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 22, "Type: T2T"); - canvas_draw_str(canvas, 2, 32, "UID length: 7"); - canvas_draw_str(canvas, 2, 42, "UID: 36 9C E7 B1 0A C1 34"); - canvas_draw_str(canvas, 2, 52, "SAK: 00 ATQA: 00/44"); -} - -bool nfc_emulate_input(InputEvent* event, void* context) { - if(event->key == InputKeyBack) { - return false; - } - return true; -} - -void nfc_emulate_enter(void* context) { - furi_assert(context); - - NfcEmulate* nfc_emulate = (NfcEmulate*)context; - nfc_worker_start( - nfc_emulate->nfc_common->worker, - NfcWorkerStateEmulate, - &nfc_emulate->nfc_common->worker_result, - NULL, - NULL); -} - -void nfc_emulate_exit(void* context) { - furi_assert(context); - - NfcEmulate* nfc_emulate = (NfcEmulate*)context; - nfc_worker_stop(nfc_emulate->nfc_common->worker); -} - -NfcEmulate* nfc_emulate_alloc(NfcCommon* nfc_common) { - furi_assert(nfc_common); - - NfcEmulate* nfc_emulate = furi_alloc(sizeof(NfcEmulate)); - nfc_emulate->nfc_common = nfc_common; - - // View allocation and configuration - nfc_emulate->view = view_alloc(); - view_set_context(nfc_emulate->view, nfc_emulate); - view_set_draw_callback(nfc_emulate->view, (ViewDrawCallback)nfc_emulate_draw); - view_set_input_callback(nfc_emulate->view, nfc_emulate_input); - view_set_enter_callback(nfc_emulate->view, nfc_emulate_enter); - view_set_exit_callback(nfc_emulate->view, nfc_emulate_exit); - - return nfc_emulate; -} - -void nfc_emulate_free(NfcEmulate* nfc_emulate) { - furi_assert(nfc_emulate); - - view_free(nfc_emulate->view); - free(nfc_emulate); -} - -View* nfc_emulate_get_view(NfcEmulate* nfc_emulate) { - furi_assert(nfc_emulate); - - return nfc_emulate->view; -} \ No newline at end of file diff --git a/applications/nfc/views/nfc_emulate.h b/applications/nfc/views/nfc_emulate.h deleted file mode 100644 index 660fdae7..00000000 --- a/applications/nfc/views/nfc_emulate.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include "../nfc_types.h" - -typedef struct NfcEmulate NfcEmulate; - -NfcEmulate* nfc_emulate_alloc(NfcCommon* nfc_common); - -void nfc_emulate_free(NfcEmulate* nfc_emulate); - -View* nfc_emulate_get_view(NfcEmulate* nfc_emulate); diff --git a/applications/nfc/views/nfc_emv.c b/applications/nfc/views/nfc_emv.c deleted file mode 100755 index 7e9dc026..00000000 --- a/applications/nfc/views/nfc_emv.c +++ /dev/null @@ -1,133 +0,0 @@ -#include "nfc_emv.h" - -#include -#include -#include - -#include "../nfc_i.h" - -struct NfcEmv { - NfcCommon* nfc_common; - View* view; -}; - -typedef struct { - bool found; - NfcEmvData emv_data; -} NfcEmvModel; - -void nfc_emv_draw(Canvas* canvas, NfcEmvModel* model) { - char buffer[32]; - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - if(model->found) { - canvas_draw_str(canvas, 0, 12, "Found EMV card"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 22, "Type:"); - snprintf(buffer, sizeof(buffer), "%s", model->emv_data.name); - canvas_draw_str(canvas, 2, 32, buffer); - snprintf(buffer, sizeof(buffer), "Number:\n"); - canvas_draw_str(canvas, 2, 42, buffer); - uint8_t card_num_len = sizeof(model->emv_data.number); - for(uint8_t i = 0; i < card_num_len; i++) { - snprintf( - buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->emv_data.number[i]); - } - buffer[card_num_len * 2] = 0; - canvas_draw_str(canvas, 2, 52, buffer); - } else { - canvas_draw_str(canvas, 0, 12, "Searching"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 22, "Place card to the back"); - } -} - -bool nfc_emv_input(InputEvent* event, void* context) { - if(event->key == InputKeyBack) { - return false; - } - return true; -} - -void nfc_emv_worker_callback(void* context) { - furi_assert(context); - - NfcEmv* nfc_emv = (NfcEmv*)context; - view_dispatcher_send_custom_event(nfc_emv->nfc_common->view_dispatcher, NfcEventEmv); -} - -bool nfc_emv_custom(uint32_t event, void* context) { - furi_assert(context); - - NfcEmv* nfc_emv = (NfcEmv*)context; - if(event == NfcEventEmv) { - NfcEmvData* data = (NfcEmvData*)&nfc_emv->nfc_common->worker_result; - - with_view_model( - nfc_emv->view, (NfcEmvModel * model) { - model->found = true; - model->emv_data = *data; - return true; - }); - // TODO add and configure next view model - return true; - } - - return false; -} - -void nfc_emv_enter(void* context) { - furi_assert(context); - - NfcEmv* nfc_emv = (NfcEmv*)context; - with_view_model( - nfc_emv->view, (NfcEmvModel * model) { - model->found = false; - return true; - }); - nfc_worker_start( - nfc_emv->nfc_common->worker, - NfcWorkerStateReadEMV, - &nfc_emv->nfc_common->worker_result, - nfc_emv_worker_callback, - nfc_emv); -} - -void nfc_emv_exit(void* context) { - furi_assert(context); - - NfcEmv* nfc_emv = (NfcEmv*)context; - nfc_worker_stop(nfc_emv->nfc_common->worker); -} - -NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common) { - furi_assert(nfc_common); - - NfcEmv* nfc_emv = furi_alloc(sizeof(NfcEmv)); - nfc_emv->nfc_common = nfc_common; - - // View allocation and configuration - nfc_emv->view = view_alloc(); - view_allocate_model(nfc_emv->view, ViewModelTypeLockFree, sizeof(NfcEmvModel)); - view_set_context(nfc_emv->view, nfc_emv); - view_set_draw_callback(nfc_emv->view, (ViewDrawCallback)nfc_emv_draw); - view_set_input_callback(nfc_emv->view, nfc_emv_input); - view_set_custom_callback(nfc_emv->view, nfc_emv_custom); - view_set_enter_callback(nfc_emv->view, nfc_emv_enter); - view_set_exit_callback(nfc_emv->view, nfc_emv_exit); - - return nfc_emv; -} - -void nfc_emv_free(NfcEmv* nfc_emv) { - furi_assert(nfc_emv); - - view_free(nfc_emv->view); - free(nfc_emv); -} - -View* nfc_emv_get_view(NfcEmv* nfc_emv) { - furi_assert(nfc_emv); - - return nfc_emv->view; -} \ No newline at end of file diff --git a/applications/nfc/views/nfc_emv.h b/applications/nfc/views/nfc_emv.h deleted file mode 100644 index e348ce98..00000000 --- a/applications/nfc/views/nfc_emv.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include "../nfc_types.h" - -typedef struct NfcEmv NfcEmv; - -NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common); - -void nfc_emv_free(NfcEmv* nfc_emv); - -View* nfc_emv_get_view(NfcEmv* nfc_emv); diff --git a/applications/nfc/views/nfc_mifare_ul.c b/applications/nfc/views/nfc_mifare_ul.c deleted file mode 100755 index ea47b6fd..00000000 --- a/applications/nfc/views/nfc_mifare_ul.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "nfc_mifare_ul.h" - -#include -#include -#include - -#include "../nfc_i.h" - -struct NfcMifareUl { - NfcCommon* nfc_common; - View* view; -}; - -typedef struct { - bool found; - NfcMifareUlData nfc_mf_ul_data; -} NfcMifareUlModel; - -void nfc_mifare_ul_draw(Canvas* canvas, NfcMifareUlModel* model) { - char buffer[32]; - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - if(model->found) { - canvas_draw_str(canvas, 0, 12, "Found Mifare Ultralight"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 22, "UID:"); - for(uint8_t i = 0; i < model->nfc_mf_ul_data.nfc_data.uid_len; i++) { - snprintf( - buffer + (i * 2), - sizeof(buffer) - (i * 2), - "%02X", - model->nfc_mf_ul_data.nfc_data.uid[i]); - } - buffer[model->nfc_mf_ul_data.nfc_data.uid_len * 2] = 0; - canvas_draw_str(canvas, 18, 22, buffer); - - uint8_t man_bl_size = sizeof(model->nfc_mf_ul_data.man_block); - canvas_draw_str(canvas, 2, 32, "Manufacturer block:"); - for(uint8_t i = 0; i < man_bl_size / 2; i++) { - snprintf( - buffer + (i * 2), - sizeof(buffer) - (i * 2), - "%02X", - model->nfc_mf_ul_data.man_block[i]); - } - buffer[man_bl_size] = 0; - canvas_draw_str(canvas, 2, 42, buffer); - - for(uint8_t i = 0; i < man_bl_size / 2; i++) { - snprintf( - buffer + (i * 2), - sizeof(buffer) - (i * 2), - "%02X", - model->nfc_mf_ul_data.man_block[man_bl_size / 2 + i]); - } - buffer[man_bl_size] = 0; - canvas_draw_str(canvas, 2, 52, buffer); - - canvas_draw_str(canvas, 2, 62, "OTP: "); - for(uint8_t i = 0; i < sizeof(model->nfc_mf_ul_data.otp); i++) { - snprintf( - buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", model->nfc_mf_ul_data.otp[i]); - } - buffer[sizeof(model->nfc_mf_ul_data.otp) * 2] = 0; - canvas_draw_str(canvas, 22, 62, buffer); - } else { - canvas_draw_str(canvas, 0, 12, "Searching"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 22, "Place card to the back"); - } -} - -bool nfc_mifare_ul_input(InputEvent* event, void* context) { - if(event->key == InputKeyBack) { - return false; - } - return true; -} - -void nfc_mifare_ul_worker_callback(void* context) { - furi_assert(context); - - NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; - view_dispatcher_send_custom_event( - nfc_mifare_ul->nfc_common->view_dispatcher, NfcEventMifareUl); -} - -bool nfc_mifare_ul_custom(uint32_t event, void* context) { - furi_assert(context); - - NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; - if(event == NfcEventMifareUl) { - NfcMifareUlData* data = (NfcMifareUlData*)&nfc_mifare_ul->nfc_common->worker_result; - - with_view_model( - nfc_mifare_ul->view, (NfcMifareUlModel * model) { - model->found = true; - model->nfc_mf_ul_data = *data; - return true; - }); - // TODO add and configure next view model - return true; - } - - return false; -} - -void nfc_mifare_ul_enter(void* context) { - furi_assert(context); - - NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; - with_view_model( - nfc_mifare_ul->view, (NfcMifareUlModel * m) { - m->found = false; - return true; - }); - nfc_worker_start( - nfc_mifare_ul->nfc_common->worker, - NfcWorkerStateReadMfUltralight, - &nfc_mifare_ul->nfc_common->worker_result, - nfc_mifare_ul_worker_callback, - nfc_mifare_ul); -} - -void nfc_mifare_ul_exit(void* context) { - furi_assert(context); - - NfcMifareUl* nfc_mifare_ul = (NfcMifareUl*)context; - nfc_worker_stop(nfc_mifare_ul->nfc_common->worker); -} - -NfcMifareUl* nfc_mifare_ul_alloc(NfcCommon* nfc_common) { - furi_assert(nfc_common); - - NfcMifareUl* nfc_mifare_ul = furi_alloc(sizeof(NfcMifareUl)); - nfc_mifare_ul->nfc_common = nfc_common; - - // View allocation and configuration - nfc_mifare_ul->view = view_alloc(); - view_allocate_model(nfc_mifare_ul->view, ViewModelTypeLockFree, sizeof(NfcMifareUlModel)); - view_set_context(nfc_mifare_ul->view, nfc_mifare_ul); - view_set_draw_callback(nfc_mifare_ul->view, (ViewDrawCallback)nfc_mifare_ul_draw); - view_set_input_callback(nfc_mifare_ul->view, nfc_mifare_ul_input); - view_set_custom_callback(nfc_mifare_ul->view, nfc_mifare_ul_custom); - view_set_enter_callback(nfc_mifare_ul->view, nfc_mifare_ul_enter); - view_set_exit_callback(nfc_mifare_ul->view, nfc_mifare_ul_exit); - - return nfc_mifare_ul; -} - -void nfc_mifare_ul_free(NfcMifareUl* nfc_mifare_ul) { - furi_assert(nfc_mifare_ul); - - view_free(nfc_mifare_ul->view); - free(nfc_mifare_ul); -} - -View* nfc_mifare_ul_get_view(NfcMifareUl* nfc_mifare_ul) { - furi_assert(nfc_mifare_ul); - - return nfc_mifare_ul->view; -} \ No newline at end of file diff --git a/applications/nfc/views/nfc_mifare_ul.h b/applications/nfc/views/nfc_mifare_ul.h deleted file mode 100644 index eb666e08..00000000 --- a/applications/nfc/views/nfc_mifare_ul.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include "../nfc_types.h" - -typedef struct NfcMifareUl NfcMifareUl; - -NfcMifareUl* nfc_mifare_ul_alloc(NfcCommon* nfc_common); - -void nfc_mifare_ul_free(NfcMifareUl* nfc_mifare_ul); - -View* nfc_mifare_ul_get_view(NfcMifareUl* nfc_mifare_ul); diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index ef50f0cc..a96c2889 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -12,8 +12,9 @@ uint16_t mf_ul_prepare_get_version(uint8_t* dest) { return 1; } -void mf_ul_parse_get_version_response(uint8_t* buff, MfUltralightRead* mf_ul_read) { +void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) { MfUltralightVersion* version = (MfUltralightVersion*) buff; + memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion)); if(version->storage_size == 0x0B || version->storage_size == 0x00) { mf_ul_read->type = MfUltralightTypeUL11; mf_ul_read->pages_to_read = 20; @@ -39,9 +40,9 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MfUltralightRead* mf_ul_rea } } -void mf_ul_set_default_version(MfUltralightRead* mf_ul_read) { +void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) { mf_ul_read->type = MfUltralightTypeUnknown; - mf_ul_read->pages_to_read = 20; + mf_ul_read->pages_to_read = 16; mf_ul_read->support_fast_read = false; } @@ -51,9 +52,88 @@ uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) { return 2; } +void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read) { + mf_ul_read->pages_readed += 4; + mf_ul_read->data.data_size = mf_ul_read->pages_readed * 4; + memcpy(&mf_ul_read->data.data[page_addr * 4], buff, 16); +} + uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) { dest[0] = MF_UL_FAST_READ_CMD; dest[1] = start_page; dest[2] = end_page; return 3; } + +void mf_ul_parse_fast_read_response(uint8_t* buff, uint8_t start_page, uint8_t end_page, MifareUlDevice* mf_ul_read) { + mf_ul_read->pages_readed = end_page - start_page + 1; + mf_ul_read->data.data_size = mf_ul_read->pages_readed * 4; + memcpy(mf_ul_read->data.data, buff, mf_ul_read->data.data_size); +} + +uint16_t mf_ul_prepare_read_signature(uint8_t* dest) { + dest[0] = MF_UL_CHECK_TEARING; + dest[1] = 0; + return 2; +} + +void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read) { + memcpy(mf_ul_read->data.signature, buff, sizeof(mf_ul_read->data.signature)); +} + +uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index) { + if(cnt_index > 2) { + return 0; + } + dest[0] = MF_UL_READ_CNT; + dest[1] = cnt_index; + return 2; +} + +void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read) { + // Reverse LSB sequence + if(cnt_index < 3) { + mf_ul_read->data.counter[cnt_index] = (buff[2] << 16) | (buff[1] << 8) | (buff[0]); + } +} + +uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value) { + if(cnt_index > 2) { + return 0; + } + dest[0] = MF_UL_INC_CNT; + dest[1] = cnt_index; + dest[2] = (uint8_t) value; + dest[3] = (uint8_t) (value >> 8); + dest[4] = (uint8_t) (value >> 16); + dest[5] = 0; + return 6; +} + +uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index) { + if(cnt_index > 2) { + return 0; + } + dest[0] = MF_UL_CHECK_TEARING; + dest[1] = cnt_index; + return 2; +} + +void mf_ul_parse_check_tearing_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read) { + if(cnt_index < 2) { + mf_ul_read->data.tearing[cnt_index] = buff[0]; + } +} + +uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) { + if(page_addr < 2) { + return 0; + } + dest[0] = MF_UL_WRITE; + dest[1] = page_addr; + dest[2] = (uint8_t) (data >> 24); + dest[3] = (uint8_t) (data >> 16); + dest[4] = (uint8_t) (data >> 8); + dest[5] = (uint8_t) data; + return 6; +} diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 43579191..83673a7e 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -4,9 +4,22 @@ #include #include +#define MF_UL_MAX_DUMP_SIZE 255 + +#define MF_UL_TEARING_FLAG_DEFAULT (0xBD) + #define MF_UL_GET_VERSION_CMD (0x60) #define MF_UL_READ_CMD (0x30) #define MF_UL_FAST_READ_CMD (0x3A) +#define MF_UL_WRITE (0xA2) +#define MF_UL_COMP_WRITE (0xA0) +#define MF_UL_READ_CNT (0x39) +#define MF_UL_INC_CNT (0xA5) +#define MF_UL_AUTH (0x1B) +#define MF_UL_READ_SIG (0x3C) +#define MF_UL_CHECK_TEARING (0x3E) +#define MF_UL_READ_VCSL (0x4B) + typedef enum { MfUltralightTypeUnknown, @@ -38,19 +51,45 @@ typedef struct { uint8_t otp[4]; } MfUltralightManufacturerBlock; +typedef struct { + MfUltralightVersion version; + uint8_t signature[32]; + uint32_t counter[3]; + uint8_t tearing[3]; + uint16_t data_size; + uint8_t data[MF_UL_MAX_DUMP_SIZE]; +} MifareUlData; + typedef struct { MfUltralightType type; uint8_t pages_to_read; uint8_t pages_readed; bool support_fast_read; - uint8_t dump[255]; -} MfUltralightRead; + MifareUlData data; +} MifareUlDevice; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); uint16_t mf_ul_prepare_get_version(uint8_t* dest); -void mf_ul_parse_get_version_response(uint8_t* buff, MfUltralightRead* mf_ul_read); -void mf_ul_set_default_version(MfUltralightRead* mf_ul_read); +void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read); +void mf_ul_set_default_version(MifareUlDevice* mf_ul_read); + +uint16_t mf_ul_prepare_read_signature(uint8_t* dest); +void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read); + +uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index); +void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read); + +uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value); + +uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index); +void mf_ul_parse_check_tearing_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read); uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page); +void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read); + uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page); +void mf_ul_parse_fast_read_response(uint8_t* buff, uint8_t start_page, uint8_t end_page, MifareUlDevice* mf_ul_read); + +uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data); +