Quellcode durchsuchen

[FL-1479] New NFC app (#544)

* view: add custom event callback
* nfc: rework nfc worker
* gui: introduce view navigator
* nfc_scences: introduce nfc scenes
* nfc: add start scene
* lib: add C application scene template
* nfc: move nfc views to separate directory
* view_dispatcher: add support for view_navigator
* nfc views: rework nfc views
* nfc scenes: add nfc application scenes
* nfc: rework nfc main thread
* view_dispatcher: add separate event for search back scene
* nfc: set worker result address at worker start
* nfc: update read nfc scenes
* view_navigator: rework with M-LIB container
* view_dispatcher: check that all views were freed
* nfc: add debug menu with all functions
* nfc read scene: add notification on success
* api-hal-nfc: add API for UID emulation
* nfc: add nfc emulation UID scene
* assets: add NFC assets
* nfc: update read and emulate scenes UI
* nfc: fix memory leak
* rfal: set custom analog configuration
gornekich vor 4 Jahren
Ursprung
Commit
a0e1e42f2d
57 geänderte Dateien mit 1942 neuen und 565 gelöschten Zeilen
  1. 15 0
      applications/gui/view.c
  2. 14 1
      applications/gui/view.h
  3. 71 15
      applications/gui/view_dispatcher.c
  4. 27 12
      applications/gui/view_dispatcher.h
  5. 5 2
      applications/gui/view_dispatcher_i.h
  6. 4 0
      applications/gui/view_i.h
  7. 109 0
      applications/gui/view_navigator.c
  8. 28 0
      applications/gui/view_navigator.h
  9. 16 0
      applications/gui/view_navigator_i.h
  10. 86 55
      applications/nfc/nfc.c
  11. 10 1
      applications/nfc/nfc_cli.c
  12. 72 6
      applications/nfc/nfc_i.h
  13. 10 54
      applications/nfc/nfc_types.h
  14. 76 79
      applications/nfc/nfc_worker.c
  15. 46 1
      applications/nfc/nfc_worker.h
  16. 2 1
      applications/nfc/nfc_worker_i.h
  17. 95 0
      applications/nfc/scenes/nfc_scene_card_menu.c
  18. 7 0
      applications/nfc/scenes/nfc_scene_card_menu.h
  19. 31 0
      applications/nfc/scenes/nfc_scene_debug_detect.c
  20. 7 0
      applications/nfc/scenes/nfc_scene_debug_detect.h
  21. 31 0
      applications/nfc/scenes/nfc_scene_debug_emulate.c
  22. 7 0
      applications/nfc/scenes/nfc_scene_debug_emulate.h
  23. 88 0
      applications/nfc/scenes/nfc_scene_debug_menu.c
  24. 7 0
      applications/nfc/scenes/nfc_scene_debug_menu.h
  25. 31 0
      applications/nfc/scenes/nfc_scene_debug_read_emv.c
  26. 7 0
      applications/nfc/scenes/nfc_scene_debug_read_emv.h
  27. 31 0
      applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.c
  28. 7 0
      applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.h
  29. 70 0
      applications/nfc/scenes/nfc_scene_emulate_uid.c
  30. 7 0
      applications/nfc/scenes/nfc_scene_emulate_uid.h
  31. 61 0
      applications/nfc/scenes/nfc_scene_not_implemented.c
  32. 7 0
      applications/nfc/scenes/nfc_scene_not_implemented.h
  33. 70 0
      applications/nfc/scenes/nfc_scene_read_card.c
  34. 7 0
      applications/nfc/scenes/nfc_scene_read_card.h
  35. 109 0
      applications/nfc/scenes/nfc_scene_read_card_success.c
  36. 7 0
      applications/nfc/scenes/nfc_scene_read_card_success.h
  37. 92 0
      applications/nfc/scenes/nfc_scene_start.c
  38. 7 0
      applications/nfc/scenes/nfc_scene_start.h
  39. 15 18
      applications/nfc/views/nfc_detect.c
  40. 1 3
      applications/nfc/views/nfc_detect.h
  41. 8 8
      applications/nfc/views/nfc_emulate.c
  42. 1 1
      applications/nfc/views/nfc_emulate.h
  43. 19 19
      applications/nfc/views/nfc_emv.c
  44. 1 3
      applications/nfc/views/nfc_emv.h
  45. 15 18
      applications/nfc/views/nfc_mifare_ul.c
  46. 1 3
      applications/nfc/views/nfc_mifare_ul.h
  47. 14 29
      assets/compiled/assets_icons.c
  48. 122 120
      assets/compiled/assets_icons.h
  49. BIN
      assets/icons/NFC/EMV_Chip_14x11.png
  50. BIN
      assets/icons/NFC/Medium-chip-22x21.png
  51. 2 6
      firmware/targets/api-hal-include/api-hal-nfc.h
  52. 20 55
      firmware/targets/f5/api-hal/api-hal-nfc.c
  53. 20 55
      firmware/targets/f6/api-hal/api-hal-nfc.c
  54. 3 0
      lib/ST25RFAL002/platform.h
  55. 309 0
      lib/ST25RFAL002/source/custom_analog_config.c
  56. 11 0
      lib/app_scene_template/app_scene.h
  57. 3 0
      lib/lib.mk

+ 15 - 0
applications/gui/view.c

@@ -24,6 +24,12 @@ void view_set_input_callback(View* view, ViewInputCallback callback) {
     view->input_callback = callback;
 }
 
+void view_set_custom_callback(View* view, ViewCustomCallback callback) {
+    furi_assert(view);
+    furi_assert(callback);
+    view->custom_callback = callback;
+}
+
 void view_set_previous_callback(View* view, ViewNavigationCallback callback) {
     furi_assert(view);
     view->previous_callback = callback;
@@ -145,6 +151,15 @@ bool view_input(View* view, InputEvent* event) {
     }
 }
 
+bool view_custom(View* view, uint32_t event) {
+    furi_assert(view);
+    if(view->custom_callback) {
+        return view->custom_callback(event, view->context);
+    } else {
+        return false;
+    }
+}
+
 uint32_t view_previous(View* view) {
     furi_assert(view);
     if(view->previous_callback) {

+ 14 - 1
applications/gui/view.h

@@ -43,6 +43,13 @@ typedef void (*ViewDrawCallback)(Canvas* canvas, void* model);
  */
 typedef bool (*ViewInputCallback)(InputEvent* event, void* context);
 
+/* View Custom callback
+ * @param event, number of custom event
+ * @param context, pointer to context
+ * @return true if event handled, false if event ignored
+ */
+typedef bool (*ViewCustomCallback)(uint32_t event, void* context);
+
 /* View navigation callback
  * @param context, pointer to context
  * @return next view id
@@ -94,12 +101,18 @@ void view_free(View* view);
  */
 void view_set_draw_callback(View* view, ViewDrawCallback callback);
 
-/* Set View Draw callback
+/* Set View Input callback
  * @param view, pointer to View
  * @param callback, input callback
  */
 void view_set_input_callback(View* view, ViewInputCallback callback);
 
+/* Set View Custom callback
+ * @param view, pointer to View
+ * @param callback, input callback
+ */
+void view_set_custom_callback(View* view, ViewCustomCallback callback);
+
 /* Set Navigation Previous callback
  * @param view, pointer to View
  * @param callback, input callback

+ 71 - 15
applications/gui/view_dispatcher.c

@@ -25,7 +25,8 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
     ViewDict_it(it, view_dispatcher->views);
     while(!ViewDict_end_p(it)) {
         ViewDict_itref_t* ref = ViewDict_ref(it);
-        view_free(ref->value);
+        // Crash if view wasn't freed
+        furi_assert(ref->value);
         ViewDict_next(it);
     }
     ViewDict_clear(view_dispatcher->views);
@@ -35,6 +36,10 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
     if(view_dispatcher->queue) {
         osMessageQueueDelete(view_dispatcher->queue);
     }
+    // Free View Navigator
+    if(view_dispatcher->view_navigator) {
+        view_navigator_free(view_dispatcher->view_navigator);
+    }
     // Free dispatcher
     free(view_dispatcher);
 }
@@ -45,10 +50,26 @@ void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) {
     view_dispatcher->queue = osMessageQueueNew(8, sizeof(ViewDispatcherMessage), NULL);
 }
 
+void view_dispatcher_enable_navigation(ViewDispatcher* view_dispatcher, void* context) {
+    furi_assert(view_dispatcher);
+    view_dispatcher->view_navigator = view_navigator_alloc(context);
+}
+
+void view_dispatcher_add_scene(ViewDispatcher* view_dispatcher, AppScene* scene) {
+    furi_assert(view_dispatcher);
+    furi_assert(view_dispatcher->view_navigator);
+    furi_assert(scene);
+    view_navigator_add_next_scene(view_dispatcher->view_navigator, scene);
+}
+
 void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
     furi_assert(view_dispatcher);
     furi_assert(view_dispatcher->queue);
 
+    if(view_dispatcher->view_navigator) {
+        view_navigator_start(view_dispatcher->view_navigator);
+    }
+
     ViewDispatcherMessage message;
     while(osMessageQueueGet(view_dispatcher->queue, &message, NULL, osWaitForever) == osOK) {
         if(message.type == ViewDispatcherMessageTypeStop) {
@@ -57,6 +78,12 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
             view_dispatcher_handle_input(view_dispatcher, &message.input);
         } else if(message.type == ViewDispatcherMessageTypeCustomEvent) {
             view_dispatcher_handle_custom_event(view_dispatcher, message.custom_event);
+        } else if(message.type == ViewDispatcherMessageTypeNavigationEvent) {
+            view_navigator_handle_navigation_event(
+                view_dispatcher->view_navigator, message.navigator_event);
+        } else if(message.type == ViewDispatcherMessageTypeBackSearchScene) {
+            view_navigator_handle_back_search_scene_event(
+                view_dispatcher->view_navigator, message.navigator_event);
         }
     }
 }
@@ -175,30 +202,35 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
         is_consumed = view_input(view_dispatcher->current_view, event);
     }
     if(!is_consumed && event->type == InputTypeShort) {
+        // TODO remove view navigation handlers
         uint32_t view_id = VIEW_IGNORE;
         if(event->key == InputKeyBack) {
             view_id = view_previous(view_dispatcher->current_view);
+            if((view_id == VIEW_IGNORE) && (view_dispatcher->view_navigator)) {
+                is_consumed = view_navigator_handle_navigation_event(
+                    view_dispatcher->view_navigator, ViewNavigatorEventBack);
+                if(!is_consumed) {
+                    view_dispatcher_stop(view_dispatcher);
+                    return;
+                }
+            }
         } else if(event->key == InputKeyOk) {
             view_id = view_next(view_dispatcher->current_view);
         }
-        view_dispatcher_switch_to_view(view_dispatcher, view_id);
+        if(!is_consumed) {
+            view_dispatcher_switch_to_view(view_dispatcher, view_id);
+        }
     }
 }
 
-void view_dispatcher_set_custom_callback(
-    ViewDispatcher* view_dispatcher,
-    CustomEventCallback callback,
-    void* context) {
-    furi_assert(view_dispatcher);
-    furi_assert(callback);
-
-    view_dispatcher->custom_event_cb = callback;
-    view_dispatcher->custom_event_ctx = context;
-}
-
 void view_dispatcher_handle_custom_event(ViewDispatcher* view_dispatcher, uint32_t event) {
-    if(view_dispatcher->custom_event_cb) {
-        view_dispatcher->custom_event_cb(event, view_dispatcher->custom_event_ctx);
+    bool is_consumed = false;
+    if(view_dispatcher->current_view) {
+        is_consumed = view_custom(view_dispatcher->current_view, event);
+    }
+    // If custom event is not consumed in View, handle it in Scene
+    if(!is_consumed) {
+        is_consumed = view_navigator_handle_custom_event(view_dispatcher->view_navigator, event);
     }
 }
 
@@ -213,6 +245,30 @@ void view_dispatcher_send_custom_event(ViewDispatcher* view_dispatcher, uint32_t
     furi_check(osMessageQueuePut(view_dispatcher->queue, &message, 0, osWaitForever) == osOK);
 }
 
+void view_dispatcher_send_navigation_event(ViewDispatcher* view_dispatcher, uint32_t event) {
+    furi_assert(view_dispatcher);
+    furi_assert(view_dispatcher->queue);
+    furi_assert(view_dispatcher->view_navigator);
+
+    ViewDispatcherMessage message;
+    message.type = ViewDispatcherMessageTypeNavigationEvent;
+    message.custom_event = event;
+
+    furi_check(osMessageQueuePut(view_dispatcher->queue, &message, 0, osWaitForever) == osOK);
+}
+
+void view_dispatcher_send_back_search_scene_event(ViewDispatcher* view_dispatcher, uint32_t event) {
+    furi_assert(view_dispatcher);
+    furi_assert(view_dispatcher->queue);
+    furi_assert(view_dispatcher->view_navigator);
+
+    ViewDispatcherMessage message;
+    message.type = ViewDispatcherMessageTypeBackSearchScene;
+    message.custom_event = event;
+
+    furi_check(osMessageQueuePut(view_dispatcher->queue, &message, 0, osWaitForever) == osOK);
+}
+
 void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* view) {
     furi_assert(view_dispatcher);
     // Dispatch view exit event

+ 27 - 12
applications/gui/view_dispatcher.h

@@ -2,15 +2,12 @@
 
 #include "view.h"
 #include "gui.h"
+#include "view_navigator.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/** Prototype for custom event callback
- */
-typedef void (*CustomEventCallback)(uint32_t custom_event, void* context);
-
 /** ViewDispatcher view_port placement
  */
 typedef enum {
@@ -37,18 +34,36 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher);
  */
 void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher);
 
-/** Set custom event callback
- * Custom callback is called when custom event in internal queue received
- */
-void view_dispatcher_set_custom_callback(
-    ViewDispatcher* view_dispatcher,
-    CustomEventCallback callback,
-    void* context);
-
 /** Send custom event
+ * @param view_dispatcher ViewDispatcher instance
  */
 void view_dispatcher_send_custom_event(ViewDispatcher* view_dispatcher, uint32_t event);
 
+/** Enable View Navigator to handle custom events and scene navigation
+ * @param view_dispatcher ViewDispatcher instance
+ * @param context  context for all scenes
+ */
+void view_dispatcher_enable_navigation(ViewDispatcher* view_dispatcher, void* context);
+
+/** Add Scene to view navigator
+ * Use only after navigation enabled
+ * @param view_dispatcher ViewDispatcher instance
+ * @param scene AppScene instance
+ */
+void view_dispatcher_add_scene(ViewDispatcher* view_dispatcher, AppScene* scene);
+
+/** Send navigation event
+ * @param view_dispatcher ViewDispatcher instance
+ * @param event event
+ */
+void view_dispatcher_send_navigation_event(ViewDispatcher* view_dispatcher, uint32_t event);
+
+/** Send search scene event
+ * @param view_dispatcher ViewDispatcher instance
+ * @param event event
+ */
+void view_dispatcher_send_back_search_scene_event(ViewDispatcher* view_dispatcher, uint32_t event);
+
 /** Run ViewDispatcher
  * Use only after queue enabled
  * @param view_dispatcher ViewDispatcher instance

+ 5 - 2
applications/gui/view_dispatcher_i.h

@@ -15,13 +15,14 @@ struct ViewDispatcher {
     ViewPort* view_port;
     ViewDict_t views;
     View* current_view;
-    CustomEventCallback custom_event_cb;
-    void* custom_event_ctx;
+    ViewNavigator* view_navigator;
 };
 
 typedef enum {
     ViewDispatcherMessageTypeInput,
     ViewDispatcherMessageTypeCustomEvent,
+    ViewDispatcherMessageTypeNavigationEvent,
+    ViewDispatcherMessageTypeBackSearchScene,
     ViewDispatcherMessageTypeStop,
 } ViewDispatcherMessageType;
 
@@ -30,6 +31,8 @@ typedef struct {
     union {
         InputEvent input;
         uint32_t custom_event;
+        ViewNavigatorEvent navigator_event;
+        uint32_t scene_id;
     };
 } ViewDispatcherMessage;
 

+ 4 - 0
applications/gui/view_i.h

@@ -11,6 +11,7 @@ typedef struct {
 struct View {
     ViewDrawCallback draw_callback;
     ViewInputCallback input_callback;
+    ViewCustomCallback custom_callback;
 
     ViewModelType model_type;
     ViewNavigationCallback previous_callback;
@@ -35,6 +36,9 @@ void view_draw(View* view, Canvas* canvas);
 /* Input Callback for View dispatcher */
 bool view_input(View* view, InputEvent* event);
 
+/* Custom Callback for View dispatcher */
+bool view_custom(View* view, uint32_t event);
+
 /* Previous Callback for View dispatcher */
 uint32_t view_previous(View* view);
 

+ 109 - 0
applications/gui/view_navigator.c

@@ -0,0 +1,109 @@
+#include "view_navigator_i.h"
+
+ViewNavigator* view_navigator_alloc(void* context) {
+    furi_assert(context);
+
+    ViewNavigator* view_navigator = furi_alloc(sizeof(ViewNavigator));
+    view_navigator->context = context;
+    ViewNavSceneArray_init(view_navigator->scene_array);
+
+    return view_navigator;
+}
+
+void view_navigator_free(ViewNavigator* view_navigator) {
+    furi_assert(view_navigator);
+    ViewNavSceneArray_clear(view_navigator->scene_array);
+
+    free(view_navigator);
+}
+
+bool view_navigator_handle_custom_event(ViewNavigator* view_navigator, uint32_t event) {
+    AppScene* scene = *ViewNavSceneArray_back(view_navigator->scene_array);
+    return scene->on_event(view_navigator->context, event);
+}
+
+bool view_navigator_handle_navigation_event(ViewNavigator* view_navigator, uint32_t event) {
+    if(event == ViewNavigatorEventNext) {
+        return view_navigator_next_scene(view_navigator);
+    } else if(event == ViewNavigatorEventBack) {
+        AppScene* scene = *ViewNavSceneArray_back(view_navigator->scene_array);
+        if(scene->on_event(view_navigator->context, ViewNavigatorEventBack)) {
+            return true;
+        } else {
+            return view_navigator_previous_scene(view_navigator);
+        }
+    }
+    return false;
+}
+
+bool view_navigator_handle_back_search_scene_event(ViewNavigator* view_navigator, uint32_t event) {
+    return view_navigator_search_previous_scene(view_navigator, event);
+}
+
+void view_navigator_add_next_scene(ViewNavigator* view_navigator, AppScene* scene) {
+    furi_assert(view_navigator);
+    furi_assert(scene);
+
+    ViewNavSceneArray_push_back(view_navigator->scene_array, scene);
+}
+
+void view_navigator_start(ViewNavigator* view_navigator) {
+    furi_assert(view_navigator);
+    AppScene* scene = *ViewNavSceneArray_front(view_navigator->scene_array);
+    furi_assert(scene);
+    scene->on_enter(view_navigator->context);
+}
+
+bool view_navigator_next_scene(ViewNavigator* view_navigator) {
+    ViewNavSceneArray_it_t scene_it;
+    ViewNavSceneArray_it_last(scene_it, view_navigator->scene_array);
+    ViewNavSceneArray_previous(scene_it);
+    AppScene* current_scene = *ViewNavSceneArray_ref(scene_it);
+    AppScene* next_scene = *ViewNavSceneArray_back(view_navigator->scene_array);
+    if(current_scene && next_scene) {
+        current_scene->on_exit(view_navigator->context);
+        next_scene->on_enter(view_navigator->context);
+        return true;
+    }
+    return false;
+}
+
+bool view_navigator_previous_scene(ViewNavigator* view_navigator) {
+    AppScene* current_scene = NULL;
+    ViewNavSceneArray_pop_back(&current_scene, view_navigator->scene_array);
+    if(ViewNavSceneArray_size(view_navigator->scene_array) == 0) {
+        // Handle exit from start scene separately
+        current_scene->on_exit(view_navigator->context);
+        return false;
+    }
+    AppScene* previous_scene = *ViewNavSceneArray_back(view_navigator->scene_array);
+    if(current_scene && previous_scene) {
+        current_scene->on_exit(view_navigator->context);
+        previous_scene->on_enter(view_navigator->context);
+        return true;
+    }
+    return false;
+}
+
+bool view_navigator_search_previous_scene(ViewNavigator* view_navigator, uint32_t scene_id) {
+    AppScene* previous_scene = NULL;
+    AppScene* current_scene = *ViewNavSceneArray_back(view_navigator->scene_array);
+    ViewNavSceneArray_it_t scene_it;
+    ViewNavSceneArray_it_last(scene_it, view_navigator->scene_array);
+    bool scene_found = false;
+    while(!scene_found) {
+        ViewNavSceneArray_previous(scene_it);
+        previous_scene = *ViewNavSceneArray_ref(scene_it);
+        if(previous_scene == NULL) {
+            return false;
+        }
+        if(previous_scene->id == scene_id) {
+            scene_found = true;
+        }
+    }
+    ViewNavSceneArray_next(scene_it);
+    ViewNavSceneArray_pop_until(view_navigator->scene_array, scene_it);
+    current_scene->on_exit(view_navigator->context);
+    previous_scene->on_enter(view_navigator->context);
+    return true;
+}

+ 28 - 0
applications/gui/view_navigator.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "app_scene.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    ViewNavigatorEventNext = 0x00000000UL,
+    ViewNavigatorEventBack = 0xFFFFFFFFUL,
+} ViewNavigatorEvent;
+
+typedef struct ViewNavigator ViewNavigator;
+
+ViewNavigator* view_navigator_alloc(void* context);
+void view_navigator_free(ViewNavigator* view_navigator);
+
+bool view_navigator_handle_custom_event(ViewNavigator* view_navigator, uint32_t event);
+bool view_navigator_handle_navigation_event(ViewNavigator* view_navigator, uint32_t event);
+bool view_navigator_handle_back_search_scene_event(ViewNavigator* view_navigator, uint32_t event);
+
+void view_navigator_add_next_scene(ViewNavigator* view_navigator, AppScene* scene);
+void view_navigator_start(ViewNavigator* view_navigator);
+
+#ifdef __cplusplus
+}
+#endif

+ 16 - 0
applications/gui/view_navigator_i.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include "view_navigator.h"
+#include <furi.h>
+#include <m-array.h>
+
+ARRAY_DEF(ViewNavSceneArray, AppScene*, M_PTR_OPLIST);
+
+struct ViewNavigator {
+    ViewNavSceneArray_t scene_array;
+    void* context;
+};
+
+bool view_navigator_next_scene(ViewNavigator* view_navigator);
+bool view_navigator_previous_scene(ViewNavigator* view_navigator);
+bool view_navigator_search_previous_scene(ViewNavigator* view_navigator, uint32_t scene_id);

+ 86 - 55
applications/nfc/nfc.c

@@ -1,64 +1,47 @@
 #include "nfc_i.h"
 #include "api-hal-nfc.h"
-
-uint32_t nfc_view_exit(void* context) {
-    return VIEW_NONE;
-}
-
-void nfc_menu_callback(void* context, uint32_t index) {
-    furi_assert(context);
-
-    Nfc* nfc = (Nfc*)context;
-    if(index == NfcSubmenuDetect) {
-        view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDetect);
-    } else if(index == NfcSubmenuEmulate) {
-        view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewEmulate);
-    } else if(index == NfcSubmenuEMV) {
-        view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewEmv);
-    } else if(index == NfcSubmenuMifareUl) {
-        view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl);
-    }
-}
-
-void nfc_view_dispatcher_callback(uint32_t event, void* context) {
-    furi_assert(context);
-
-    Nfc* nfc = (Nfc*)context;
-    NfcMessage message;
-    osMessageQueueGet(nfc->message_queue, &message, NULL, osWaitForever);
-    if(event == NfcEventDetect) {
-        nfc_detect_view_dispatcher_callback(nfc->nfc_detect, &message);
-    } else if(event == NfcEventEmv) {
-        nfc_emv_view_dispatcher_callback(nfc->nfc_emv, &message);
-    } else if(event == NfcEventMifareUl) {
-        nfc_mifare_ul_view_dispatcher_callback(nfc->nfc_mifare_ul, &message);
-    }
-}
+#include "app_scene.h"
 
 Nfc* nfc_alloc() {
     Nfc* nfc = furi_alloc(sizeof(Nfc));
 
-    nfc->message_queue = osMessageQueueNew(8, sizeof(NfcMessage), NULL);
-    nfc->nfc_common.worker = nfc_worker_alloc(nfc->message_queue);
+    nfc->nfc_common.worker = nfc_worker_alloc();
     nfc->nfc_common.view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(nfc->nfc_common.view_dispatcher);
+    view_dispatcher_enable_navigation(nfc->nfc_common.view_dispatcher, nfc);
 
     // Open GUI record
     nfc->gui = furi_record_open("gui");
     view_dispatcher_attach_to_gui(
         nfc->nfc_common.view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
 
-    // Menu
+    // Open Notification record
+    nfc->notifications = furi_record_open("notification");
+
+    // Submenu
     nfc->submenu = submenu_alloc();
-    submenu_add_item(nfc->submenu, "Detect", NfcSubmenuDetect, nfc_menu_callback, nfc);
-    submenu_add_item(nfc->submenu, "Emulate", NfcSubmenuEmulate, nfc_menu_callback, nfc);
-    submenu_add_item(nfc->submenu, "Read bank card", NfcSubmenuEMV, nfc_menu_callback, nfc);
-    submenu_add_item(
-        nfc->submenu, "Read Mifare Ultralight", NfcSubmenuMifareUl, nfc_menu_callback, nfc);
+    view_dispatcher_add_view(
+        nfc->nfc_common.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));
 
-    View* submenu_view = submenu_get_view(nfc->submenu);
-    view_set_previous_callback(submenu_view, nfc_view_exit);
-    view_dispatcher_add_view(nfc->nfc_common.view_dispatcher, NfcViewMenu, submenu_view);
+    // Popup
+    nfc->popup = popup_alloc();
+    view_dispatcher_add_view(
+        nfc->nfc_common.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));
+
+    // 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));
 
     // Detect
     nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common);
@@ -82,12 +65,20 @@ Nfc* nfc_alloc() {
         NfcViewMifareUl,
         nfc_mifare_ul_get_view(nfc->nfc_mifare_ul));
 
-    // Set View Dispatcher custom event callback
-    view_dispatcher_set_custom_callback(
-        nfc->nfc_common.view_dispatcher, nfc_view_dispatcher_callback, nfc);
-
-    // Switch to menu
-    view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu);
+    // Scene allocation
+    nfc->scene_start = nfc_scene_start_alloc();
+    nfc->scene_read_card = nfc_scene_read_card_alloc();
+    nfc->scene_read_card_success = nfc_scene_read_card_success_alloc();
+    nfc->scene_card_menu = nfc_scene_card_menu_alloc();
+    nfc->scene_not_implemented = nfc_scene_not_implemented_alloc();
+    nfc->scene_debug_menu = nfc_scene_debug_menu_alloc();
+    nfc->scene_debug_detect = nfc_scene_debug_detect_alloc();
+    nfc->scene_debug_emulate = nfc_scene_debug_emulate_alloc();
+    nfc->scene_debug_read_emv = nfc_scene_debug_read_emv_alloc();
+    nfc->scene_debug_read_mifare_ul = nfc_scene_debug_read_mifare_ul_alloc();
+    nfc->scene_emulate_uid = nfc_scene_emulate_uid_alloc();
+
+    view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_start);
 
     return nfc;
 }
@@ -99,6 +90,22 @@ void nfc_free(Nfc* nfc) {
     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMenu);
     submenu_free(nfc->submenu);
 
+    // DialogEx
+    view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx);
+    dialog_ex_free(nfc->dialog_ex);
+
+    // Popup
+    view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewPopup);
+    popup_free(nfc->popup);
+
+    // TextInput
+    view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewTextInput);
+    text_input_free(nfc->text_input);
+
+    // ByteInput
+    view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput);
+    byte_input_free(nfc->byte_input);
+
     // Detect
     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect);
     nfc_detect_free(nfc->nfc_detect);
@@ -111,7 +118,7 @@ void nfc_free(Nfc* nfc) {
     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewEmv);
     nfc_emv_free(nfc->nfc_emv);
 
-    // Mifare ultralight
+    // Mifare Ultralight
     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewMifareUl);
     nfc_mifare_ul_free(nfc->nfc_mifare_ul);
 
@@ -119,15 +126,30 @@ void nfc_free(Nfc* nfc) {
     nfc_worker_stop(nfc->nfc_common.worker);
     nfc_worker_free(nfc->nfc_common.worker);
 
-    // View dispatcher
+    // Scenes
+    nfc_scene_start_free(nfc->scene_start);
+    nfc_scene_read_card_free(nfc->scene_read_card);
+    nfc_scene_read_card_success_free(nfc->scene_read_card_success);
+    nfc_scene_card_menu_free(nfc->scene_card_menu);
+    nfc_scene_not_implemented_free(nfc->scene_not_implemented);
+    nfc_scene_debug_menu_free(nfc->scene_debug_menu);
+    nfc_scene_debug_detect_free(nfc->scene_debug_detect);
+    nfc_scene_debug_emulate_free(nfc->scene_debug_emulate);
+    nfc_scene_debug_read_emv_free(nfc->scene_debug_read_emv);
+    nfc_scene_debug_read_mifare_ul_free(nfc->scene_debug_read_mifare_ul);
+    nfc_scene_emulate_uid_free(nfc->scene_emulate_uid);
+
+    // View Dispatcher
     view_dispatcher_free(nfc->nfc_common.view_dispatcher);
 
     // GUI
     furi_record_close("gui");
     nfc->gui = NULL;
 
-    // The rest
-    osMessageQueueDelete(nfc->message_queue);
+    // Notifications
+    furi_record_close("notification");
+    nfc->notifications = NULL;
+
     free(nfc);
 }
 
@@ -140,3 +162,12 @@ int32_t nfc_task(void* p) {
 
     return 0;
 }
+
+void nfc_set_text_store(Nfc* nfc, const char* text, ...) {
+    va_list args;
+    va_start(args, text);
+
+    vsnprintf(nfc->text_store, sizeof(nfc->text_store), text, args);
+
+    va_end(args);
+}

+ 10 - 1
applications/nfc/nfc_cli.c

@@ -56,8 +56,17 @@ 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 = {
+        .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1},
+        .uid_len = 7,
+        .atqa = {0x44, 0x00},
+        .sak = 0x00,
+        .device = NfcDeviceNfca,
+        .protocol = NfcDeviceProtocolMfUltralight,
+    };
+
     while(!cli_cmd_interrupt_received(cli)) {
-        if(api_hal_nfc_listen(ApiHalNfcEmulateParamsMifare, 100)) {
+        if(api_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 100)) {
             printf("Reader detected\r\n");
             api_hal_nfc_deactivate();
         }

+ 72 - 6
applications/nfc/nfc_i.h

@@ -10,33 +10,99 @@
 #include <gui/view.h>
 #include <gui/view_dispatcher.h>
 #include <cli/cli.h>
+#include <notification/notification-messages.h>
 
 #include <gui/modules/submenu.h>
+#include <gui/modules/dialog_ex.h>
+#include <gui/modules/popup.h>
+#include <gui/modules/text_input.h>
+#include <gui/modules/byte_input.h>
 
-#include "nfc_detect.h"
-#include "nfc_emulate.h"
-#include "nfc_emv.h"
-#include "nfc_mifare_ul.h"
+#include "views/nfc_detect.h"
+#include "views/nfc_emulate.h"
+#include "views/nfc_emv.h"
+#include "views/nfc_mifare_ul.h"
+
+#include "scenes/nfc_scene_start.h"
+#include "scenes/nfc_scene_read_card.h"
+#include "scenes/nfc_scene_read_card_success.h"
+#include "scenes/nfc_scene_card_menu.h"
+#include "scenes/nfc_scene_emulate_uid.h"
+#include "scenes/nfc_scene_not_implemented.h"
+
+// TODO delete debug scenes
+#include "scenes/nfc_scene_debug_menu.h"
+#include "scenes/nfc_scene_debug_detect.h"
+#include "scenes/nfc_scene_debug_emulate.h"
+#include "scenes/nfc_scene_debug_read_emv.h"
+#include "scenes/nfc_scene_debug_read_mifare_ul.h"
+
+#define NFC_TEXT_STORE_SIZE 128
 
 struct Nfc {
     NfcCommon nfc_common;
-    osMessageQueueId_t message_queue;
     Gui* gui;
-    Submenu* submenu;
+    NotificationApp* notifications;
+
+    char text_store[NFC_TEXT_STORE_SIZE + 1];
+
+    // Nfc Views
     NfcDetect* nfc_detect;
     NfcEmulate* nfc_emulate;
     NfcEmv* nfc_emv;
     NfcMifareUl* nfc_mifare_ul;
+
+    // Common Views
+    Submenu* submenu;
+    DialogEx* dialog_ex;
+    Popup* popup;
+    TextInput* text_input;
+    ByteInput* byte_input;
+
+    // Scenes
+    AppScene* scene_start;
+    AppScene* scene_read_card;
+    AppScene* scene_read_card_success;
+    AppScene* scene_card_menu;
+    AppScene* scene_not_implemented;
+    AppScene* scene_emulate_uid;
+
+    // TODO delete debug scenes
+    AppScene* scene_debug_menu;
+    AppScene* scene_debug_detect;
+    AppScene* scene_debug_emulate;
+    AppScene* scene_debug_read_emv;
+    AppScene* scene_debug_read_mifare_ul;
 };
 
 typedef enum {
     NfcViewMenu,
+    NfcViewDialogEx,
+    NfcViewPopup,
+    NfcViewTextInput,
+    NfcViewByteInput,
     NfcViewDetect,
     NfcViewEmulate,
     NfcViewEmv,
     NfcViewMifareUl,
 } NfcView;
 
+typedef enum {
+    NfcSceneStart,
+    NfcSceneReadCard,
+    NfcSceneReadCardSuccess,
+    NfcSceneCardMenu,
+    NfcSceneEmulateUID,
+    NfcSceneNotImplemented,
+    NfcSceneDebugMenu,
+    NfcSceneDebugDetect,
+    NfcSceneDebugEmulate,
+    NfcSceneDebugReadEmv,
+    NfcSceneDebugReadMifareUl,
+} NfcScene;
+
 Nfc* nfc_alloc();
 
 int32_t nfc_task(void* p);
+
+void nfc_set_text_store(Nfc* nfc, const char* text, ...);

+ 10 - 54
applications/nfc/nfc_types.h

@@ -9,51 +9,9 @@
 typedef struct {
     NfcWorker* worker;
     ViewDispatcher* view_dispatcher;
+    NfcWorkerResult worker_result;
 } NfcCommon;
 
-typedef enum {
-    NfcDeviceNfca,
-    NfcDeviceNfcb,
-    NfcDeviceNfcf,
-    NfcDeviceNfcv,
-} NfcDeviceType;
-
-typedef enum {
-    NfcDeviceProtocolUnknown,
-    NfcDeviceProtocolEMV,
-    NfcDeviceProtocolMfUltralight,
-} NfcProtocol;
-
-typedef struct {
-    uint8_t uid_len;
-    uint8_t uid[10];
-    uint8_t atqa[2];
-    uint8_t sak;
-    NfcDeviceType device;
-    NfcProtocol protocol;
-} NfcDeviceData;
-
-typedef struct {
-    NfcDeviceData nfc_data;
-    char name[32];
-    uint8_t number[8];
-} NfcEmvData;
-
-typedef struct {
-    NfcDeviceData nfc_data;
-    uint8_t man_block[12];
-    uint8_t otp[4];
-} NfcMifareUlData;
-
-typedef struct {
-    bool found;
-    union {
-        NfcDeviceData nfc_detect_data;
-        NfcEmvData nfc_emv_data;
-        NfcMifareUlData nfc_mifare_ul_data;
-    };
-} NfcMessage;
-
 typedef enum {
     NfcEventDetect,
     NfcEventEmv,
@@ -69,19 +27,17 @@ typedef enum {
 
 static inline const char* nfc_get_dev_type(rfalNfcDevType type) {
     if(type == RFAL_NFC_LISTEN_TYPE_NFCA) {
-        return "NFC-A";
+        return "NFC-A may be:";
     } else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) {
-        return "NFC-B";
+        return "NFC-B may be:";
     } else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) {
-        return "NFC-F";
-    } else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) {
-        return "NFC-B";
+        return "NFC-F may be:";
     } else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) {
-        return "NFC-V";
+        return "NFC-V may be:";
     } else if(type == RFAL_NFC_LISTEN_TYPE_ST25TB) {
-        return "NFC-ST25TB";
+        return "NFC-ST25TB may be:";
     } else if(type == RFAL_NFC_LISTEN_TYPE_AP2P) {
-        return "NFC-AP2P";
+        return "NFC-AP2P may be:";
     } else {
         return "Unknown";
     }
@@ -105,10 +61,10 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) {
 
 static inline const char* nfc_get_protocol(NfcProtocol protocol) {
     if(protocol == NfcDeviceProtocolEMV) {
-        return "EMV";
+        return "EMV bank card";
     } else if(protocol == NfcDeviceProtocolMfUltralight) {
-        return "Mifare UL";
+        return "Mifare Ultralight";
     } else {
-        return "Unknown";
+        return "Unrecognized";
     }
 }

+ 76 - 79
applications/nfc/nfc_worker.c

@@ -7,9 +7,8 @@
 
 /***************************** NFC Worker API *******************************/
 
-NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue) {
+NfcWorker* nfc_worker_alloc() {
     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker));
-    nfc_worker->message_queue = message_queue;
     // Worker thread attributes
     nfc_worker->thread_attr.name = "nfc_worker";
     nfc_worker->thread_attr.stack_size = 8192;
@@ -40,23 +39,33 @@ 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,
     NfcWorkerCallback callback,
     void* context) {
     furi_assert(nfc_worker);
     furi_assert(nfc_worker->state == NfcWorkerStateReady);
+    furi_assert(result_dest);
 
     nfc_worker->callback = callback;
     nfc_worker->context = context;
+    nfc_worker->last_result = result_dest;
     nfc_worker_change_state(nfc_worker, state);
     nfc_worker->thread = osThreadNew(nfc_worker_task, nfc_worker, &nfc_worker->thread_attr);
 }
 
 void nfc_worker_stop(NfcWorker* nfc_worker) {
     furi_assert(nfc_worker);
-    if(nfc_worker->state == NfcWorkerStateBroken) {
+    if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) {
         return;
     }
 
@@ -82,11 +91,11 @@ void nfc_worker_task(void* context) {
     } else if(nfc_worker->state == NfcWorkerStateReadEMV) {
         nfc_worker_read_emv(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateEmulateEMV) {
-        nfc_worker_field(nfc_worker);
+        nfc_worker_emulate_emv(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateReadMfUltralight) {
         nfc_worker_read_mf_ultralight(nfc_worker);
-        nfc_worker_emulate_emv(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateField) {
+        nfc_worker_field(nfc_worker);
     }
     api_hal_nfc_deactivate();
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
@@ -98,46 +107,50 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
     rfalNfcDevice* dev_list;
     rfalNfcDevice* dev;
     uint8_t dev_cnt;
-    NfcMessage message;
+    NfcDeviceData* result = &nfc_worker->last_result->nfc_detect_data;
 
     while(nfc_worker->state == NfcWorkerStateDetect) {
-        message.found = false;
         if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) {
             // Process first found device
             dev = &dev_list[0];
-            message.found = true;
-            message.nfc_detect_data.uid_len = dev->nfcidLen;
-            memcpy(message.nfc_detect_data.uid, dev->nfcid, dev->nfcidLen);
-
+            result->uid_len = dev->nfcidLen;
+            memcpy(result->uid, dev->nfcid, dev->nfcidLen);
             if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) {
-                message.nfc_detect_data.device = NfcDeviceNfca;
-                message.nfc_detect_data.atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
-                message.nfc_detect_data.atqa[1] = dev->dev.nfca.sensRes.platformInfo;
-                message.nfc_detect_data.sak = dev->dev.nfca.selRes.sak;
-                // TODO check protocols
+                result->device = NfcDeviceNfca;
+                result->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
+                result->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
+                result->sak = dev->dev.nfca.selRes.sak;
+                if(mf_ul_check_card_type(
+                       dev->dev.nfca.sensRes.anticollisionInfo,
+                       dev->dev.nfca.sensRes.platformInfo,
+                       dev->dev.nfca.selRes.sak)) {
+                    result->protocol = NfcDeviceProtocolMfUltralight;
+                } else {
+                    result->protocol = NfcDeviceProtocolUnknown;
+                }
 
             } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) {
-                message.nfc_detect_data.device = NfcDeviceNfcb;
+                result->device = NfcDeviceNfcb;
             } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) {
-                message.nfc_detect_data.device = NfcDeviceNfcf;
+                result->device = NfcDeviceNfcf;
             } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) {
-                message.nfc_detect_data.device = NfcDeviceNfcv;
+                result->device = NfcDeviceNfcv;
             }
+            // Notify caller and exit
+            if(nfc_worker->callback) {
+                nfc_worker->callback(nfc_worker->context);
+            }
+            break;
         }
-        if(nfc_worker->callback) {
-            nfc_worker->callback(nfc_worker->context);
-        }
-        furi_check(
-            osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
         osDelay(100);
     }
 }
 
 void nfc_worker_emulate(NfcWorker* nfc_worker) {
+    NfcDeviceData* param = &nfc_worker->emulate_params;
     while(nfc_worker->state == NfcWorkerStateEmulate) {
-        if(api_hal_nfc_listen(ApiHalNfcEmulateParamsMifare, 100)) {
+        if(api_hal_nfc_listen(param->uid, param->uid_len, param->atqa, param->sak, 100)) {
             FURI_LOG_I(NFC_WORKER_TAG, "Reader detected");
-            api_hal_nfc_deactivate();
         }
         osDelay(10);
     }
@@ -152,14 +165,9 @@ 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;
 
-    NfcMessage message = {.found = false};
     while(nfc_worker->state == NfcWorkerStateReadEMV) {
-        if(nfc_worker->callback) {
-            nfc_worker->callback(nfc_worker->context);
-        }
-        furi_check(
-            osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
         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
@@ -169,7 +177,6 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                 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);
-                    message.found = false;
                     api_hal_nfc_deactivate();
                     continue;
                 }
@@ -179,7 +186,6 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced");
                 } else {
                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application");
-                    message.found = false;
                     api_hal_nfc_deactivate();
                     continue;
                 }
@@ -189,7 +195,6 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                 if(err != ERR_NONE) {
                     FURI_LOG_E(
                         NFC_WORKER_TAG, "Error during application selection request: %d", err);
-                    message.found = false;
                     api_hal_nfc_deactivate();
                     continue;
                 }
@@ -198,10 +203,9 @@ 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(message.nfc_emv_data.name, emv_app.name, sizeof(emv_app.name));
+                    memcpy(result->name, emv_app.name, sizeof(emv_app.name));
                 } else {
                     FURI_LOG_E(NFC_WORKER_TAG, "Can't read card name");
-                    message.found = false;
                     api_hal_nfc_deactivate();
                     continue;
                 }
@@ -211,19 +215,17 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                 if(err != ERR_NONE) {
                     FURI_LOG_E(
                         NFC_WORKER_TAG, "Error during Get Processing Options command: %d", err);
-                    message.found = false;
                     api_hal_nfc_deactivate();
                     continue;
                 }
                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) {
                     FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed");
-                    message.found = true;
-                    memcpy(
-                        message.nfc_emv_data.number,
-                        emv_app.card_number,
-                        sizeof(emv_app.card_number));
-                    api_hal_nfc_deactivate();
-                    continue;
+                    memcpy(result->number, emv_app.card_number, sizeof(emv_app.card_number));
+                    // Notify caller and exit
+                    if(nfc_worker->callback) {
+                        nfc_worker->callback(nfc_worker->context);
+                    }
+                    break;
                 } else {
                     // Mastercard doesn't give PAN / card number as GPO response
                     // Iterate over all files found in application
@@ -253,27 +255,25 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                     }
                     if(pan_found) {
                         FURI_LOG_I(NFC_WORKER_TAG, "Card PAN found");
-                        message.found = true;
-                        memcpy(
-                            message.nfc_emv_data.number,
-                            emv_app.card_number,
-                            sizeof(emv_app.card_number));
+                        memcpy(result->number, emv_app.card_number, sizeof(emv_app.card_number));
+                        // Notify caller and exit
+                        if(nfc_worker->callback) {
+                            nfc_worker->callback(nfc_worker->context);
+                        }
+                        break;
                     } else {
                         FURI_LOG_E(NFC_WORKER_TAG, "Can't read card number");
-                        message.found = false;
                     }
                     api_hal_nfc_deactivate();
                 }
             } else {
                 // Can't find EMV card
                 FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV");
-                message.found = false;
                 api_hal_nfc_deactivate();
             }
         } else {
             // Can't find EMV card
             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards");
-            message.found = false;
             api_hal_nfc_deactivate();
         }
         osDelay(20);
@@ -286,9 +286,17 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
     uint16_t tx_len = 0;
     uint8_t* rx_buff;
     uint16_t* rx_len;
+    NfcDeviceData params = {
+        .uid = {0xCF, 0x72, 0xd4, 0x40},
+        .uid_len = 4,
+        .atqa = {0x00, 0x04},
+        .sak = 0x20,
+        .device = NfcDeviceNfca,
+        .protocol = NfcDeviceProtocolEMV,
+    };
 
     while(nfc_worker->state == NfcWorkerStateEmulateEMV) {
-        if(api_hal_nfc_listen(ApiHalNfcEmulateParamsEMV, 1000)) {
+        if(api_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 100)) {
             FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected");
             // Read data from POS terminal
             err = api_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
@@ -344,15 +352,9 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) {
     uint8_t* rx_buff;
     uint16_t* rx_len;
     MfUltralightRead mf_ul_read;
+    NfcMifareUlData* result = &nfc_worker->last_result->nfc_mifare_ul_data;
 
-    // Update screen before start searching
-    NfcMessage message = {.found = false};
     while(nfc_worker->state == NfcWorkerStateReadMfUltralight) {
-        if(nfc_worker->callback) {
-            nfc_worker->callback(nfc_worker->context);
-        }
-        furi_check(
-            osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK);
         api_hal_nfc_deactivate();
         memset(&mf_ul_read, 0, sizeof(mf_ul_read));
         if(api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
@@ -383,7 +385,6 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) {
                     api_hal_nfc_deactivate();
                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search");
-                        message.found = false;
                         continue;
                     }
                 } else {
@@ -391,7 +392,6 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) {
                         NFC_WORKER_TAG,
                         "Error getting Mifare Ultralight version. Error code: %d",
                         err);
-                    message.found = false;
                     continue;
                 }
 
@@ -411,7 +411,6 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) {
                         mf_ul_read.pages_readed = mf_ul_read.pages_to_read;
                     } else {
                         FURI_LOG_E(NFC_WORKER_TAG, "Fast read failed");
-                        message.found = false;
                         continue;
                     }
                 } else {
@@ -431,20 +430,15 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) {
                     }
                 }
 
-                // Fill message for nfc application
-                message.found = true;
-                message.nfc_mifare_ul_data.nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
-                message.nfc_mifare_ul_data.nfc_data.atqa[0] =
-                    dev_list[0].dev.nfca.sensRes.anticollisionInfo;
-                message.nfc_mifare_ul_data.nfc_data.atqa[1] =
-                    dev_list[0].dev.nfca.sensRes.platformInfo;
-                message.nfc_mifare_ul_data.nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
+                // Fill result data
+                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(
-                    message.nfc_mifare_ul_data.nfc_data.uid,
-                    dev_list[0].dev.nfca.nfcId1,
-                    message.nfc_mifare_ul_data.nfc_data.uid_len);
-                memcpy(message.nfc_mifare_ul_data.man_block, mf_ul_read.dump, 4 * 3);
-                memcpy(message.nfc_mifare_ul_data.otp, &mf_ul_read.dump[4 * 3], 4);
+                    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);
                 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++) {
@@ -452,12 +446,15 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) {
                     }
                     printf("\r\n");
                 }
+                // Notify caller and exit
+                if(nfc_worker->callback) {
+                    nfc_worker->callback(nfc_worker->context);
+                }
+                break;
             } else {
-                message.found = false;
                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight");
             }
         } else {
-            message.found = false;
             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags");
         }
         osDelay(100);

+ 46 - 1
applications/nfc/nfc_worker.h

@@ -1,5 +1,47 @@
 #pragma once
 
+typedef enum {
+    NfcDeviceNfca,
+    NfcDeviceNfcb,
+    NfcDeviceNfcf,
+    NfcDeviceNfcv,
+} NfcDeviceType;
+
+typedef enum {
+    NfcDeviceProtocolUnknown,
+    NfcDeviceProtocolEMV,
+    NfcDeviceProtocolMfUltralight,
+} NfcProtocol;
+
+typedef struct {
+    uint8_t uid_len;
+    uint8_t uid[10];
+    uint8_t atqa[2];
+    uint8_t sak;
+    NfcDeviceType device;
+    NfcProtocol protocol;
+} NfcDeviceData;
+
+typedef struct {
+    NfcDeviceData nfc_data;
+    char name[32];
+    uint8_t number[8];
+} NfcEmvData;
+
+typedef struct {
+    NfcDeviceData nfc_data;
+    uint8_t man_block[12];
+    uint8_t otp[4];
+} NfcMifareUlData;
+
+typedef struct {
+    union {
+        NfcDeviceData nfc_detect_data;
+        NfcEmvData nfc_emv_data;
+        NfcMifareUlData nfc_mifare_ul_data;
+    };
+} NfcWorkerResult;
+
 typedef struct NfcWorker NfcWorker;
 
 typedef enum {
@@ -20,17 +62,20 @@ typedef enum {
 
 typedef void (*NfcWorkerCallback)(void* context);
 
-NfcWorker* nfc_worker_alloc(osMessageQueueId_t message_queue);
+NfcWorker* nfc_worker_alloc();
 
 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,
     NfcWorkerCallback callback,
     void* context);
 

+ 2 - 1
applications/nfc/nfc_worker_i.h

@@ -20,9 +20,10 @@ struct NfcWorker {
     osThreadAttr_t thread_attr;
     osThreadId_t thread;
 
-    osMessageQueueId_t message_queue;
+    NfcWorkerResult* last_result;
     NfcWorkerCallback callback;
     void* context;
+    NfcDeviceData emulate_params;
 
     NfcWorkerState state;
     ReturnCode error;

+ 95 - 0
applications/nfc/scenes/nfc_scene_card_menu.c

@@ -0,0 +1,95 @@
+#include "nfc_scene_card_menu.h"
+#include "../nfc_i.h"
+
+#include <furi.h>
+#include <gui/modules/submenu.h>
+#include <gui/view_dispatcher.h>
+
+typedef enum {
+    SubmenuIndexRunApp,
+    SubmenuIndexChooseScript,
+    SubmenuIndexEmulate,
+    SubmenuIndexSave,
+} 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);
+}
+
+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);
+    submenu_add_item(
+        submenu,
+        "Additional reading scripts",
+        SubmenuIndexChooseScript,
+        nfc_scene_card_menu_submenu_callback,
+        nfc);
+    submenu_add_item(
+        submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_card_menu_submenu_callback, nfc);
+    submenu_add_item(
+        submenu, "Name and save UID", SubmenuIndexSave, nfc_scene_card_menu_submenu_callback, nfc);
+
+    view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu);
+}
+
+const bool nfc_scene_card_menu_on_event(void* context, uint32_t event) {
+    Nfc* nfc = (Nfc*)context;
+
+    if(event == SubmenuIndexRunApp) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexChooseScript) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexEmulate) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_emulate_uid);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexSave) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == ViewNavigatorEventBack) {
+        view_dispatcher_send_back_search_scene_event(
+            nfc->nfc_common.view_dispatcher, NfcSceneStart);
+        return true;
+    }
+
+    return false;
+}
+
+const void nfc_scene_card_menu_on_exit(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    submenu_clean(nfc->submenu);
+}
+
+AppScene* nfc_scene_card_menu_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneCardMenu;
+    scene->on_enter = nfc_scene_card_menu_on_enter;
+    scene->on_event = nfc_scene_card_menu_on_event;
+    scene->on_exit = nfc_scene_card_menu_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_card_menu_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_card_menu.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_card_menu_alloc();
+
+void nfc_scene_card_menu_free(AppScene* scene);

+ 31 - 0
applications/nfc/scenes/nfc_scene_debug_detect.c

@@ -0,0 +1,31 @@
+#include "nfc_scene_debug_detect.h"
+#include "../nfc_i.h"
+
+#include <furi.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, uint32_t event) {
+    return false;
+}
+
+const void nfc_scene_debug_detect_on_exit(void* context) {
+}
+
+AppScene* nfc_scene_debug_detect_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneDebugDetect;
+    scene->on_enter = nfc_scene_debug_detect_on_enter;
+    scene->on_event = nfc_scene_debug_detect_on_event;
+    scene->on_exit = nfc_scene_debug_detect_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_debug_detect_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_debug_detect.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_debug_detect_alloc();
+
+void nfc_scene_debug_detect_free(AppScene* scene);

+ 31 - 0
applications/nfc/scenes/nfc_scene_debug_emulate.c

@@ -0,0 +1,31 @@
+#include "nfc_scene_debug_emulate.h"
+#include "../nfc_i.h"
+
+#include <furi.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, uint32_t event) {
+    return false;
+}
+
+const void nfc_scene_debug_emulate_on_exit(void* context) {
+}
+
+AppScene* nfc_scene_debug_emulate_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneDebugEmulate;
+    scene->on_enter = nfc_scene_debug_emulate_on_enter;
+    scene->on_event = nfc_scene_debug_emulate_on_event;
+    scene->on_exit = nfc_scene_debug_emulate_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_debug_emulate_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_debug_emulate.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_debug_emulate_alloc();
+
+void nfc_scene_debug_emulate_free(AppScene* scene);

+ 88 - 0
applications/nfc/scenes/nfc_scene_debug_menu.c

@@ -0,0 +1,88 @@
+#include "nfc_scene_debug_menu.h"
+#include "../nfc_i.h"
+
+#include <furi.h>
+#include <gui/modules/submenu.h>
+#include <gui/view_dispatcher.h>
+
+typedef enum {
+    SubmenuIndexDetect,
+    SubmenuIndexEmulate,
+    SubmenuIndexReadEmv,
+    SubmenuIndexReadMifareUl,
+} SubmenuIndex;
+
+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);
+
+    view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu);
+}
+
+const bool nfc_scene_debug_menu_on_event(void* context, uint32_t event) {
+    Nfc* nfc = (Nfc*)context;
+
+    if(event == SubmenuIndexDetect) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_debug_detect);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexEmulate) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_debug_emulate);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexReadEmv) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_debug_read_emv);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexReadMifareUl) {
+        view_dispatcher_add_scene(
+            nfc->nfc_common.view_dispatcher, nfc->scene_debug_read_mifare_ul);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    }
+
+    return false;
+}
+
+const void nfc_scene_debug_menu_on_exit(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    submenu_clean(nfc->submenu);
+}
+
+AppScene* nfc_scene_debug_menu_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneDebugMenu;
+    scene->on_enter = nfc_scene_debug_menu_on_enter;
+    scene->on_event = nfc_scene_debug_menu_on_event;
+    scene->on_exit = nfc_scene_debug_menu_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_debug_menu_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_debug_menu.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_debug_menu_alloc();
+
+void nfc_scene_debug_menu_free(AppScene* scene);

+ 31 - 0
applications/nfc/scenes/nfc_scene_debug_read_emv.c

@@ -0,0 +1,31 @@
+#include "nfc_scene_debug_read_emv.h"
+#include "../nfc_i.h"
+
+#include <furi.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, uint32_t event) {
+    return false;
+}
+
+const void nfc_scene_debug_read_emv_on_exit(void* context) {
+}
+
+AppScene* nfc_scene_debug_read_emv_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneDebugReadEmv;
+    scene->on_enter = nfc_scene_debug_read_emv_on_enter;
+    scene->on_event = nfc_scene_debug_read_emv_on_event;
+    scene->on_exit = nfc_scene_debug_read_emv_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_debug_read_emv_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_debug_read_emv.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_debug_read_emv_alloc();
+
+void nfc_scene_debug_read_emv_free(AppScene* scene);

+ 31 - 0
applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.c

@@ -0,0 +1,31 @@
+#include "nfc_scene_debug_read_mifare_ul.h"
+#include "../nfc_i.h"
+
+#include <furi.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, uint32_t event) {
+    return false;
+}
+
+const void nfc_scene_debug_read_mifare_ul_on_exit(void* context) {
+}
+
+AppScene* nfc_scene_debug_read_mifare_ul_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneDebugReadMifareUl;
+    scene->on_enter = nfc_scene_debug_read_mifare_ul_on_enter;
+    scene->on_event = nfc_scene_debug_read_mifare_ul_on_event;
+    scene->on_exit = nfc_scene_debug_read_mifare_ul_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_debug_read_mifare_ul_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_debug_read_mifare_ul.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_debug_read_mifare_ul_alloc();
+
+void nfc_scene_debug_read_mifare_ul_free(AppScene* scene);

+ 70 - 0
applications/nfc/scenes/nfc_scene_emulate_uid.c

@@ -0,0 +1,70 @@
+#include <nfc/scenes/nfc_scene_emulate_uid.h>
+
+#include <furi.h>
+
+#include "../nfc_i.h"
+
+const void nfc_scene_emulate_uid_on_enter(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    // Setup view
+    Popup* popup = nfc->popup;
+    NfcDeviceData* data = &nfc->nfc_common.worker_result.nfc_detect_data;
+    if(data->uid_len == 4) {
+        nfc_set_text_store(
+            nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]);
+    } else if(data->uid_len == 7) {
+        nfc_set_text_store(
+            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, 4, I_RFIDDolphinSend_98x60);
+    popup_set_header(popup, "Emulating UID", 56, 31, AlignLeft, AlignTop);
+    popup_set_text(popup, nfc->text_store, 56, 43, AlignLeft, AlignTop);
+
+    // Setup and start worker
+    nfc_worker_set_emulation_params(
+        nfc->nfc_common.worker, &nfc->nfc_common.worker_result.nfc_detect_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);
+}
+
+const bool nfc_scene_emulate_uid_on_event(void* context, uint32_t event) {
+    return false;
+}
+
+const void nfc_scene_emulate_uid_on_exit(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    // Stop worker
+    nfc_worker_stop(nfc->nfc_common.worker);
+
+    // Clear view
+    Popup* popup = nfc->popup;
+    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
+    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
+    popup_set_icon(popup, 0, 0, I_Empty_1x1);
+}
+
+AppScene* nfc_scene_emulate_uid_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneEmulateUID;
+    scene->on_enter = nfc_scene_emulate_uid_on_enter;
+    scene->on_event = nfc_scene_emulate_uid_on_event;
+    scene->on_exit = nfc_scene_emulate_uid_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_emulate_uid_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_emulate_uid.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_emulate_uid_alloc();
+
+void nfc_scene_emulate_uid_free(AppScene* scene);

+ 61 - 0
applications/nfc/scenes/nfc_scene_not_implemented.c

@@ -0,0 +1,61 @@
+#include "nfc_scene_not_implemented.h"
+#include "../nfc_i.h"
+
+#include <furi.h>
+#include <gui/modules/dialog_ex.h>
+#include <gui/view_dispatcher.h>
+
+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);
+}
+
+const void nfc_scene_not_implemented_on_enter(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    // TODO Set data from worker
+    DialogEx* dialog_ex = nfc->dialog_ex;
+    dialog_ex_set_left_button_text(dialog_ex, "Back");
+    dialog_ex_set_header(dialog_ex, "Not implemented", 60, 24, AlignCenter, AlignCenter);
+    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);
+}
+
+const bool nfc_scene_not_implemented_on_event(void* context, uint32_t event) {
+    Nfc* nfc = (Nfc*)context;
+
+    if(event == DialogExResultLeft) {
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventBack);
+        return true;
+    }
+    return false;
+}
+
+const void nfc_scene_not_implemented_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_left_button_text(dialog_ex, NULL);
+    dialog_ex_set_result_callback(dialog_ex, NULL);
+    dialog_ex_set_context(dialog_ex, NULL);
+}
+
+AppScene* nfc_scene_not_implemented_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneReadCardSuccess;
+    scene->on_enter = nfc_scene_not_implemented_on_enter;
+    scene->on_event = nfc_scene_not_implemented_on_event;
+    scene->on_exit = nfc_scene_not_implemented_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_not_implemented_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_not_implemented.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_not_implemented_alloc();
+
+void nfc_scene_not_implemented_free(AppScene* scene);

+ 70 - 0
applications/nfc/scenes/nfc_scene_read_card.c

@@ -0,0 +1,70 @@
+#include <nfc/scenes/nfc_scene_read_card.h>
+
+#include <furi.h>
+
+#include "../nfc_i.h"
+#include "../views/nfc_detect.h"
+
+#include <gui/view_dispatcher.h>
+
+void nfc_read_card_worker_callback(void* context) {
+    Nfc* nfc = (Nfc*)context;
+    view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, NfcEventDetect);
+}
+
+const void nfc_scene_read_card_on_enter(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    // Setup view
+    Popup* popup = nfc->popup;
+    popup_set_header(popup, "Detecting\nNFC card", 70, 34, AlignLeft, AlignTop);
+    popup_set_icon(popup, 0, 4, I_RFIDDolphinReceive_98x60);
+
+    // Start worker
+    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);
+}
+
+const bool nfc_scene_read_card_on_event(void* context, uint32_t event) {
+    Nfc* nfc = (Nfc*)context;
+
+    if(event == NfcEventDetect) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_read_card_success);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    }
+    return false;
+}
+
+const void nfc_scene_read_card_on_exit(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    // Stop worker
+    nfc_worker_stop(nfc->nfc_common.worker);
+
+    // Clear view
+    Popup* popup = nfc->popup;
+    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
+    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
+    popup_set_icon(popup, 0, 0, I_Empty_1x1);
+}
+
+AppScene* nfc_scene_read_card_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneReadCard;
+    scene->on_enter = nfc_scene_read_card_on_enter;
+    scene->on_event = nfc_scene_read_card_on_event;
+    scene->on_exit = nfc_scene_read_card_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_read_card_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_read_card.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_read_card_alloc();
+
+void nfc_scene_read_card_free(AppScene* scene);

+ 109 - 0
applications/nfc/scenes/nfc_scene_read_card_success.c

@@ -0,0 +1,109 @@
+#include "nfc_scene_read_card_success.h"
+#include "../nfc_i.h"
+
+#include <furi.h>
+#include <gui/modules/dialog_ex.h>
+#include <gui/view_dispatcher.h>
+
+#define NFC_SCENE_READ_SUCCESS_SHIFT "              "
+
+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);
+}
+
+const void nfc_scene_read_card_success_on_enter(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    // Send notification
+    notification_message(nfc->notifications, &sequence_success);
+
+    // Setup view
+    NfcDeviceData* data = (NfcDeviceData*)&nfc->nfc_common.worker_result;
+    DialogEx* dialog_ex = nfc->dialog_ex;
+    dialog_ex_set_left_button_text(dialog_ex, "Retry");
+    dialog_ex_set_right_button_text(dialog_ex, "More");
+    dialog_ex_set_header(dialog_ex, nfc_get_dev_type(data->device), 36, 8, AlignLeft, AlignCenter);
+    dialog_ex_set_icon(dialog_ex, 8, 13, I_Medium_chip_22x21);
+    // Display UID
+    if(data->uid_len == 4) {
+        nfc_set_text_store(
+            nfc,
+            NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT
+                                         "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X",
+            nfc_get_protocol(data->protocol),
+            data->atqa[0],
+            data->atqa[1],
+            data->sak,
+            data->uid[0],
+            data->uid[1],
+            data->uid[2],
+            data->uid[3]);
+    } else if(data->uid_len == 7) {
+        nfc_set_text_store(
+            nfc,
+            NFC_SCENE_READ_SUCCESS_SHIFT
+            "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT
+            "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X",
+            nfc_get_protocol(data->protocol),
+            data->atqa[0],
+            data->atqa[1],
+            data->sak,
+            data->uid[0],
+            data->uid[1],
+            data->uid[2],
+            data->uid[3],
+            data->uid[4],
+            data->uid[5],
+            data->uid[6]);
+    }
+    dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
+    dialog_ex_set_context(dialog_ex, nfc);
+    dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_card_success_dialog_callback);
+
+    view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx);
+}
+
+const bool nfc_scene_read_card_success_on_event(void* context, uint32_t event) {
+    Nfc* nfc = (Nfc*)context;
+
+    if(event == DialogExResultLeft) {
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventBack);
+        return true;
+    } else if(event == DialogExResultRight) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_card_menu);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    }
+    return false;
+}
+
+const void nfc_scene_read_card_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, I_Empty_1x1);
+    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);
+}
+
+AppScene* nfc_scene_read_card_success_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneReadCardSuccess;
+    scene->on_enter = nfc_scene_read_card_success_on_enter;
+    scene->on_event = nfc_scene_read_card_success_on_event;
+    scene->on_exit = nfc_scene_read_card_success_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_read_card_success_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_read_card_success.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_read_card_success_alloc();
+
+void nfc_scene_read_card_success_free(AppScene* scene);

+ 92 - 0
applications/nfc/scenes/nfc_scene_start.c

@@ -0,0 +1,92 @@
+#include "nfc_scene_start.h"
+#include "../nfc_i.h"
+
+#include <furi.h>
+#include <gui/modules/submenu.h>
+#include <gui/view_dispatcher.h>
+
+typedef enum {
+    SubmenuIndexRead,
+    SubmenuIndexRunScript,
+    SubmenuIndexSaved,
+    SubmenuIndexAddManualy,
+    SubmenuIndexDebug,
+} SubmenuIndex;
+
+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);
+}
+
+const void nfc_scene_start_on_enter(void* context) {
+    Nfc* nfc = (Nfc*)context;
+    Submenu* submenu = nfc->submenu;
+
+    submenu_add_item(
+        submenu, "Read card", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
+    submenu_add_item(
+        submenu,
+        "Run special action",
+        SubmenuIndexRunScript,
+        nfc_scene_start_submenu_callback,
+        nfc);
+    submenu_add_item(
+        submenu, "Saved cards", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
+    submenu_add_item(
+        submenu, "Add manualy", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
+    submenu_add_item(submenu, "Debug", SubmenuIndexDebug, nfc_scene_start_submenu_callback, nfc);
+
+    view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu);
+}
+
+const bool nfc_scene_start_on_event(void* context, uint32_t event) {
+    Nfc* nfc = (Nfc*)context;
+
+    if(event == SubmenuIndexRead) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_read_card);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexRunScript) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexSaved) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexAddManualy) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+        return true;
+    } else if(event == SubmenuIndexDebug) {
+        view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_debug_menu);
+        view_dispatcher_send_navigation_event(
+            nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext);
+    }
+    return false;
+}
+
+const void nfc_scene_start_on_exit(void* context) {
+    Nfc* nfc = (Nfc*)context;
+
+    submenu_clean(nfc->submenu);
+}
+
+AppScene* nfc_scene_start_alloc() {
+    AppScene* scene = furi_alloc(sizeof(AppScene));
+    scene->id = NfcSceneStart;
+    scene->on_enter = nfc_scene_start_on_enter;
+    scene->on_event = nfc_scene_start_on_event;
+    scene->on_exit = nfc_scene_start_on_exit;
+
+    return scene;
+}
+
+void nfc_scene_start_free(AppScene* scene) {
+    free(scene);
+}

+ 7 - 0
applications/nfc/scenes/nfc_scene_start.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "app_scene.h"
+
+AppScene* nfc_scene_start_alloc();
+
+void nfc_scene_start_free(AppScene* scene);

+ 15 - 18
applications/nfc/nfc_detect.c → applications/nfc/views/nfc_detect.c

@@ -1,11 +1,11 @@
 #include "nfc_detect.h"
 
-#include "nfc_i.h"
-#include "nfc_types.h"
 #include <furi.h>
 #include <api-hal.h>
 #include <input/input.h>
 
+#include "../nfc_i.h"
+
 struct NfcDetect {
     NfcCommon* nfc_common;
     View* view;
@@ -64,24 +64,24 @@ void nfc_detect_worker_callback(void* context) {
     view_dispatcher_send_custom_event(nfc_detect->nfc_common->view_dispatcher, NfcEventDetect);
 }
 
-void nfc_detect_view_dispatcher_callback(NfcDetect* nfc_detect, NfcMessage* message) {
-    furi_assert(nfc_detect);
-    furi_assert(message);
+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;
 
-    if(message->found) {
         with_view_model(
             nfc_detect->view, (NfcDetectModel * model) {
                 model->found = true;
-                model->data = message->nfc_detect_data;
-                return true;
-            });
-    } else {
-        with_view_model(
-            nfc_detect->view, (NfcDetectModel * model) {
-                model->found = false;
+                model->data = *data;
                 return true;
             });
+        // TODO add and configure next view model
+        return false;
     }
+
+    return false;
 }
 
 void nfc_detect_enter(void* context) {
@@ -97,6 +97,7 @@ void nfc_detect_enter(void* context) {
     nfc_worker_start(
         nfc_detect->nfc_common->worker,
         NfcWorkerStateDetect,
+        &nfc_detect->nfc_common->worker_result,
         nfc_detect_worker_callback,
         nfc_detect);
 }
@@ -108,10 +109,6 @@ void nfc_detect_exit(void* context) {
     nfc_worker_stop(nfc_detect->nfc_common->worker);
 }
 
-uint32_t nfc_detect_back(void* context) {
-    return NfcViewMenu;
-}
-
 NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common) {
     furi_assert(nfc_common);
 
@@ -124,9 +121,9 @@ NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common) {
     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);
-    view_set_previous_callback(nfc_detect->view, nfc_detect_back);
 
     return nfc_detect;
 }

+ 1 - 3
applications/nfc/nfc_detect.h → applications/nfc/views/nfc_detect.h

@@ -1,7 +1,7 @@
 #pragma once
 
 #include <gui/view.h>
-#include "nfc_types.h"
+#include "../nfc_types.h"
 
 typedef struct NfcDetect NfcDetect;
 
@@ -10,5 +10,3 @@ NfcDetect* nfc_detect_alloc(NfcCommon* nfc_common);
 void nfc_detect_free(NfcDetect* nfc_detect);
 
 View* nfc_detect_get_view(NfcDetect* nfc_detect);
-
-void nfc_detect_view_dispatcher_callback(NfcDetect* nfc_detect, NfcMessage* message);

+ 8 - 8
applications/nfc/nfc_emulate.c → applications/nfc/views/nfc_emulate.c

@@ -1,11 +1,11 @@
 #include "nfc_emulate.h"
 
-#include "nfc_i.h"
-#include "nfc_types.h"
 #include <furi.h>
 #include <api-hal.h>
 #include <input/input.h>
 
+#include "../nfc_i.h"
+
 struct NfcEmulate {
     NfcCommon* nfc_common;
     View* view;
@@ -33,7 +33,12 @@ void nfc_emulate_enter(void* context) {
     furi_assert(context);
 
     NfcEmulate* nfc_emulate = (NfcEmulate*)context;
-    nfc_worker_start(nfc_emulate->nfc_common->worker, NfcWorkerStateEmulate, NULL, NULL);
+    nfc_worker_start(
+        nfc_emulate->nfc_common->worker,
+        NfcWorkerStateEmulate,
+        &nfc_emulate->nfc_common->worker_result,
+        NULL,
+        NULL);
 }
 
 void nfc_emulate_exit(void* context) {
@@ -43,10 +48,6 @@ void nfc_emulate_exit(void* context) {
     nfc_worker_stop(nfc_emulate->nfc_common->worker);
 }
 
-uint32_t nfc_emulate_back(void* context) {
-    return NfcViewMenu;
-}
-
 NfcEmulate* nfc_emulate_alloc(NfcCommon* nfc_common) {
     furi_assert(nfc_common);
 
@@ -60,7 +61,6 @@ NfcEmulate* nfc_emulate_alloc(NfcCommon* nfc_common) {
     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);
-    view_set_previous_callback(nfc_emulate->view, nfc_emulate_back);
 
     return nfc_emulate;
 }

+ 1 - 1
applications/nfc/nfc_emulate.h → applications/nfc/views/nfc_emulate.h

@@ -1,7 +1,7 @@
 #pragma once
 
 #include <gui/view.h>
-#include "nfc_types.h"
+#include "../nfc_types.h"
 
 typedef struct NfcEmulate NfcEmulate;
 

+ 19 - 19
applications/nfc/nfc_emv.c → applications/nfc/views/nfc_emv.c

@@ -1,11 +1,11 @@
 #include "nfc_emv.h"
 
-#include "nfc_i.h"
-#include "nfc_types.h"
 #include <furi.h>
 #include <api-hal.h>
 #include <input/input.h>
 
+#include "../nfc_i.h"
+
 struct NfcEmv {
     NfcCommon* nfc_common;
     View* view;
@@ -56,24 +56,24 @@ void nfc_emv_worker_callback(void* context) {
     view_dispatcher_send_custom_event(nfc_emv->nfc_common->view_dispatcher, NfcEventEmv);
 }
 
-void nfc_emv_view_dispatcher_callback(NfcEmv* nfc_emv, NfcMessage* message) {
-    furi_assert(nfc_emv);
-    furi_assert(message);
+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;
 
-    if(message->found) {
         with_view_model(
             nfc_emv->view, (NfcEmvModel * model) {
                 model->found = true;
-                model->emv_data = message->nfc_emv_data;
-                return true;
-            });
-    } else {
-        with_view_model(
-            nfc_emv->view, (NfcEmvModel * model) {
-                model->found = false;
+                model->emv_data = *data;
                 return true;
             });
+        // TODO add and configure next view model
+        return true;
     }
+
+    return false;
 }
 
 void nfc_emv_enter(void* context) {
@@ -86,7 +86,11 @@ void nfc_emv_enter(void* context) {
             return true;
         });
     nfc_worker_start(
-        nfc_emv->nfc_common->worker, NfcWorkerStateReadEMV, nfc_emv_worker_callback, nfc_emv);
+        nfc_emv->nfc_common->worker,
+        NfcWorkerStateReadEMV,
+        &nfc_emv->nfc_common->worker_result,
+        nfc_emv_worker_callback,
+        nfc_emv);
 }
 
 void nfc_emv_exit(void* context) {
@@ -96,10 +100,6 @@ void nfc_emv_exit(void* context) {
     nfc_worker_stop(nfc_emv->nfc_common->worker);
 }
 
-uint32_t nfc_emv_back(void* context) {
-    return NfcViewMenu;
-}
-
 NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common) {
     furi_assert(nfc_common);
 
@@ -112,9 +112,9 @@ NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common) {
     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);
-    view_set_previous_callback(nfc_emv->view, nfc_emv_back);
 
     return nfc_emv;
 }

+ 1 - 3
applications/nfc/nfc_emv.h → applications/nfc/views/nfc_emv.h

@@ -1,7 +1,7 @@
 #pragma once
 
 #include <gui/view.h>
-#include "nfc_types.h"
+#include "../nfc_types.h"
 
 typedef struct NfcEmv NfcEmv;
 
@@ -10,5 +10,3 @@ NfcEmv* nfc_emv_alloc(NfcCommon* nfc_common);
 void nfc_emv_free(NfcEmv* nfc_emv);
 
 View* nfc_emv_get_view(NfcEmv* nfc_emv);
-
-void nfc_emv_view_dispatcher_callback(NfcEmv* nfc_emv, NfcMessage* message);

+ 15 - 18
applications/nfc/nfc_mifare_ul.c → applications/nfc/views/nfc_mifare_ul.c

@@ -1,11 +1,11 @@
 #include "nfc_mifare_ul.h"
 
-#include "nfc_i.h"
-#include "nfc_types.h"
 #include <furi.h>
 #include <api-hal.h>
 #include <input/input.h>
 
+#include "../nfc_i.h"
+
 struct NfcMifareUl {
     NfcCommon* nfc_common;
     View* view;
@@ -85,24 +85,24 @@ void nfc_mifare_ul_worker_callback(void* context) {
         nfc_mifare_ul->nfc_common->view_dispatcher, NfcEventMifareUl);
 }
 
-void nfc_mifare_ul_view_dispatcher_callback(NfcMifareUl* nfc_mifare_ul, NfcMessage* message) {
-    furi_assert(nfc_mifare_ul);
-    furi_assert(message);
+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;
 
-    if(message->found) {
         with_view_model(
             nfc_mifare_ul->view, (NfcMifareUlModel * model) {
                 model->found = true;
-                model->nfc_mf_ul_data = message->nfc_mifare_ul_data;
-                return true;
-            });
-    } else {
-        with_view_model(
-            nfc_mifare_ul->view, (NfcMifareUlModel * model) {
-                model->found = false;
+                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) {
@@ -117,6 +117,7 @@ void nfc_mifare_ul_enter(void* context) {
     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);
 }
@@ -128,10 +129,6 @@ void nfc_mifare_ul_exit(void* context) {
     nfc_worker_stop(nfc_mifare_ul->nfc_common->worker);
 }
 
-uint32_t nfc_mifare_ul_back(void* context) {
-    return NfcViewMenu;
-}
-
 NfcMifareUl* nfc_mifare_ul_alloc(NfcCommon* nfc_common) {
     furi_assert(nfc_common);
 
@@ -144,9 +141,9 @@ NfcMifareUl* nfc_mifare_ul_alloc(NfcCommon* nfc_common) {
     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);
-    view_set_previous_callback(nfc_mifare_ul->view, nfc_mifare_ul_back);
 
     return nfc_mifare_ul;
 }

+ 1 - 3
applications/nfc/nfc_mifare_ul.h → applications/nfc/views/nfc_mifare_ul.h

@@ -1,7 +1,7 @@
 #pragma once
 
 #include <gui/view.h>
-#include "nfc_types.h"
+#include "../nfc_types.h"
 
 typedef struct NfcMifareUl NfcMifareUl;
 
@@ -10,5 +10,3 @@ 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);
-
-void nfc_mifare_ul_view_dispatcher_callback(NfcMifareUl* nfc_mifare_ul, NfcMessage* message);

Datei-Diff unterdrückt, da er zu groß ist
+ 14 - 29
assets/compiled/assets_icons.c


+ 122 - 120
assets/compiled/assets_icons.h

@@ -3,148 +3,150 @@
 #include <gui/icon.h>
 
 typedef enum {
-	A_FX_Sitting_40x27,
-	A_MDIB_32x32,
-	A_MDI_32x32,
-	A_MDWLB_32x32,
-	A_MDWL_32x32,
-	A_MDWRB_32x32,
-	A_MDWR_32x32,
-	A_WatchingTV_128x64,
-	A_Wink_128x64,
-	I_125_10px,
-	I_ble_10px,
-	I_dir_10px,
-	I_ibutt_10px,
-	I_ir_10px,
+	I_KeyBackspaceSelected_16x9,
+	I_KeySave_24x11,
+	I_KeySaveSelected_24x11,
+	I_KeyBackspace_16x9,
+	I_Battery_26x8,
+	I_PlaceholderL_11x13,
+	I_Bluetooth_5x8,
+	I_BadUsb_9x8,
+	I_PlaceholderR_30x13,
+	I_USBConnected_15x8,
+	I_Battery_19x8,
+	I_Lock_8x8,
+	I_Background_128x11,
+	I_Background_128x8,
+	I_SDcardFail_11x8,
+	I_SDcardMounted_11x8,
 	I_Nfc_10px,
+	I_ir_10px,
+	I_ble_10px,
 	I_sub1_10px,
+	I_dir_10px,
 	I_unknown_10px,
-	I_ButtonCenter_7x7,
-	I_ButtonLeftSmall_3x5,
+	I_ibutt_10px,
+	I_125_10px,
+	A_iButton_14,
+	A_Plugins_14,
+	A_Bluetooth_14,
+	A_Games_14,
+	A_Infrared_14,
+	A_NFC_14,
+	A_FileManager_14,
+	A_Passport_14,
+	A_Settings_14,
+	A_Power_14,
+	A_125khz_14,
+	A_GPIO_14,
+	A_Tamagotchi_14,
+	A_U2F_14,
+	A_Sub1ghz_14,
 	I_ButtonLeft_4x7,
-	I_ButtonRightSmall_3x5,
 	I_ButtonRight_4x7,
+	I_ButtonRightSmall_3x5,
 	I_Empty_1x1,
-	I_BigBurger_24x24,
-	I_BigGames_24x24,
-	I_BigProfile_24x24,
-	I_DolphinFirstStart0_70x53,
-	I_DolphinFirstStart1_59x53,
-	I_DolphinFirstStart2_59x51,
-	I_DolphinFirstStart3_57x48,
-	I_DolphinFirstStart4_67x53,
-	I_DolphinFirstStart5_45x53,
-	I_DolphinFirstStart6_58x54,
-	I_DolphinFirstStart7_61x51,
-	I_DolphinFirstStart8_56x51,
-	I_DolphinOkay_41x43,
-	I_Flipper_young_80x60,
-	I_FX_Bang_32x6,
-	I_FX_SittingB_40x27,
-	I_DolphinExcited_64x63,
-	I_DolphinMafia_115x62,
-	I_DolphinNice_96x59,
-	I_DolphinWait_61x59,
-	I_iButtonDolphinSuccess_109x60,
-	I_iButtonDolphinVerySuccess_108x52,
-	I_iButtonKey_49x44,
-	I_DoorLeft_70x55,
-	I_DoorLeft_8x56,
-	I_DoorLocked_10x56,
-	I_DoorRight_70x55,
-	I_DoorRight_8x56,
-	I_LockPopup_100x49,
-	I_PassportBottom_128x17,
-	I_PassportLeft_6x47,
-	I_Back_15x10,
-	I_Down_25x27,
-	I_Down_hvr_25x27,
+	I_ButtonCenter_7x7,
+	I_ButtonLeftSmall_3x5,
+	I_Vol_up_25x27,
 	I_Fill_marker_7x7,
-	I_IrdaArrowDown_4x8,
 	I_IrdaArrowUp_4x8,
-	I_IrdaLearnShort_128x31,
-	I_IrdaLearn_128x64,
-	I_IrdaSendShort_128x34,
+	I_Down_hvr_25x27,
+	I_Vol_up_hvr_25x27,
+	I_Power_25x27,
+	I_Vol_down_25x27,
 	I_IrdaSend_128x64,
-	I_Mute_25x27,
+	I_Up_hvr_25x27,
+	I_Back_15x10,
+	I_IrdaSendShort_128x34,
 	I_Mute_hvr_25x27,
-	I_Power_25x27,
-	I_Power_hvr_25x27,
+	I_IrdaLearnShort_128x31,
+	I_Down_25x27,
 	I_Up_25x27,
-	I_Up_hvr_25x27,
-	I_Vol_down_25x27,
+	I_Mute_25x27,
 	I_Vol_down_hvr_25x27,
-	I_Vol_up_25x27,
-	I_Vol_up_hvr_25x27,
-	I_KeyBackspaceSelected_16x9,
-	I_KeyBackspace_16x9,
-	I_KeySaveSelected_24x11,
-	I_KeySave_24x11,
-	A_125khz_14,
-	A_Bluetooth_14,
-	A_FileManager_14,
-	A_Games_14,
-	A_GPIO_14,
-	A_iButton_14,
-	A_Infrared_14,
-	A_NFC_14,
-	A_Passport_14,
-	A_Plugins_14,
-	A_Power_14,
-	A_Settings_14,
-	A_Sub1ghz_14,
-	A_Tamagotchi_14,
-	A_U2F_14,
-	I_passport_bad1_43x45,
+	I_Power_hvr_25x27,
+	I_IrdaLearn_128x64,
+	I_IrdaArrowDown_4x8,
+	A_MDWRB_32x32,
+	A_MDWL_32x32,
+	A_WatchingTV_128x64,
+	A_MDWR_32x32,
+	A_FX_Sitting_40x27,
+	A_MDI_32x32,
+	A_Wink_128x64,
+	A_MDIB_32x32,
+	A_MDWLB_32x32,
+	I_RFIDBigChip_37x36,
+	I_RFIDDolphinReceive_98x60,
+	I_RFIDDolphinSuccess_108x57,
+	I_RFIDDolphinSend_98x60,
+	I_DoorRight_70x55,
+	I_DoorLocked_10x56,
+	I_DoorLeft_70x55,
+	I_PassportLeft_6x47,
+	I_DoorRight_8x56,
+	I_DoorLeft_8x56,
+	I_LockPopup_100x49,
+	I_PassportBottom_128x17,
+	I_Medium_chip_22x21,
+	I_EMV_Chip_14x11,
+	I_iButtonDolphinVerySuccess_108x52,
+	I_DolphinMafia_115x62,
+	I_iButtonDolphinSuccess_109x60,
+	I_DolphinExcited_64x63,
+	I_DolphinNice_96x59,
+	I_iButtonKey_49x44,
+	I_DolphinWait_61x59,
 	I_passport_bad2_43x45,
-	I_passport_bad3_43x45,
-	I_passport_happy1_43x45,
-	I_passport_happy2_43x45,
-	I_passport_happy3_43x45,
 	I_passport_okay1_43x45,
+	I_passport_happy3_43x45,
+	I_passport_bad1_43x45,
+	I_passport_happy2_43x45,
 	I_passport_okay2_43x45,
+	I_passport_happy1_43x45,
 	I_passport_okay3_43x45,
-	I_BatteryBody_52x28,
-	I_Battery_16x16,
-	I_FaceCharging_29x14,
-	I_FaceConfused_29x14,
-	I_FaceNopower_29x14,
-	I_FaceNormal_29x14,
-	I_Health_16x16,
-	I_Temperature_16x16,
-	I_Voltage_16x16,
-	I_RFIDBigChip_37x36,
-	I_RFIDDolphinReceive_98x60,
-	I_RFIDDolphinSend_98x60,
-	I_RFIDDolphinSuccess_108x57,
-	I_Home_painting_17x20,
+	I_passport_bad3_43x45,
+	I_SDQuestion_35x43,
+	I_SDError_43x35,
+	I_WalkLB1_32x32,
 	I_PC_22x29,
+	I_Home_painting_17x20,
 	I_Sofa_40x13,
-	I_TV_20x20,
-	I_TV_20x24,
+	I_WalkRB1_32x32,
 	I_WalkL1_32x32,
-	I_WalkL2_32x32,
-	I_WalkLB1_32x32,
-	I_WalkLB2_32x32,
 	I_WalkR1_32x32,
+	I_WalkL2_32x32,
 	I_WalkR2_32x32,
-	I_WalkRB1_32x32,
+	I_TV_20x24,
+	I_WalkLB2_32x32,
+	I_TV_20x20,
 	I_WalkRB2_32x32,
-	I_SDError_43x35,
-	I_SDQuestion_35x43,
-	I_Background_128x11,
-	I_Background_128x8,
-	I_BadUsb_9x8,
-	I_Battery_19x8,
-	I_Battery_26x8,
-	I_Bluetooth_5x8,
-	I_Lock_8x8,
-	I_PlaceholderL_11x13,
-	I_PlaceholderR_30x13,
-	I_SDcardFail_11x8,
-	I_SDcardMounted_11x8,
-	I_USBConnected_15x8,
+	I_Health_16x16,
+	I_FaceNopower_29x14,
+	I_Battery_16x16,
+	I_BatteryBody_52x28,
+	I_FaceConfused_29x14,
+	I_FaceCharging_29x14,
+	I_FaceNormal_29x14,
+	I_Voltage_16x16,
+	I_Temperature_16x16,
+	I_DolphinOkay_41x43,
+	I_DolphinFirstStart7_61x51,
+	I_DolphinFirstStart4_67x53,
+	I_DolphinFirstStart3_57x48,
+	I_FX_Bang_32x6,
+	I_Flipper_young_80x60,
+	I_DolphinFirstStart0_70x53,
+	I_DolphinFirstStart2_59x51,
+	I_DolphinFirstStart6_58x54,
+	I_FX_SittingB_40x27,
+	I_BigProfile_24x24,
+	I_DolphinFirstStart5_45x53,
+	I_BigGames_24x24,
+	I_DolphinFirstStart8_56x51,
+	I_BigBurger_24x24,
+	I_DolphinFirstStart1_59x53,
 } IconName;
 
 Icon * assets_icons_get(IconName name);

BIN
assets/icons/NFC/EMV_Chip_14x11.png


BIN
assets/icons/NFC/Medium-chip-22x21.png


+ 2 - 6
firmware/targets/api-hal-include/api-hal-nfc.h

@@ -9,11 +9,7 @@
 extern "C" {
 #endif
 
-/** Nfc emulation parameters */
-typedef enum {
-    ApiHalNfcEmulateParamsMifare,
-    ApiHalNfcEmulateParamsEMV,
-} ApiHalNfcEmulateParams;
+#define API_HAL_NFC_UID_MAX_LEN 10
 
 /**
  * Init nfc
@@ -53,7 +49,7 @@ bool api_hal_nfc_detect(rfalNfcDevice** dev_list, uint8_t* dev_cnt, uint32_t tim
 /**
  * NFC listen
  */
-bool api_hal_nfc_listen(ApiHalNfcEmulateParams params, uint32_t timeout);
+bool api_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout);
 
 /**
  * NFC data exchange

+ 20 - 55
firmware/targets/f5/api-hal/api-hal-nfc.c

@@ -3,53 +3,6 @@
 
 static const uint32_t clocks_in_ms = 64 * 1000;
 
-static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_mifare = {
-    .compMode = RFAL_COMPLIANCE_MODE_NFC,
-    .techs2Find = RFAL_NFC_LISTEN_TECH_A,
-    .totalDuration = 1000,
-    .devLimit = 1,
-    .wakeupEnabled = false,
-    .wakeupConfigDefault = true,
-    .nfcfBR = RFAL_BR_212,
-    .ap2pBR = RFAL_BR_424,
-    .maxBR = RFAL_BR_KEEP,
-    .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
-    .notifyCb = NULL,
-    .lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_07,
-    .lmConfigPA.nfcid[0] = 0X36,
-    .lmConfigPA.nfcid[1] = 0x9C,
-    .lmConfigPA.nfcid[2] = 0xE7,
-    .lmConfigPA.nfcid[3] = 0xB1,
-    .lmConfigPA.nfcid[4] = 0x0A,
-    .lmConfigPA.nfcid[5] = 0xC1,
-    .lmConfigPA.nfcid[6] = 0x34,
-    .lmConfigPA.SENS_RES[0] = 0x44,
-    .lmConfigPA.SENS_RES[1] = 0x00,
-    .lmConfigPA.SEL_RES = 0x00,
-};
-
-static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_emv = {
-    .compMode = RFAL_COMPLIANCE_MODE_EMV,
-    .techs2Find = RFAL_NFC_LISTEN_TECH_A,
-    .totalDuration = 1000,
-    .devLimit = 1,
-    .wakeupEnabled = false,
-    .wakeupConfigDefault = true,
-    .nfcfBR = RFAL_BR_212,
-    .ap2pBR = RFAL_BR_424,
-    .maxBR = RFAL_BR_KEEP,
-    .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
-    .notifyCb = NULL,
-    .lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_04,
-    .lmConfigPA.nfcid[0] = 0XCF,
-    .lmConfigPA.nfcid[1] = 0x72,
-    .lmConfigPA.nfcid[2] = 0xD4,
-    .lmConfigPA.nfcid[3] = 0x40,
-    .lmConfigPA.SENS_RES[0] = 0x04,
-    .lmConfigPA.SENS_RES[1] = 0x00,
-    .lmConfigPA.SEL_RES = 0x20,
-};
-
 ReturnCode api_hal_nfc_init() {
     // Check if Nfc worker was started
     rfalNfcState state = rfalNfcGetState();
@@ -135,9 +88,7 @@ bool api_hal_nfc_detect(rfalNfcDevice **dev_list, uint8_t* dev_cnt, uint32_t tim
     return true;
 }
 
-bool api_hal_nfc_listen(ApiHalNfcEmulateParams params, uint32_t timeout) {
-    api_hal_nfc_exit_sleep();
-
+bool api_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout) {
     rfalNfcState state = rfalNfcGetState();
     if(state == RFAL_NFC_STATE_NOTINIT) {
         rfalNfcInitialize();
@@ -145,11 +96,25 @@ bool api_hal_nfc_listen(ApiHalNfcEmulateParams params, uint32_t timeout) {
         rfalNfcDeactivate(false);
     }
 
-    if(params == ApiHalNfcEmulateParamsMifare) {
-        rfalNfcDiscover(&api_hal_nfc_emulate_params_mifare);
-    } else if(params == ApiHalNfcEmulateParamsEMV) {
-        rfalNfcDiscover(&api_hal_nfc_emulate_params_emv);
-    }
+    rfalNfcDiscoverParam params = {
+        .compMode = RFAL_COMPLIANCE_MODE_NFC,
+        .techs2Find = RFAL_NFC_LISTEN_TECH_A,
+        .totalDuration = 1000,
+        .devLimit = 1,
+        .wakeupEnabled = false,
+        .wakeupConfigDefault = true,
+        .nfcfBR = RFAL_BR_212,
+        .ap2pBR = RFAL_BR_424,
+        .maxBR = RFAL_BR_KEEP,
+        .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
+        .notifyCb = NULL,
+    };
+    params.lmConfigPA.nfcidLen = uid_len;
+    memcpy(params.lmConfigPA.nfcid, uid, uid_len);
+    params.lmConfigPA.SENS_RES[0] = atqa[0];
+    params.lmConfigPA.SENS_RES[1] = atqa[1];
+    params.lmConfigPA.SEL_RES = sak;
+    rfalNfcDiscover(&params);
 
     uint32_t start = DWT->CYCCNT;
     while(state != RFAL_NFC_STATE_ACTIVATED) {

+ 20 - 55
firmware/targets/f6/api-hal/api-hal-nfc.c

@@ -3,53 +3,6 @@
 
 static const uint32_t clocks_in_ms = 64 * 1000;
 
-static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_mifare = {
-    .compMode = RFAL_COMPLIANCE_MODE_NFC,
-    .techs2Find = RFAL_NFC_LISTEN_TECH_A,
-    .totalDuration = 1000,
-    .devLimit = 1,
-    .wakeupEnabled = false,
-    .wakeupConfigDefault = true,
-    .nfcfBR = RFAL_BR_212,
-    .ap2pBR = RFAL_BR_424,
-    .maxBR = RFAL_BR_KEEP,
-    .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
-    .notifyCb = NULL,
-    .lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_07,
-    .lmConfigPA.nfcid[0] = 0X36,
-    .lmConfigPA.nfcid[1] = 0x9C,
-    .lmConfigPA.nfcid[2] = 0xE7,
-    .lmConfigPA.nfcid[3] = 0xB1,
-    .lmConfigPA.nfcid[4] = 0x0A,
-    .lmConfigPA.nfcid[5] = 0xC1,
-    .lmConfigPA.nfcid[6] = 0x34,
-    .lmConfigPA.SENS_RES[0] = 0x44,
-    .lmConfigPA.SENS_RES[1] = 0x00,
-    .lmConfigPA.SEL_RES = 0x00,
-};
-
-static const rfalNfcDiscoverParam api_hal_nfc_emulate_params_emv = {
-    .compMode = RFAL_COMPLIANCE_MODE_EMV,
-    .techs2Find = RFAL_NFC_LISTEN_TECH_A,
-    .totalDuration = 1000,
-    .devLimit = 1,
-    .wakeupEnabled = false,
-    .wakeupConfigDefault = true,
-    .nfcfBR = RFAL_BR_212,
-    .ap2pBR = RFAL_BR_424,
-    .maxBR = RFAL_BR_KEEP,
-    .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
-    .notifyCb = NULL,
-    .lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_04,
-    .lmConfigPA.nfcid[0] = 0XCF,
-    .lmConfigPA.nfcid[1] = 0x72,
-    .lmConfigPA.nfcid[2] = 0xD4,
-    .lmConfigPA.nfcid[3] = 0x40,
-    .lmConfigPA.SENS_RES[0] = 0x04,
-    .lmConfigPA.SENS_RES[1] = 0x00,
-    .lmConfigPA.SEL_RES = 0x20,
-};
-
 ReturnCode api_hal_nfc_init() {
     // Check if Nfc worker was started
     rfalNfcState state = rfalNfcGetState();
@@ -135,9 +88,7 @@ bool api_hal_nfc_detect(rfalNfcDevice **dev_list, uint8_t* dev_cnt, uint32_t tim
     return true;
 }
 
-bool api_hal_nfc_listen(ApiHalNfcEmulateParams params, uint32_t timeout) {
-    api_hal_nfc_exit_sleep();
-
+bool api_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout) {
     rfalNfcState state = rfalNfcGetState();
     if(state == RFAL_NFC_STATE_NOTINIT) {
         rfalNfcInitialize();
@@ -145,11 +96,25 @@ bool api_hal_nfc_listen(ApiHalNfcEmulateParams params, uint32_t timeout) {
         rfalNfcDeactivate(false);
     }
 
-    if(params == ApiHalNfcEmulateParamsMifare) {
-        rfalNfcDiscover(&api_hal_nfc_emulate_params_mifare);
-    } else if(params == ApiHalNfcEmulateParamsEMV) {
-        rfalNfcDiscover(&api_hal_nfc_emulate_params_emv);
-    }
+    rfalNfcDiscoverParam params = {
+        .compMode = RFAL_COMPLIANCE_MODE_NFC,
+        .techs2Find = RFAL_NFC_LISTEN_TECH_A,
+        .totalDuration = 1000,
+        .devLimit = 1,
+        .wakeupEnabled = false,
+        .wakeupConfigDefault = true,
+        .nfcfBR = RFAL_BR_212,
+        .ap2pBR = RFAL_BR_424,
+        .maxBR = RFAL_BR_KEEP,
+        .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
+        .notifyCb = NULL,
+    };
+    params.lmConfigPA.nfcidLen = uid_len;
+    memcpy(params.lmConfigPA.nfcid, uid, uid_len);
+    params.lmConfigPA.SENS_RES[0] = atqa[0];
+    params.lmConfigPA.SENS_RES[1] = atqa[1];
+    params.lmConfigPA.SEL_RES = sak;
+    rfalNfcDiscover(&params);
 
     uint32_t start = DWT->CYCCNT;
     while(state != RFAL_NFC_STATE_ACTIVATED) {

+ 3 - 0
lib/ST25RFAL002/platform.h

@@ -23,12 +23,15 @@ HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t
 void platformProtectST25RComm();
 void platformUnprotectST25RComm();
 
+
 #define ST25R_SS_PIN NFC_CS_Pin
 #define ST25R_SS_PORT NFC_CS_GPIO_Port
 
 #define ST25R_INT_PIN NFC_IRQ_Pin
 #define ST25R_INT_PORT NFC_IRQ_GPIO_Port
 
+#define RFAL_ANALOG_CONFIG_CUSTOM              true       /*!< Enable/Disable RFAL custom analog configuration                           */
+
 #define RFAL_FEATURE_LISTEN_MODE               true       /*!< Enable/Disable RFAL support for Listen Mode                               */
 #define RFAL_FEATURE_WAKEUP_MODE               true       /*!< Enable/Disable RFAL support for the Wake-Up mode                          */
 #define RFAL_FEATURE_LOWPOWER_MODE             true       /*!< Enable/Disable RFAL support for the Low Power mode                        */

+ 309 - 0
lib/ST25RFAL002/source/custom_analog_config.c

@@ -0,0 +1,309 @@
+#include "rfal_analogConfigTbl.h"
+
+const uint8_t rfalAnalogConfigCustomSettings[] = {
+    /****** Default Analog Configuration for Chip-Specific Reset ******/
+    MODE_ENTRY_16_REG( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_INIT)
+                        , ST25R3916_REG_IO_CONF1, (ST25R3916_REG_IO_CONF1_out_cl_mask | ST25R3916_REG_IO_CONF1_lf_clk_off), 0x07                               /* Disable MCU_CLK */
+                        , ST25R3916_REG_IO_CONF2, (ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2 ), 0x18                                   /* SPI Pull downs */
+                        // , ST25R3916_REG_IO_CONF2,  ST25R3916_REG_IO_CONF2_aat_en, ST25R3916_REG_IO_CONF2_aat_en                                                /* Enable AAT */
+                        , ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_d_res_mask, 0x00                                                                    /* Set RFO resistance Active Tx */
+                        , ST25R3916_REG_RES_AM_MOD, 0xFF, 0x80                                                                                                 /* Use minimum non-overlap */
+                        , ST25R3916_REG_FIELD_THRESHOLD_ACTV,   ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask, ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV      /* Lower activation threshold (higher than deactivation)*/
+                        , ST25R3916_REG_FIELD_THRESHOLD_ACTV,   ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask, ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV      /* Lower activation threshold (higher than deactivation)*/
+                        , ST25R3916_REG_FIELD_THRESHOLD_DEACTV, ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask, ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV   /* Lower deactivation threshold */
+                        , ST25R3916_REG_FIELD_THRESHOLD_DEACTV, ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask, ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV   /* Lower deactivation threshold */
+                        , ST25R3916_REG_AUX_MOD, ST25R3916_REG_AUX_MOD_lm_ext, 0x00                                                                            /* Disable External Load Modulation */
+                        , ST25R3916_REG_AUX_MOD, ST25R3916_REG_AUX_MOD_lm_dri, ST25R3916_REG_AUX_MOD_lm_dri                                                    /* Use internal Load Modulation */
+                        , ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_fdel_mask, (5U<<ST25R3916_REG_PASSIVE_TARGET_fdel_shift)                  /* Adjust the FDT to be aligned with the bitgrid  */
+                        , ST25R3916_REG_PT_MOD, (ST25R3916_REG_PT_MOD_ptm_res_mask | ST25R3916_REG_PT_MOD_pt_res_mask), 0x5f                                   /* Reduce RFO resistance in Modulated state */
+                        , ST25R3916_REG_EMD_SUP_CONF, ST25R3916_REG_EMD_SUP_CONF_rx_start_emv, ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on                      /* Enable start on first 4 bits */
+                        , ST25R3916_REG_ANT_TUNE_A, 0xFF, 0x82                                                                                                 /* Set Antenna Tuning (Poller): ANTL */
+                        , ST25R3916_REG_ANT_TUNE_B, 0xFF, 0x82                                                                                                 /* Set Antenna Tuning (Poller): ANTL */
+                        , 0x84U, 0x10, 0x10                                                                                                                     /* Avoid chip internal overheat protection */
+                        )
+    
+    /****** Default Analog Configuration for Chip-Specific Poll Common ******/
+    , MODE_ENTRY_9_REG( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON)
+                        , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am  , ST25R3916_REG_MODE_tr_am_am                                           /* Use AM modulation */      
+                        , ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_am_mod_mask, ST25R3916_REG_TX_DRIVER_am_mod_12percent                /* Set Modulation index */
+                        , ST25R3916_REG_AUX_MOD, (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am), 0x00                           /* Use AM via regulator */
+                        , ST25R3916_REG_ANT_TUNE_A, 0xFF, 0x82                                                                                  /* Set Antenna Tuning (Poller): ANTL */
+                        , ST25R3916_REG_ANT_TUNE_B, 0xFF, 0x82                                                                                  /* Set Antenna Tuning (Poller): ANTL */
+                        , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x00                                                                            /* Disable Overshoot Protection  */
+                        , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x00                                                                            /* Disable Overshoot Protection  */
+                        , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x00                                                                            /* Disable Undershoot Protection */
+                        , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x00                                                                            /* Disable Undershoot Protection */
+                        )
+
+                      
+    /****** Default Analog Configuration for Poll NFC-A Rx Common ******/
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_correlator                                   /* Use Correlator Receiver */
+                      )
+                      
+    /****** Default Analog Configuration for Poll NFC-A Tx 106 ******/
+    , MODE_ENTRY_5_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am, ST25R3916_REG_MODE_tr_am_ook                                              /* Use OOK */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x40                                                                              /* Set default Overshoot Protection */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x03                                                                              /* Set default Overshoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x40                                                                              /* Set default Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x03                                                                              /* Set default Undershoot Protection */
+                      )
+                      
+    /****** Default Analog Configuration for Poll NFC-A Rx 106 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x08
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x2D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x51
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-A Tx 212 ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am  , ST25R3916_REG_MODE_tr_am_am                                             /* Use AM modulation */
+                      , ST25R3916_REG_AUX_MOD, (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am), 0x88                             /* Use Resistive AM */
+                      , ST25R3916_REG_RES_AM_MOD, ST25R3916_REG_RES_AM_MOD_md_res_mask, 0x7F                                      /* Set Resistive modulation */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x40                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x03                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x40                                                                              /* Set default Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x03                                                                              /* Set default Undershoot Protection */
+                      )
+                      
+    /****** Default Analog Configuration for Poll NFC-A Rx 212 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x02
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x14
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+                      
+    /****** Default Analog Configuration for Poll NFC-A Tx 424 ******/                      
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am  , ST25R3916_REG_MODE_tr_am_am                                             /* Use AM modulation */
+                      , ST25R3916_REG_AUX_MOD, (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am), 0x88                             /* Use Resistive AM */
+                      , ST25R3916_REG_RES_AM_MOD, ST25R3916_REG_RES_AM_MOD_md_res_mask, 0x7F                                                    /* Set Resistive modulation */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x40                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x03                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x40                                                                              /* Set default Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x03                                                                              /* Set default Undershoot Protection */
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx 424 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x42
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x54
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-A Tx 848 ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_848 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am  , ST25R3916_REG_MODE_tr_am_am                                             /* Use AM modulation */
+                      , ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_am_mod_mask, ST25R3916_REG_TX_DRIVER_am_mod_40percent                  /* Set Modulation index */
+                      , ST25R3916_REG_AUX_MOD, (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am), 0x00                             /* Use AM via regulator */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x00                                                                              /* Disable Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x00                                                                              /* Disable Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x00                                                                              /* Disable Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x00                                                                              /* Disable Undershoot Protection */
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx 848 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_848 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x42
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x44
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+                      
+    /****** Default Analog Configuration for Poll NFC-A Anticolision setting ******/
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL)
+                      , ST25R3916_REG_CORR_CONF1, ST25R3916_REG_CORR_CONF1_corr_s6, 0x00                                                            /* Set collision detection level different from data */
+                      )
+
+#ifdef RFAL_USE_COHE
+    /****** Default Analog Configuration for Poll NFC-B Rx Common ******/
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_coherent                                     /* Use Coherent Receiver */
+                      )
+#else
+    /****** Default Analog Configuration for Poll NFC-B Rx Common ******/
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                        , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_correlator                                 /* Use Correlator Receiver */
+                        )
+#endif /*RFAL_USE_COHE*/
+
+      /****** Default Analog Configuration for Poll NFC-B Rx 106 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x04
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x1B
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 212 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x02
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x14
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 424 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1, 0xFF, 0x42
+                      , ST25R3916_REG_RX_CONF2, 0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3, 0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4, 0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x54
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 848 ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_848 | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x42
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x44
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )    
+#ifdef RFAL_USE_COHE
+
+    /****** Default Analog Configuration for Poll NFC-F Rx Common ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_coherent      /* Use Pulse Receiver */
+                      , ST25R3916_REG_RX_CONF1, 0xFF, 0x13
+                      , ST25R3916_REG_RX_CONF2, 0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3, 0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4, 0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x54
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+#else
+    /****** Default Analog Configuration for Poll NFC-F Rx Common ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_correlator                                   /* Use Correlator Receiver */
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x13
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x3D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x54
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x00
+                      )
+#endif /*RFAL_USE_COHE*/
+
+
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_1OF4 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am, ST25R3916_REG_MODE_tr_am_ook                                              /* Use OOK */
+                      )
+
+
+#ifdef RFAL_USE_COHE
+    /****** Default Analog Configuration for Poll NFC-V Rx Common ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_coherent                                     /* Use Pulse Receiver */
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x13
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x2D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x13
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x01
+                      )
+#else
+    /****** Default Analog Configuration for Poll NFC-V Rx Common ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_AUX,  ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr_correlator                                   /* Use Correlator Receiver */
+                      , ST25R3916_REG_RX_CONF1,   0xFF, 0x13
+                      , ST25R3916_REG_RX_CONF2,   0xFF, 0x2D
+                      , ST25R3916_REG_RX_CONF3,   0xFF, 0x00
+                      , ST25R3916_REG_RX_CONF4,   0xFF, 0x00
+                      , ST25R3916_REG_CORR_CONF1, 0xFF, 0x13
+                      , ST25R3916_REG_CORR_CONF2, 0xFF, 0x01
+                      )
+#endif /*RFAL_USE_COHE*/
+
+                      
+    /****** Default Analog Configuration for Poll AP2P Tx 106 ******/
+    , MODE_ENTRY_5_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am , ST25R3916_REG_MODE_tr_am_ook                                             /* Use OOK modulation */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x40                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x03                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x40                                                                              /* Set default Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x03                                                                              /* Set default Undershoot Protection */
+                      )
+
+    /****** Default Analog Configuration for Poll AP2P Tx 212 ******/    
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am , ST25R3916_REG_MODE_tr_am_am                                              /* Use AM modulation */
+                      )
+                                                                                                                                                
+    /****** Default Analog Configuration for Poll AP2P Tx 424 ******/                                                                           
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_TX)       
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am , ST25R3916_REG_MODE_tr_am_am                                              /* Use AM modulation */
+                      )
+                                                                                                                                                
+                                                                                                                                                
+    /****** Default Analog Configuration for Chip-Specific Listen On ******/
+    , MODE_ENTRY_6_REG( (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON)
+                      , ST25R3916_REG_ANT_TUNE_A, 0xFF, 0x00                                                                                    /* Set Antenna Tuning (Listener): ANTL */
+                      , ST25R3916_REG_ANT_TUNE_B, 0xFF, 0xff                                                                                    /* Set Antenna Tuning (Listener): ANTL */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x00                                                                              /* Disable Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x00                                                                              /* Disable Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x00                                                                              /* Disable Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x00                                                                              /* Disable Undershoot Protection */
+                      )
+                                                                                                                                                
+                                                                                                                                                
+    /****** Default Analog Configuration for Listen AP2P Tx Common ******/
+    , MODE_ENTRY_7_REG( (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_ANT_TUNE_A, 0xFF, 0x82                                                                                    /* Set Antenna Tuning (Poller): ANTL */
+                      , ST25R3916_REG_ANT_TUNE_B, 0xFF, 0x82                                                                                    /* Set Antenna Tuning (Poller): ANTL */
+                      , ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_am_mod_mask, ST25R3916_REG_TX_DRIVER_am_mod_12percent                  /* Set Modulation index */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x00                                                                              /* Disable Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x00                                                                              /* Disable Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x00                                                                              /* Disable Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x00                                                                              /* Disable Undershoot Protection */
+                      )
+                                                                                                                                                
+                                                                                                                                                
+    /****** Default Analog Configuration for Listen AP2P Rx Common ******/
+    , MODE_ENTRY_3_REG( (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX)
+                      , ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_lp_mask, ST25R3916_REG_RX_CONF1_lp_1200khz                               /* Set Rx filter configuration */
+                      , ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_hz_mask, ST25R3916_REG_RX_CONF1_hz_12_200khz                             /* Set Rx filter configuration */
+                      , ST25R3916_REG_RX_CONF2, ST25R3916_REG_RX_CONF2_amd_sel, ST25R3916_REG_RX_CONF2_amd_sel_mixer                            /* AM demodulator: mixer */
+                      )
+                                                                                                                                                
+    /****** Default Analog Configuration for Listen AP2P Tx 106 ******/
+    , MODE_ENTRY_5_REG( (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_TX)
+                      , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am , ST25R3916_REG_MODE_tr_am_ook                                             /* Use OOK modulation */
+                      , ST25R3916_REG_OVERSHOOT_CONF1,  0xFF, 0x40                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_OVERSHOOT_CONF2,  0xFF, 0x03                                                                              /* Set default Overshoot Protection  */
+                      , ST25R3916_REG_UNDERSHOOT_CONF1, 0xFF, 0x40                                                                              /* Set default Undershoot Protection */
+                      , ST25R3916_REG_UNDERSHOOT_CONF2, 0xFF, 0x03                                                                              /* Set default Undershoot Protection */
+                      )
+                                                                                                                                                
+    /****** Default Analog Configuration for Listen AP2P Tx 212 ******/
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_TX)
+                     , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am , ST25R3916_REG_MODE_tr_am_am                                               /* Use AM modulation */
+                     )
+                                                                                                                                                
+    /****** Default Analog Configuration for Listen AP2P Tx 424 ******/
+    , MODE_ENTRY_1_REG( (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_TX)
+                     , ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am , ST25R3916_REG_MODE_tr_am_am                                               /* Use AM modulation */
+                     )
+
+};
+
+const uint16_t rfalAnalogConfigCustomSettingsLength = sizeof(rfalAnalogConfigCustomSettings);

+ 11 - 0
lib/app_scene_template/app_scene.h

@@ -0,0 +1,11 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct {
+    uint32_t id;
+    const void (*on_enter)(void* context);
+    const bool (*on_event)(void* context, uint32_t event);
+    const void (*on_exit)(void* context);
+} AppScene;

+ 3 - 0
lib/lib.mk

@@ -61,6 +61,9 @@ CFLAGS			+= -I$(LIB_DIR)/callback-connector
 # app template library
 CFLAGS			+= -I$(LIB_DIR)/app-template
 
+# add C scene template
+CFLAGS			+= -I$(LIB_DIR)/app_scene_template
+
 # fnv1a hash library
 CFLAGS			+= -I$(LIB_DIR)/fnv1a-hash
 C_SOURCES		+= $(LIB_DIR)/fnv1a-hash/fnv1a-hash.c

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.